SpringMVC请求响应数据详解和常用注解介绍



一、SpringMVC入门


在这里插入图片描述


服务器端程序,一般都基于两种形式,一种C/S架构程序,一种B/S架构程序. 使用Java语言基本上都是开发B/S架构的程序,B/S架构又分成了三层架构


三层架构:

​ 表现层:WEB层,用来和客户端进行数据交互的。表现层一般会采用MVC的设计模型

​ 业务层:处理公司具体的业务逻辑的

​ 持久层:用来操作数据库的


MVC全名是Model View Controller 模型视图控制器,每个部分各司其职。

​ Model:数据模型,JavaBean的类,用来进行数据封装。

​ View:指JSP、HTML用来展示数据给用户

​ Controller:用来接收用户的请求,整个流程的控制器。用来进行数据校验等(Hibernate Validator)


SpringMVC


SpringMVC是一种基于Java的、实现MVC设计模型的、请求驱动类型的(基于HTTP协议)、轻量级Web框架,属于 Spring FrameWork 的后续产品。Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。

SpringMVC已经成为目前最主流的 MVC 框架之一,并且随着Spring3.0的发布,全面超越 Struts2,成为最优秀的 MVC(web层的) 框架。

它通过一套注解,让一个简单的Java类成为处理请求的控制器(Controller),而无须实现任何接口(跟Servlet对比)。同时它还支持RESTful编程风格的请求。


SpringMVC的优点


  1. 清晰的角色划分:

    前端控制器(DispatcherServlet)

    请求到处理器映射(HandlerMapping) :负责找controller类

    处理器适配器(HandlerAdapter) : 负责调用controller类,得到结果,封装结果

    视图解析器(ViewResolver) : 负责解析view

    处理器或页面控制器(Controller)

    验证器( Validator)

    命令对象(Command 请求参数绑定到的对象就叫命令对象)

    表单对象(Form Object 提供给表单展示和提交到的对象就叫表单对象)。

  2. 分工明确,而且扩展点相当灵活,可以很容易扩展,虽然几乎不需要。

  3. 由于命令对象就是一个 POJO, 无需继承框架特定 API,可以使用命令对象直接作为业务对象。

  4. 和 Spring 其他框架无缝集成,是其它 Web 框架所不具备的。

  5. 可适配,通过 HandlerAdapter 可以支持任意的类作为处理器。

  6. 可定制性, HandlerMapping、 ViewResolver 等能够非常简单的定制。

  7. 功能强大的数据验证、格式化、绑定机制。

  8. 利用 Spring 提供的 Mock 对象能够非常简单的进行 Web 层单元测试。

  9. 本地化、主题的解析的支持,使我们更容易进行国际化和主题的切换。

  10. 强大的 JSP 标签库,使 JSP 编写更容易。

  11. 有比如RESTful风格的支持、简单的文件上传、约定大于配置的契约式编程支持、基于注解的零配
    置支持等等。


小结

  1. Spring MVC 是Spring开发的关于Web层的框架

  2. 它的作用:接收请求,调用service,响应结果


代码实现


导入依赖

<dependencies>
    <!--springmvc-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.1.2.RELEASE</version>
    </dependency> 
    <!--jsp-api-->
    <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>javax.servlet.jsp-api</artifactId>
        <version>2.3.1</version>
        <scope>provided</scope>
    </dependency>
    <!--servlet-api-->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

编写页面


在webapp里创建index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h2>这是首页~</h2>
<a href="/sayHi">点我发起请求</a>
</body>
</html>


在webapp里创建success.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h2>这是成功的页面~</h2>

</body>
</html>


编写Controller

com.execise.controller包中创建类Controller01

类上增加@Controller注解,声明成为一个bean

创建sayHi方法,并在方法上增加@RequestMapping注解,声明方法的访问路径


package com.execise.controller;

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

/*
    入门案例
        1. 定义类,类上打注解 @Controller
        2. 定义方法, 方法上打注解 @RequestMapping

        3. 这个controller能处理 /sayHi的请求,但是要想处理请求,首先必须能抓住请求。
        4. 所以要在web.xml配置servlet :: DispatcherServlet
 */
@Controller
public class Controller01 {
    @RequestMapping("/sayHi")
    public String sayHi(){
        System.out.println("调用了Controller01的sayHi方法~!~");
        return "/success.jsp";
    }
}

编写配置文件


resources中创建springmvc的配置文件springmvc.xml , 这个名字可以随意,也可以写成前几天的 applicationContext.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:mvc="http://www.springframework.org/schema/mvc"
       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
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">

  
    <!--1. 扫描包-->
    <context:component-scan base-package="com.execise"/>
</beans>

修改Web.xml


webapp/WEB-INF/web.xml中配置前端控制器DispatcherServlet


<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5">

	<!--登记|注册 DispatcherServlet,让它来抓请求-->
	<servlet>
		<servlet-name>dispatcher</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>


		<!--1. 告诉DispatcherServlet,springmvc配置文件在哪里。它会解析这个文件,进而去扫描包-->
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:springmvc.xml</param-value>
		</init-param>

		<!--2. 让DispatcherServlet初始的时机提前到服务器启动时-->
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>dispacher</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>
</web-app>

运行测试

启动项目,点击首页的超链接访问Controller

sayHi方法被访问到,并且页面跳转到了success.jsp


小结

  1. 创建web工程,导入依赖:spring-webmvc, servlet-api, jsp-api

  2. 编写Controller

  3. 提供springmvc.xml:开启组件扫描

  4. 修改web.xml:配置前端控制器DispatcherServlet


配置详解


求响应流程


在这里插入图片描述


三大组件


HandlerMapping处理器映射器

  • 作用:根据客户端请求的资源路径,查找匹配的Controller及拦截器(类似过滤器)链

HandlerAdapter处理器适配器

  • 作用:用于适配调用不同的Controller 执行Controller,得到模型和视图

ViewResolver视图解析器

  • 作用:用于解析视图,根据视图路径找到真实视图(页面)

详细执行流程

  1. 客户端发请求到DispatcherServlet

  2. DispatcherServlet

    1. 通过HandlerMapping处理器映射器,根据请求路径,查找匹配的Controller及拦截器

    2. 得到要执行的Controller和拦截器(执行链)

  3. DispatcherServlet

    1. 通过HandlerAdapter处理器适配器,调用控制器Controller

    2. 得到ModelAndView对象(其中View指视图路径,Model要响应的数据对象)

  4. DispatcherServlet

    1. 通过ViewResolver解析视图,得到真实视图(视图路径对应的页面)

    2. 渲染视图(把Model里的数据填充到View里 , 替换页面上的 EL表达式为真实的数据)

  5. 把最终渲染的结果,响应到客户端


springmvc.xml的配置


跟之前的 applicationContext.xml 是一样的。只是换了个名字而已。springmvc和spring可以共用同一个配置文件!


基本配置示例


<!--开启组件扫描-->
<context:component-scan base-package="com.execise.controller"/>

<!--开启mvc的注解驱动-->
<mvc:annotation-driven/>

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

<!-- 静态资源的配置:让SpringMVC不处理静态资源 -->
<mvc:default-servlet-Handler/>

mvc的注解驱动

<!--
    2. 注解驱动
        2.1 声明时一定要选择mvc的标签,如果选择到cache的标签,则会出现这个错误:
            No bean named 'cacheManager' available
        2.2 这个标签会帮助我们在项目里面导入三大组件
        2.3 后面用到的一些注解,必须要有这个标签的支撑,否则注解用不了! eg:@ResponseBody
-->
<mvc:annotation-driven/>

配置说明

在SpringMVC中,处理器映射器,处理器适配器,视图解析器 被称为三大组件

在springmvc.xml中配置<mvc:annotation-driven/>标签,可以加载SpringMVC的组件

  • 如果没有此项配置,SpringMVC也会自动加载组件,所以现在的使用中不配置这一项也可以

  • 但是在之后,这个标签还有其它作用,所以要配置上


视图解析器设置


视图路径的配置方式

SpringMVC把页面称为视图,例如JSP|HTML页面就是视图。Controller的方法中,返回的字符串就是跳转的视图(页面)路径


视图的路径有两种写法:

  • 物理视图:/success.jsp | success.jsp ,即:视图的真实路径(完整路径)

    • 直观,但是写起来麻烦

    • 例如: 如果有一个页面page.jsp 位于 /webapp/a/b/c/page.jsp , 那么物理视图返回: “/a/b/c/page.jsp”;

  • 逻辑视图:success,需要配合视图解析器,才能得到真实路径

    • 不直观,但是写起来简单
    • 例如: 如果有一个页面page.jsp 位于 /webapp/a/b/c/page.jsp , 那么逻辑视图返回: “page”

物理视图的配置方式

  • Controller的方法中,直接返回物理视图路径。

  • 不需要配置视图解析器

@Controller
public class Controller01 { 

    //物理视图跳转: 要写完整的路径地址
    @RequestMapping("/sayHi02")
    public String sayHi02(){
        System.out.println("调用了Controller01的sayHi02方法~!~");
        return "/a/b/c/success.jsp";
    }
}

逻辑视图的配置方式


springmvc.xml中增加以下内容:

  <!--
        3. 视图解析器
            3.1 视图解析器是搭配逻辑视图使用的,它要和方法的返回值拼接起来得到页面的真实路径
                前缀  +  方法的返回值  +  后缀    ====   /success.jsp
            3.2 视图解析器一旦配置,就会对全局产生影响,所有的controller的方法返回值都要受到它的影响
                除了某些方法之外【后面讲!】
    -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

Controller中修改代码,简化方法返回值

@Controller
public class Controller01 {
    //逻辑视图跳转:只要写页面的名字即可,需要搭配视图解析器来使用
    @RequestMapping("/sayHi03")
    public String sayHi03(){
        System.out.println("调用了Controller01的sayHi03方法~!~");
        return "success";
    }
}

由视图解析器,帮我们把prefix + "success" + suffix,拼接成物理视图/success.jsp


处理静态资源


请求静态资源的说明

  • 使用SpringMVC时,客户端访问静态资源时,会访问不到 , 会得到404

  • Tomcat本身具备处理静态资源的能力,但是我们配置的DispatcherServlet把Tomcat的默认处理器覆盖掉了;而DispatcherServlet没有处理静态资源的能力,所以:访问不到静态资源

    Tomcat里面有一个Servlet,可以处理静态资源: DefaultServlet,它的映射路径是 /

    我们使用SpringMVC的时候,在web.xml中,配置DispatcherServlet,配置的地址路径也是 /


在这里插入图片描述


两种配置方式解决问题


指定静态资源的位置

针对客户端对静态资源的请求,指定资源所在的位置。让SpringMVC直接去指定目录下加载


示例:

<!-- 4. 静态资源处理:
   4.1 当我们的DispatcherServlet配置的映射路径是 / 的时候,静态资源就看不到了,报:404的错误
       a. 在tomcat里面有一个默认的DefaultServlet, 它的映射路径是 / 它的作用是专门用来处理静态资源
       b. 由于DispatcherServlet,映射路径也是 /  所以咱们的DispatcherServlet把DefaultServlet给覆盖了。而DispatcherServlet 又不能处理静态资源,所以出现404
   4.2 解决静态资源的问题,有两种办法:
	  1.不要将DispatcherServlet的映射路径配置为/  配置为*.do就可以了  
			【不想替换  因为每次发起请求都要带一个.do的尾巴】
      2.DispatcherServlet映射路径依然配置为/,如何解决
       		a. 配置映射地址和资源路径。
       		b. 把静态资源的请求,交还给tomcat的DefaultServlet处理
-->
<!--
   1. 配置地址和路径的映射
       a. 不推荐使用这种办法,因为以后如果还有新的静态资源的类型,那么就需要在这里再增加一行配置
       b. 解释:
          mvc:resources : 用来做请求地址和资源路径映射
              mapping : 请求地址
                 * : 表示当前的位置,只能匹配一级目录
                 		/html/*   ========不能匹配==========localhost:82/html/my.html
                 		/html/* ========不能匹配==========localhost:82/html/a/b/c/my.html
                  ** : 表示匹配任意目录
                       /html/**   ========能匹配==========localhost:82/html/my.html
                       /html/** ========能匹配==========localhost:82/html/a/b/c/my.html
          location : 静态资源所在位置 , 后面要有 / 结尾
-->
<mvc:resources mapping="/html/**" location="/html/"/>
<mvc:resources mapping="/js/**" location="/js/"/>
<mvc:resources mapping="/css/**" location="/css/"/>

由Tomcat处理静态资源(推荐)

如果客户端请求了静态资源,DispatcherServlet处理不了,就交给Tomcat的原生Servlet来处理


示例:

    <!--2. 把静态资源的处理,交给tomcat的DefaultServlet来做-->
    <mvc:default-servlet-handler/>

小结


配置视图解析器

  • Controller里的方法返回值要写逻辑视图

  • 再配置视图解析器

 <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
     <property name="prefix" value="/"/>
     <property name="suffix" value=".jsp"/>
</bean>

如果有静态资源要访问,把静态资源仍然交给Tomcat处理

<mvc:default-servlet-handler/>

开启mvc的注解驱动:会注册一些组件,提供一些功能

<mvc:annotation-driven/>

开启组件扫描

<context:component-scan base-pcakge="com.execise.controller"/>

web.xml的配置

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5">

	<!--登记|注册 DispatcherServlet,让它来抓请求-->
	<servlet>
		<servlet-name>dispatcher</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>


		<!--1. 告诉DispatcherServlet,springmvc配置文件在哪里。它会解析这个文件,进而去扫描包-->
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:springmvc.xml</param-value>
		</init-param>

		<!--2. 让DispatcherServlet初始的时机提前到项目发布-->
		<load-on-startup>1</load-on-startup>
	</servlet>

<!--
  DispatcherServlet的映射路径应该写什么呢?
   1. 映射路径能不能写成 *.do *.execise这样的写法呢?【也就是说,只抓尾巴】
    	a. 可以!并且它不会覆盖掉Tomcat里面的DefaultServlet,也不需要写静态资源处理配置
    	b. 有一点不好的地方就是:访问所有的controller方法,都必须带上尾巴 .do

   2. 映射路径能不能写成 /*  这样的写法呢?
    	不可以! jsp页面看不到了! 看到的只是jsp页面的源码
    	a. 在tomcat里面还有一个Servlet叫做:JspServlet, 它专门用来处理jsp页面的请求
    	b. 这个JspServlet的映射路径是 *.jsp
    	c. 现在DispatcherServlet,映射的路径是 /* ,那么就会涉及到一个优先级的问题!
    	d. 映射路径的优先级是这样: /aa >  /*  > *.jsp | *.do >  /

  综上所述:
     1. 当DispatcherServlet配置的映射路径是 /*的时候,浏览器访问jsp页面这个请求,也会被它抓住
     	但是DispatcherServlet又不能解析,执行jsp页面,所以直接把这个页面的源码丢给了浏览器!

     2. /表示缺省配置,优先级是最低!所谓的缺省配置就是当没有任何servlet处理这个请求的时候,就由它来处理!
 -->
	<servlet-mapping>
		<servlet-name>dispatcher</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>
</web-app>

配置说明


load-on-startup:配置Servlet的创建时机,值是整数

  • 如果是正整数,表示服务器一启动就要创建Servlet对象。数值越小,创建的越早

  • 如果是0或者负数,表示默认的:第一次访问时,创建Servlet对象

DispatcherServlet是SpringMVC一切功能的基础和核心,要求:服务器启动时就创建,并且要最早创建,所以设置值为1

init-param:配置Servlet的初始化参数

contextConfigLocation:配置springmvc.xml的路径,让DispatcherServlet被创建时,加载配置文件,初始化Spring容器

url-pattern:配置Servlet的路径,通常配置为/


拓展:


DispatcherServlet配置成//*的区别:

  • 对JSP的处理不同。当客户端请求了xxx.jsp

如果DispatcherServlet配置的是/*,不能正常访问JSP

  • /*是目录匹配,优先级高于扩展名匹配(Tomcat里有JspServlet,路径是*.jsp

  • 必定是由DispatcherServlet来处理JSP,但是DispatcherServlet不具备查找和处理jsp的能力,会报错

如果DispatcherServlet配置的是/,可以正常访问JSP

  • /是缺省匹配,优先级低于扩展名匹配(Tomcat里有JspServlet,路径是*.jsp

  • 必定是由Tomcat来处理JSP,Tomcat本身具备查找和处理JSP的能力,可以正常访问JSP

完全路径匹配 > 目录匹配 > 扩展名匹配 > 缺省匹配

/aa > /* > *.do > /


controller的配置

package com.execise.controller;

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

import javax.servlet.Servlet;

/*
    @Controller :
        1. 表示这个类是一个控制器,可以处理请求。
        2. spring会把这个类管理起来, 创建这个类的对象。
    RequestMapping :
        1. 表示方法的映射地址,当什么请求来的时候,会执行这个方法。
        2. 属性:
            value|path : 用来设置映射路径
            method : 用来设置请求方式,表示什么样的请求方式,才能执行这个方法。【默认是都支持!】
                RequestMethod.GET : 允许get请求到这里来
                RequestMethod.POST : 允许post请求到这里来
                    如果设置了post,页面还是用get请求过来,那么会报错:
                        Request method 'GET' not supported
            params : 用来要求请求一定要携带指定名称的参数
                params="username"`:必须提交了 名称为username的表单参数,才可以访问
                params="username=tom"`:必须提交了 名称为username、值为tom的表单参数,才可以访问
                params="username!=tom"`:提交了表单参数  名称为username、值不是tom, 才可以访问
        3. 这个注解可以打在方法身上,也可以打在类身上!
            3.1 在类身上写@RequestMapping,访问方法时,需要加上类上面的映射路径
            3.2 这样子做的好处主要是为了和其他的模块进行区分。有前缀的划分。
 */
@Controller
@RequestMapping("/user")
public class Controller01  {


    @RequestMapping(value = "/sayHi04", method = RequestMethod.GET , params = "username")
    public String sayHi04(){
        System.out.println("调用了Controller01的sayHi04方法~!~");
        return "success";
    }
}

配置说明


@RequestMapping注解 , 通常用在Controller里,用于设置访问路径


注解语法

@RequestMapping(
	value="访问路径",
    method=请求方式,
    params="请求参数"
)

常用属性:

  • value/path:访问路径,即:什么路径能够访问到这个方法

  • method:请求方式,即:什么请求方式能够访问这个方法。从枚举RequestMethod中取值

    • RequestMethod.POST:必须是POST方式,才可以访问到

    • RequestMethod.GET:必须是GET方式,才可以访问到

  • params:请求参数,即:请求携带了什么样的参数能够访问这个方法(了解)

    • params="username":必须提交了 名称为username的表单参数,才可以访问

    • params="username=tom":必须提交了 名称为username、值为tom的表单参数,才可以访问

    • params="username!=tom":提交了表单参数 名称为username、值不是tom, 才可以访问

  • 如果注解用在Controller类上

    • 表示设置访问路径的一级目录,要和方法上的路径组装成访问路径。用于模块化管理,例如:

      • 类上有注解@RequestMapping("/user")

      • 类里方法上有注解@RequestMapping("/save")

      • 那么方法的访问路径是:/user/save


二、获取请求数据


请求参数的绑定


绑定机制

表单提交的数据都是key=value格式的(username=zs&password=123), SpringMVC的参数绑定过程是把表单提交的请求参数,作为控制器中方法的参数进行绑定的(要求:提交表单的name和方法的参数的名称是相同的)


<form action="">
    用户名:<input type="text" name="username"/>
    密码: <input type= "password" name="password"/>
    <input type="submit"/>
</form>
public String register(String username , String password){


}

//======================================================

class User{
    
    private String username;
    private String password;
    
}

public String register02(User user){


}

支持的数据类型

  • 基本数据类型和字符串类型

  • 实体类型(JavaBean)

  • 集合数据类型(List、map集合等)


使用要求

  • 如果是基本类型或者 String 类型: 要求我们的参数名称必须和controller中方法的形参名称保持一致。 (严格区分大小写) .

  • 如果是 对象 类型,或者它的关联对象: 要求表单中参数名称和对象类的属性名称保持一致

  • 如果是集合类型,有两种方式:

    • 第一种:要求集合类型的请求参数必须在对象类 中。在表单中请求参数名称要和 对象类中集合属性名称相同。给 List 集合中的元素赋值, 使用下标【】。给 Map 集合中的元素赋值, 使用键值对。

    • 第二种:接收的请求参数是 json 格式数据。需要借助一个注解实现 @RequestBody


小结


  1. 绑定机制

SpringMVC的参数绑定过程是把表单提交的请求参数,作为controller里面方法的参数进行绑定的。


  1. 支持的数据类型 :

​ 基本数据类型和字符串类型

​ 实体类型(JavaBean)

​ 集合数据类型(List、map集合等)


  1. 使用要求: 名字需要一样

获取请求参数


基本类型和String


说明

  • 客户端提交的表单参数名称, 和Controller里方法参数名称相同

  • SpringMVC会自动绑定同名参数,并自动转换类型

页面


index.jsp

<h2>提交简单的参数:</h2>
<form action="/requestSimpleParam" method="post">
    用户名:<input type="text" name="username"/><br/>
    密  码:<input type="text" name="password"/><br/>
    年  龄:<input type="text" name="age"/><br/>
    <input type="submit"/>
</form>


success.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h2>这是成功的页面~!~</h2>
</body>
</html>

controller

package com.execise.controller;

import com.execise.bean.*;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Arrays;

@Controller
public class Controller01 {

    /*
        获取简单的参数:
            要求:
                1. 方法的参数名字必须和页面的form表单中的name属性的值 一样!
                    用户名:<input type="text" name="username"/>
     */
    @RequestMapping("/requestSimpleParam")
    public String requestSimpleParam(String username, String password , int age){
        System.out.println("username = " + username);
        System.out.println("password = " + password);
        System.out.println("age = " + age);

        return "success";
    }
}

对象类型


SpringMVC会帮我们自动把表单参数,封装成对象,但是要求:

客户端提交的表单参数名称,必须和JavaBean的属性名一样!


Pojo(User)

package com.execise.bean;

import lombok.Data;

@Data
public class User {
    private String username;
    private String password;
    private int age;
}

前端页面

<h2>提交对象的参数:</h2>
<form action="/requestObjectParam">
    用户名:<input type="text" name="username"/><br/>
    密  码:<input type="text" name="password"/><br/>
    年  龄:<input type="text" name="age"/><br/>
    <input type="submit"/>
</form>

controller

package com.execise.controller;

import com.execise.bean.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Arrays;

@Controller
public class Controller01 { 
    /*
        获取对象参数:
            要求:
                1. 页面提交上来的form表单的name属性值必须和JavaBean的属性名字一样!
                    用户名:<input type="text" name="username"/>

                    public class User {
                        private String username;
                    }
     */
    @RequestMapping("/requestObjectParam")
    public String requestObjectParam(User user){
        System.out.println("user = " + user);
        return "success";
    }

}

嵌套POJO类型参数


POJO对象中包含POJO对象

public class User {
    private String name;
    private int age;
    private Address address;
    //同学们自己添加getter/setter/toString()方法
}
public class Address {
    private String province;
    private String city;
}

嵌套POJO参数:请求参数名与形参对象属性名相同,按照对象层次结构关系即可接收嵌套POJO属性参数


在这里插入图片描述


//嵌套POJO参数:嵌套属性按照层次结构设定名称即可完成参数传递
@RequestMapping("/pojoContainPojoParam")
@ResponseBody
public String pojoContainPojoParam(User user){
    System.out.println("pojo嵌套pojo参数传递 user ==> "+user);
    return "{'module':'pojo contain pojo param'}";
}

注意事项:请求参数key的名称要和POJO中属性的名称一致,否则无法封装。


数组


注:只能2接前端多个参数(一个名字对应多个值),不能用List集合。确实需要List集合接收时,使用包装user.list


页面

<h2>提交数组的参数:</h2>
<form action="/requestArrayParam">
    请选择您的爱好:<br/>
        <input type="checkbox" name="hobby" value="smoke"/>抽烟
        <input type="checkbox" name="hobby" value="drink"/>喝酒
        <input type="checkbox" name="hobby" value="firehead"/>烫头<br/>
    <input type="submit"/>
</form>



Controller01

package com.execise.controller;

import com.execise.bean.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Arrays;

@Controller
public class Controller01 {
      /*
        获取数组参数:
            要求:
                1. 页面上的表单项,name属性值必须一样!
                2. 方法参数的名字必须和name属性的值一样!
     */
    @RequestMapping("/requestArrayParam")
    public String requestArrayParam(String [] hobby){
        System.out.println("hobby=" + Arrays.toString(hobby));
        return "success";
    }
}

集合类型参数


集合保存普通参数:请求参数名与形参集合对象名相同且请求参数为多个,@RequestParam绑定参数关系


在这里插入图片描述


//集合参数:同名请求参数可以使用@RequestParam注解映射到对应名称的集合对象中作为数据
@RequestMapping("/listParam")
@ResponseBody
public String listParam(@RequestParam List<String> likes){
    System.out.println("集合参数传递 likes ==> "+ likes);
    return "{'module':'list param'}";
}

日期类型参数传递


代码演示

  • 日期类型数据基于系统不同格式也不尽相同

    2088-08-18

    2088/08/18

    08/18/2088

  • 接收形参时,根据不同的日期格式设置不同的接收方式


在这里插入图片描述


//日期参数 http://localhost:80/dataParam?date=2088/08/08&date1=2088-08-18&date2=2088/08/28 8:08:08
//使用@DateTimeFormat注解设置日期类型数据格式,默认格式yyyy/MM/dd
@RequestMapping("/dataParam")
@ResponseBody
public String dataParam(Date date,
                  @DateTimeFormat(pattern="yyyy-MM-dd") Date date1,
                  @DateTimeFormat(pattern="yyyy/MM/dd HH:mm:ss") Date date2){
    System.out.println("参数传递 date ==> "+date);
    System.out.println("参数传递 date1(yyyy-MM-dd) ==> "+date1);
    System.out.println("参数传递 date2(yyyy/MM/dd HH:mm:ss) ==> "+date2);
    return "{'module':'data param'}";
}

@DateTimeFormat注解介绍

  • 名称:@DateTimeFormat

  • 类型:形参注解

  • 位置:SpringMVC控制器方法形参前面

  • 作用:设定日期时间型数据格式

  • 属性:pattern:指定日期时间格式字符串


json数据参数传递


问题:@EnableWebMvc注解和@ResponseBody注解有什么用?


json数据参数介绍

  • json普通数组([“”,“”,“”,…])

  • json对象({key:value,key:value,…})

  • json对象数组([{key:value,…},{key:value,…}])


传递json普通数组


代码演示

  1. 添加json数据转换相关坐标
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.6</version>
</dependency>
  1. 设置发送json数据(请求body中添加json数据)

在这里插入图片描述


  1. 在Controller中编写方法接收json参数
//集合参数:json格式
//1.开启json数据格式的自动转换,在springmvc.xml配置文件中配置开启注解驱动
//2.使用@RequestBody注解将外部传递的json数组数据映射到形参的集合对象中作为数据
@RequestMapping("/listParamForJson")
@ResponseBody
public String listParamForJson(@RequestBody List<String> likes){
    System.out.println("list common(json)参数传递 list ==> "+likes);
    return "{'module':'list common for json param'}";
}

@RequestBody注解介绍

  • 名称:@RequestBody

  • 类型:形参注解

  • 位置:SpringMVC控制器方法形参定义前面

  • 作用:将请求中请求体所包含的数据传递给请求参数,此注解一个处理器方法只能使用一次


范例:

@RequestMapping("/listParamForJson")
@ResponseBody
public String listParamForJson(@RequestBody List<String> likes){
    System.out.println("list common(json)参数传递 list ==> "+likes);
    return "{'module':'list common for json param'}";
} 

传递json对象

POJO参数:json数据与形参对象属性名相同,定义POJO类型形参即可接收参数


在这里插入图片描述


//POJO参数:json格式
//1.开启json数据格式的自动转换,在springmvc.xml配置文件中配置开启注解驱动
//2.使用@RequestBody注解将外部传递的json数据映射到形参的实体类对象中,要求属性名称一一对应
@RequestMapping("/pojoParamForJson")
@ResponseBody
public String pojoParamForJson(@RequestBody User user){
    System.out.println("pojo(json)参数传递 user ==> "+user);
    return "{'module':'pojo for json param'}";
}

传递json对象数组

POJO集合参数:json数组数据与集合泛型属性名相同,定义List类型形参即可接收参数


在这里插入图片描述


//集合参数:json格式
//1.开启json数据格式的自动转换,在springmvc.xml配置文件中配置开启注解驱动
//2.使用@RequestBody注解将外部传递的json数组数据映射到形参的保存实体类对象的集合对象中,要求属性名称一一对应
@RequestMapping("/listPojoParamForJson")
@ResponseBody
public String listPojoParamForJson(@RequestBody List<User> list){
    System.out.println("list pojo(json)参数传递 list ==> "+list);
    return "{'module':'list pojo for json param'}";
}

@RequestBody与@RequestParam区别


@RequestParam用于接收url地址传参,表单传参【application/x-www-form-urlencoded】

@RequestBody用于接收json数据【application/json】


应用

后期开发中,发送json格式数据为主,@RequestBody应用较广

如果发送非json格式数据,选用@RequestParam接收请求参数


小结


请求参数类型是简单(基本,String)类型

  • 方法的形参和请求参数的name一致就可以

请求参数类型是pojo对象类型

  • 形参就写pojo对象

  • pojo的属性必须和请求参数的name一致就可以

提交数组,只能用数组接收,多个参数的name属性名一致,参数要与controller中的参数名一致。

请求参数时json数据类型

  • 添加jackson-databind依赖

  • springmvc.xml中开启注解驱动

  • 在参数前面加上@RequestBody注解 并且注意对象的属性要和json数据的key一致


细节处理和特殊情况


请求参数乱码

如果请求参数或者响应中有中文就会乱码。在web阶段,我们通过一个自定义的过滤器实现了统一乱码解决

req.setCharacterEncoding(“utf-8”)

resp.setContentType(“text/html;charset=utf-8”);

现在SpringMVC本身 ,也给我们提供了一个过滤器CharacterEncodingFilter,用于解决乱码问题 。 只有在post请求才会有中文乱码,如果tomcat > 8.5的版本,那么tomcat已经帮助修复了get请求的中文乱码。

如果使用了tomcat7的插件来跑项目, get请求还是会有乱码的!需要配置一下下!


在web.xml里面配置编码过滤器

<!--配置字符编码过滤器-->
<filter>
	<filter-name>char</filter-name>
	<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>

	<!--指定使用UTF-8的编码 , encoding是固定写法-->
	<init-param>
		<param-name>encoding</param-name>
		<param-value>utf-8</param-value>
	</init-param>
</filter>

<filter-mapping>
	<filter-name>char</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>

如果使用了tomcat7的插件,get请求会出现中文乱码,那么可以这么解决

  <build> 
    <plugins> 
      <plugin> 
        <groupId>org.apache.tomcat.maven</groupId>  
        <artifactId>tomcat7-maven-plugin</artifactId>  
        <version>2.2</version>  
        <configuration> 
          <!-- 指定端口 -->  
          <port>82</port>  
          <!-- 请求路径 -->  
          <path>/</path>

          <!--配置编码-->
          <uriEncoding>utf-8</uriEncoding>
        </configuration> 
      </plugin> 
    </plugins> 
  </build> 

自定义类型转换器


默认情况下,SpringMVC已经实现一些数据类型自动转换。 内置转换器全都在: org.springframework.core.convert.support 包下 ,如遇特殊类型转换要求,需要我们自己编写自定义类型转换器。


在这里插入图片描述


场景


页面

<h2>提交包含日期的参数:</h2>
<form action="/requestDateParam">
    用户名:<input type="text" name="username"/><br/>
    密  码:<input type="text" name="password"/><br/>
    出生日期:<input type="text" name="birthday"/><br/>
    <input type="submit"/>
</form>

User04

package com.execise.bean;

import lombok.Data;

import java.util.Date;

@Data
public class User04 {
    private String username;
    private String password;
    private Date birthday;
}

Controller01.java

package com.execise.controller;

import com.execise.bean.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Arrays;


@Controller
public class Controller01 {

     /*
        获取日期格式的数据
     */
    @RequestMapping("/requestDateParam")
    public String requestDateParam(User04 user04){
        System.out.println("user04 = " + user04);
        return "success";
    }

}

报错了:


在这里插入图片描述


自定义类型转换器

步骤:

  1. 创建一个类实现Converter 接口

  2. 配置类型转换器

实现:

  • 定义一个类,实现 Converter 接口

    该接口有两个泛型,S:表示接受的类型, T:表示目标类型(需要转的类型)

package com.execise.converter;

import org.springframework.core.convert.converter.Converter;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;


/*
    自定义日期格式转换器
        1. 定义类,实现接口Converter
            里面有两个泛型: S : 表示的是源数据的类型 , T: 表示的是目标数据的类型
        2. 实现方法convert
 */
public class DateConverter implements Converter<String , Date> {

    /**
     *
     * @param source 从页面接收到的数据
     * @return 转化出来的日期对象。
     */
    public Date convert(String source) {
        try {
            System.out.println("来到我们的日期转化器了:" + source);
            //1. 定义SimpleDateFormat对象
            SimpleDateFormat sf =null ;
            if(source .contains("-")){
                sf = new SimpleDateFormat("yyyy-MM-dd");
            }else if(source.contains("/")){
                sf = new SimpleDateFormat("yyyy/MM/dd");
            }
            //2. 转化
            return sf.parse(source);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }
}

在springmvc.xml里面配置转换器

spring 配置类型转换器的机制是,将自定义的转换器注册到类型转换服务中去


<!--2. 注解驱动-->
     <mvc:annotation-driven conversion-service="cs"/>

     <!--
         5. 配置日期格式转换器
             5.1 配置转换工厂对象
             5.2 给它里面的集合    converters 注入我们自己的类型转换器!
     -->
     <bean id="cs" class="org.springframework.context.support.ConversionServiceFactoryBean">
         <property name="converters">
             <bean class="com.execise.converter.DateConverter"/>
         </property>
     </bean>

三、响应数据和视图


返回页面视图


返回页面文件名


controller方法返回的字符串会被解析成页面视图(即:页面的地址路径)


返回逻辑视图名称

  • 方法返回的字符串,和视图解析器里的前缀、后缀拼接得到真实路径,再进行跳转

  • 不管是物理视图(完整的写法)还是逻辑视图(简写),默认采用的都是请求转发跳转


在这里插入图片描述


返回带前缀的物理视图

  • 请求转发:forward:/success.jsp

  • 重定向:redirect:/success.jsp

  • 注意:如果带有forward或者redirect,那么路径必须是完整的真实路径 , 不受视图解析器影响*


使用示例

package com.execise.controller;

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


/*
    响应视图: 跳转页面
        1. springmvc跳转页面的时候,默认是采用请求转发去跳转
        2. 跳转的写法:
            2.1 逻辑视图
                只要写上页面的名字即可

            2.2 物理视图
                 要写完整的页面的路径地址才行。

                 a. 不带前缀的写法
                    会受到视图解析器的影响
                 b. 带前缀的写法
                    不会受到视图解析器的影响
                        forward:物理视图路径    表示使用请求转发跳转
                        redirect:物理视图路径   表示使用重定向跳转
 */
@Controller
public class Controller02 {

    //逻辑视图跳转: 只要写上视图的名字即可
    @RequestMapping("/page01")
    public String page01(){
        System.out.println("page01...");
        return "success";
    }

    //物理视图跳转: 写上视图的完整路径
    @RequestMapping("/page02")
    public String page02(){
        System.out.println("page02...");
        return "/success.jsp";
    }

    //物理视图跳转:加上前缀  forward:
    // forward: 表示 使用请求转发跳转,并且它不会受到视图解析器的影响
    @RequestMapping("/page03")
    public String page03(){
        System.out.println("page03...");
        return "forward:/success.jsp";
    }

    //物理视图跳转,加上前缀 redirect:
    // redirect: 表示使用重定向跳转,并且不会受到视图解析器的影响
    @RequestMapping("/page04")
    public String page04(){
        System.out.println("page04...");
        return "redirect:/success.jsp";
    }
}


请求转发并传递数据


ModelAndView是SpringMVC提供的组件之一,其中

  • Model,模型,用于封装数据(Springmvc会把数据放到了request域中)

  • View,视图,就是页面,用于展示数据

如果我们设置了视图名称,并且封装了数据模型,SpringMVC会:

  • 把Model的数据放到request域对象中,然后请求转发到指定的视图(页面)

  • 我们可以视图页面中获取数据显示出来


使用示例

package com.execise.controller;

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;
import javax.servlet.http.HttpSession;


/*
   跳转页面,并且携带数据到页面上显示!
        1. 使用ModelAndView来封装数据和视图
 */
@Controller
public class Controller03 {

    //1. 自己new ModelAndView对象
    @RequestMapping("/page05")
    public ModelAndView page05(){
        //1. 创建ModelAndView对象
        ModelAndView mv = new ModelAndView();
        //2. 装数据: 会把这份数据保存到request作用域里面
        mv.addObject("username", "page05");
        //3. 装视图 : 会受视图解析器的影响。
        mv.setViewName("success");
        //4. 返回mv;
        return mv ;
    }

    //在参数里面定义ModelAndView,要求springmvc传递进来对象
    @RequestMapping("/page06")
    public ModelAndView page06(ModelAndView mv){
        //2. 装数据: 会把这份数据保存到request作用域里面
        mv.addObject("username", "page06");
        //3. 装视图 : 会受视图解析器的影响。
        mv.setViewName("success");
        //4. 返回mv;
        return mv ;
    }

    //参数传递进来Model对象,封装数据,使用返回值返回视图。
    @RequestMapping("/page07")
    public String page07(Model model){
        //装数据
        model.addAttribute("username","page07");

        //4. 返回mv;
        return "success" ;
    }

    //========================可以使用以前的request对象或者session对象来存值===============
    @RequestMapping("/page08")
    public String page08(HttpServletRequest req){
        //装数据
        req.setAttribute("username", "page08");

        //4. 返回mv;
        return "success" ;
    }

    @RequestMapping("/page09")
    public String page09(HttpSession session){
        //装数据
        session.setAttribute("username", "page09");

        //4. 返回mv;
        return "success" ;
    }

    //是用重定向的方式跳转页面
    @RequestMapping("/page10")
    public String page10(HttpSession session){
        //装数据
        session.setAttribute("username", "page10");

        //4. 返回mv;
        //return "success" ; //请求转发方式跳转
        return "redirect:/success.jsp" ; //重定向方式跳转!
    }

}

在index.jsp视图页面中,取出数据显示出来

<h2>这是成功的页面 ${username}</h2>

小结


返回页面文件名

  • 返回逻辑视图

    • 方法返回的字符串,和视图解析器里的前缀、后缀拼接得到真实路径,再进行跳转

    • 是请求转发跳转

  • 返回带前缀的物理视图 (不受视图解析器的影响)

    • 请求转发:forward:/success.jsp

    • 重定向:redirect:/success.jsp

方法返回ModelAndView

public ModelAndView jump(){
    ModelAndView mav = new ModelAndView();
    mav.setViewName("视图名称");
    mav.addObject("数据名称", "值");
    return mav;
}

public ModelAndView jump(ModelAndView mav){
    mav.setViewName("视图名称");
    mav.addObject("数据名称", "值");
    return mav;
}
  • 方法返回String:视图名称
public String jump(Model model){
    model.addAttribute("数据名称", "值");
    return "视图名称";
}

返回数据


直接响应字符串


两种方式

  • 使用Servlet原生的response对象,返回响应数据 response.getWrite().write(“xxxx”);

  • 方法上使用@ResponseBody注解,springmvc就会把方法的返回值当成字符串来看待,不会再识别成页面的地址路径


使用示例

package com.execise.controller;

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

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/*
    返回数据给页面: 字符串 &  JSON
 */
@Controller
public class Controller04 {

    /*
        返回字符串:  使用response对象, 把字符串写出去!
     */
    @RequestMapping("/returnStr01")
    public void returnStr01(HttpServletResponse resp) throws IOException {
        resp.getWriter().write("returnStr01...");
    }

    /*
        返回字符串:
            1. 直接在方法的返回值返回字符串
            2. 要加上注解 @ResponseBody, springMVC会把返回值看成是字符串,否则会被看成是页面的路径
     */
    @ResponseBody
    @RequestMapping("/returnStr02")
    public String returnStr02(){
        return "returnStr02...";
    }
}


拓展


如果使用@ResponseBody响应的中文字符串,即使配置了CharacterEncodingFilter,也会有乱码

package com.execise.controller;

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

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/*
    返回数据给页面: 字符串 &  JSON
 */
@Controller
public class Controller04 {

    //=================返回字符串(包含中文)=========================

    /*
        使用@ResponseBody 返回字符串的时候,如果返回中文字符串,即使设置了编码过滤器,那么页面看到的仍然是乱码!
        解决:
            有两种办法解决:
                1. 使用标准的写法来设置编码,在springmvc.xml中设置
                    只要配置了,那么对全局都是有效的!
                2. 使用投机取巧的办法!
                    在requestMapping里面使用produces来设置编码,仅对当前的方法生效!
     */
    @ResponseBody
    @RequestMapping("/returnStr03")
    public String returnStr03(){
        return "中文03...";
    }

    // 在requestMapping里面使用produces来设置编码,仅对当前的方法生效!
    @ResponseBody
    @RequestMapping(value = "/returnStr04", produces = "text/html;charset=utf-8")
    public String returnStr04(){
        return "中文04...";
    }

}


解决方法:在springmvc.xml里配置如下:

配置SpringMVC的StringHttpMessageConverter进行字符串处理转换,设置采用utf-8字符集

  <mvc:annotation-driven>
        <!--设置消息转换器-->
        <mvc:message-converters>
            <!--设置从后端给前端返回的字符串的消息转换器,设置它的转换的编码-->
            <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                <property name="defaultCharset" value="utf-8"/>

                <!--针对不同的数据类型,设置不同的编码-->
                <property name="supportedMediaTypes">
                    <list>
                        <value>text/html;charset=utf-8</value>
                        <value>application/json;charset=utf-8</value>
                    </list>
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>

返回json数据

两种方式介绍

  • 自己把JavaBean对象转换成json格式的字符串,响应给客户端

  • 方法返回JavaBean对象,使用@ResponseBody注解Springmvc帮我们转换成json格式 【推荐】


前提条件

在pom.xml中导入依赖:jackson-databind


<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.6</version>
</dependency>

springmvc.xml中开启mvc注解开关

 <mvc:annotation-driven/>

使用示例

package com.execise.controller;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.execise.bean.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

/*
    返回json字符串
        1. 手动把JavaBean和转化成json字符串,然后返回字符串
        2. 直接返回javaBean即可
 */
@Controller
public class Controller05 {

    // 手动把JavaBean对象转化成Json字符串,返回。
    @ResponseBody
    @RequestMapping(value = "/returnJson01" , produces = "application/json;charset=utf-8")
    public String returnJson01() throws JsonProcessingException {

        //1. 构建User
        User user = new User("管理员01","xxx");

        //2. 把这个对象手动转化成Json字符串
        ObjectMapper om  = new ObjectMapper();
        String json = om.writeValueAsString(user);

        return json;
    }

    /*
        1. 直接返回JavaBean,springmvc会把这个JavaBean转化成json字符串返回。
        2. 要想使用这种操作,那么必须要在pom.xml里面添加jackson-databind的依赖
     */
    @ResponseBody
    @RequestMapping("/returnJson02")
    public User returnJson02() throws JsonProcessingException {
        return new User("管理员02","xxx");
    }
}

小结


如果要直接响应数据,使用response对象
public void method1(HttpServletResponse response){
    //如果响应普通文本数据
	//response.setContentType("text/html;charset=utf-8");
    
    //如果响应json格式的字符串
    response.setContentType("application/json;charset=utf-8");
    
    response.getWriter().print("xxxx");
}

如果要bean对象 , 使用注解@ResponseBody


如果返回的是json数据,需要添加jackson-databind的依赖!

@RequestMapping("/method2")
@ResponseBody
public User method2(){
    return new User();
}

四、常用注解


导入依赖

  <dependencies> 
    <!--springmvc-->  
    <dependency> 
      <groupId>org.springframework</groupId>  
      <artifactId>spring-webmvc</artifactId>  
      <version>5.1.2.RELEASE</version> 
    </dependency>  
    <!--jsp-api-->  
    <dependency> 
      <groupId>javax.servlet.jsp</groupId>  
      <artifactId>javax.servlet.jsp-api</artifactId>  
      <version>2.3.1</version>  
      <scope>provided</scope> 
    </dependency>  
    <!--servlet-api-->  
    <dependency> 
      <groupId>javax.servlet</groupId>  
      <artifactId>javax.servlet-api</artifactId>  
      <version>3.1.0</version>  
      <scope>provided</scope> 
    </dependency>  
    <dependency> 
      <groupId>org.projectlombok</groupId>  
      <artifactId>lombok</artifactId>  
      <version>1.18.18</version> 
    </dependency>


    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.9.6</version>
    </dependency>
</dependencies>

定义两个页面


index.jsp

<%--
  Created by IntelliJ IDEA.
  User: xiaomi
  Date: 2021/9/10
  Time: 8:58
  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>
<h2>这是首页~!</h2>
</body>
</html>

success.jsp

<%--
  Created by IntelliJ IDEA.
  User: xiaomi
  Date: 2021/9/10
  Time: 8:58
  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>
<h2>这是成功的页面~!</h2>

</body>
</html>


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

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

            <mvc:annotation-driven/>

            <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                <property name="prefix" value="/"/>
                <property name="suffix" value=".jsp"/>
            </bean>

            <mvc:default-servlet-handler/>
</beans>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5">

	<!--配置前端控制器 DispatcherServlet-->
		<servlet>
			<servlet-name>dispatcher</servlet-name>
			<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

			<init-param>
				<param-name>contextConfigLocation</param-name>
				<param-value>classpath:springmvc.xml</param-value>
			</init-param>

			<load-on-startup>1</load-on-startup>
		</servlet>

		<servlet-mapping>
			<servlet-name>dispatcher</servlet-name>
			<url-pattern>/</url-pattern>
		</servlet-mapping>

	<!--springmvc已经定义好了过滤器,可以帮助我们解决post请求,中文乱码的问题,我们只需要配置即可-->
		<filter>
			<filter-name>char</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>char</filter-name>
			<url-pattern>/*</url-pattern>
		</filter-mapping>
</web-app>

@RequestParam


作用:

  1. 可以对浏览器请求做出参数上的要求,要求一定要有指定名字的参数,如果没有,就报错!

  2. 可以把请求提交上来的参数赋值给方法的形参。

属性

value: 要求携带的参数名字

required:请求参数中是否必须提供此参数。 默认值: true。表示必须提供,如果不提供将报错。

defaultValue:默认值


使用示例


Controller01.java

package com.execise.controller;

import com.execise.bean.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;

/*
    常用的注解:
 */
@Controller
public class Controller01 {


     /*
        @RequestParam:
            作用: 要求客户端来访问的时候,一定要携带指定名称的参数,否则报错!
            步骤:
                1. 在方法参数的前面打注解 @RequestParam
             属性:
                name|value : 用来指定携带的参数名称,如果不指定,那么就以参数名为参考标准。
                required: 表示是否一定要携带参数,默认值是true,
                defaultValue: 默认值
     */
    @RequestMapping("/requestParam")
    public String requestParam(@RequestParam(value="abc" , required = false , defaultValue = "张三") String username , @RequestParam String password){
        System.out.println("username = " + username);
        System.out.println("password = " + password);
        return "success";
    }
}

@RequestParam 只能用于接收 url 的传参 ?name=xxx, form表单的提交。

无法接收提交的json数据(contentType=application/json)


@RequestBody


作用

  1. 用于获取请求体内容。 直接使用得到是 key=value&key=value…结构的字符串。【不常用】

  2. 把获得json类型的数据转成JavaBean对象(后面再讲)【推荐】


注意: get 请求方式不适用


属性

required:是否必须有请求体。默认值是:true。当取值为 true 时,get 请求方式会报错。如果取值为 false, get 请求得到是 null。

  • @RequestBody 不能使用get请求, 在Controller的方法参数里,@RequestBody它只能出现一次!

  • 匹配json数据的获取,例如:request.getInputStream()


使用实例


index.jsp 页面 追加以下内容

<h2>使用@RequestBody获取请求体:</h2>
<form action="/requestBody01" method="post">
    用户名: <input type="text" name="username"/><br/>
    密码: <input type="text" name="password"/><br/>
    <input type="submit">
</form>

Controller01.java

package com.execise.controller;

import com.execise.bean.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;

/*
    常用的注解:
 */
@Controller
public class Controller01 {


   /*
        @RequestBody
            作用:
                1. 可以获取表单提交上来的请求体,只有post请求才有请求体,get请求是没有请求体【不常用】
                    拿到的是一个字符串:  username=admin&password=xxx;
                2. 可以接收页面提交上来的json数据,封装到JavaBe里面【常用】
            步骤:
                1. 方法参数的前面打上注解 @RequestBody,springmvc就会把请求体赋值给方法的参数。
     */
    @RequestMapping("/requestBody01")
    public String requestBody01(@RequestBody String body) throws UnsupportedEncodingException {
        System.out.println("body = " + body);
    }

        /*
            页面提交中文的时候,默认情况下,浏览器会对内容进行编码,使用URLEncoder.encode("张三","utf-8");
                6张三7 ----URLEncoder.encode("张三","utf-8")-----6%E5%BC%A0%E4%B8%897

            如果我们希望看到正常的张三:
                1. 必须要设置过滤器,真正的解决中文乱码的问题。
                2. 对这份数据解码即可:
                6%E5%BC%A0%E4%B8%897 ----------URLDecoder.decode("6%E5%BC%A0%E4%B8%897", utf-8);
         */
        String data = URLDecoder.decode(body, "utf-8");
        System.out.println("data = " + data);

        return "success";
    }
}

接收json数据


客户端发Ajax请求,提交json格式的数据

服务端接收json格式的数据,直接封装成User对象


前提条件

pom.xml中添加jackson的依赖:


<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.6</version>
</dependency>

springmvc.xml中,增加配置静态资源的处理


因为发请求,需要ajax的支持。


<!--配置静态资源的处理-->
<mvc:default-servlet-handler/>

需求实现


index.jsp 添加以下内容


<h2>使用@RequestBody来获取json数据</h2><input type="button" οnclick="sendJSON()" value="点我发送JSON数据"/><script src="js/axios-0.18.0.js"></script><script>    function sendJSON(){        //1. 定义一份json数据        var data = {"username":"admin" , "password":"xxx"};        //2. 使用axios发起异步请求        axios.post("/requestBody02" , data);    }</script>

Controller01

package com.execise.controller;

import com.execise.bean.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;

/*
    常用的注解:
 */
@Controller
public class Controller01 {


  /*
        @RequestBody:
            接收页面提交上来的json数据,封装到JavaBean对象身上。
           步骤:
                1. 前端页面必须提交的是一份json数据

                2. 添加进来jackson-databind的依赖
                    如果不加依赖,会报错: 415 Unsupported Media Type

                3. 定义一个JavaBean,属性名字不能乱写,必须和json里面的KEY一样。

                4. 在Controller方法参数的前面加上注解@RequestBody
                    如果不打注解,那么得到都是null.
     */
    @RequestMapping("/requestBody02")
    public String requestBody02(@RequestBody User user ) {
        System.out.println("user = " + user);
        return "success";
    }

}

@PathVariable


作用:

  • 用于截取请求地址(url)里面的某些部分的数据。这个需要配合RestFul风格来说明

    以前删除用户: localhost:82/deleteUser?id=3restFul :  localhost:82/delete/3
    

属性:

  • value: 用于指定 url 中占位符名称。

  • required:是否必须提供占位符。

场景:获取路径中的参数,与restful编程风格一起,通常微服架构中使用


使用实例


index.jsp 页面添加以下内容

<h2>使用@PathVariable来获取地址中的参数</h2>
<a href="/delete/1">点我发请求</a>
<a href="/delete02/30/40">点我发请求2</a>
  • Controller01.java
package com.execise.controller;

import com.execise.bean.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;

/*
    常用的注解:
 */
@Controller
public class Controller01 {

     /*
        现在以 按照id来删除用户举例:
            以前的写法:  localhost:82/delete?id=1
            restFul:  localhost:82/delete/1

         @PathVariable:
            作用: 用来截取地址栏中的参数,赋值给方法的形参
            步骤:
                1. 在映射地址里面使用 {占位符名字} 来占位,表示匹配这个位置的数据
                2. 在方法参数的前面加上注解 @PathVariable("占位的名字")
             属性:
                name |  value : 用来指定|设置 占位符的名称。
                   如果name和value不写,只有一种情况可以不写,就是占位符的名字和方法的参数名字一样!
     */

    @RequestMapping("/delete/{id}")
    public String pathVariable(@PathVariable(value="id") int id) {
        System.out.println("id = " + id);
        return "success";
    }

    @RequestMapping("/delete02/{id}/{id2}")
    public String pathVariable02(@PathVariable int id , @PathVariable int id2) {
        System.out.println("id = " + id);
        System.out.println("id2 = " + id2);
        return "success";
    }
}

@RequestHeader


作用:

  • 获取指定名字的请求头数据,赋值给方法参数。

属性:

  • value:提供消息头名称

  • required:是否必须有此消息头 , 默认值是true

  • 从请求头中获取参数,鉴权(token 畅购open auth 2.0 jwt token) Authorization


使用实例


index.jsp 页面 添加以下内容

<h2>使用@ReqeustHeader来获取请求头的数据</h2>
<a href="/requestHeader">点我发请求</a>

Controller01.java

package com.execise.controller;

import com.execise.bean.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;

/*
    常用的注解:
 */
@Controller
public class Controller01 {


    /*
        @RequestHeader:
            作用: 用来获取指定名称的请求头数据,赋值给方法的参数
     */
    @RequestMapping("/requestHeader")
    public String requestHeader(@RequestHeader("User-Agent") String data) {
        System.out.println("data = " + data);
        return "success";
    }
}

@CookieValue


作用:

  • 用于把指定 cookie 名称的值传入控制器方法参数。

属性:

  • value:指定 cookie 的名称。

  • required:是否必须有此 cookie, 默认值是:true


使用实例


index.jsp 页面添加以下内容

<h2>使用@CookieValue来获取Cookie的值</h2>
<a href="/cookieValue">点我发请求</a>



Controller01.java

package com.execise.controller;

import com.execise.bean.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;

/*
    常用的注解:
 */
@Controller
public class Controller01 {




    /*
        @CookieValue
            作用: 用来获取指定名称的cookie的值,赋值给方法的形参。
            属性:
                name&value : 指定cookie的名字!

           JESSIONID:
                1. 这是session作用域的id的名称,它会存放到cookie里面去。
                2. 当我们打开首页的时候,访问的是index.jsp  ----背后会被翻译成========> Servlet
                3. 在这个翻译成的servlet里面,它会创建session对象,并且把session的地址存放到cookie里面去。
                    存放的cookie的KEY 叫做: JSESSIONID.
     */
    @RequestMapping("/cookieValue")
    public String cookieValue(@CookieValue("JSESSIONID") String data) {
        System.out.println("data = " + data);
        return "success";
    }

}


小结

  1. 这几个注解都使用作用在方法的参数上,不是写在方法上。他们或多或少都是对客户端提交的数据有这样或者那样的要求

  2. @RequestParam : 要求客户端必须要携带指定的参数。

  3. @RequestBody: 要求必须有请求体,一般它是作用于 页面提交上来的json数据,转化成 javabean对象

  4. @PathVariable : 路径变量,配合RestFul风格使用,用于截取地址里面的数据

  5. @RequestHeader: 用来获取的指定的请求头数据,赋值给方法形参

  6. @CookieValue: 用来获取的cookie数据,赋值给方法的形参。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

请叫我阿杰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值