SpringMVC的注解式开发

SpringMVC概述

文章目录

一、SpringMVC简介

​ SpringMVC也叫Spring web mvc。是Spring框架的一部分, 是在Spring3.0后发布的。
优点:

  • 基于MVC架构功能分工明确。解耦合
  • 容易理解,上手快,使用简单。可以开发一个注解的SpringMVC项目,SpringMVC也是轻量级的,jar 很小。不依赖特定的接口和类
  • 作为Spring框架一部分,能够使用Spring的 loC和Aop。方便整合Strtus、MyBatis、Hiberate、JPA等其他框架
  • SpringMVC强化注解的使用,在控制器,Service, Dao 都可以使用注解。方便灵活

​ 使用@Controller创建处理器对象,@Service创建业务对象,@Autowired 或者@Resource 在控制器类中注入Service,Service 类中注入Dao

二、第一个注解的SpringMVC程序

​ 所谓SpringMVC的注解式开发是指,在代码中通过对类与方法的注解,便可完成处理器在springmvc容器的注册。

​ 注解式开发是重点。

​ 完成功能:用户提交一个请求,服务端处理器在接收到这个请求后,给出一条欢迎信息,在响应页面中显示该信息。

1、新建maven web项目

在这里插入图片描述

2、pom.xml
<!--servlet依赖-->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
    <scope>provided</scope>
</dependency>
<!--springmvc依赖-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.6.RELEASE</version>
</dependency>
3、注册中央调度器

​ 声明,注册springmvc的核心对象DispatcherServlet,需要在tomcat服务器启动后,创建DispatcherServlet对象的实例。

重点:在web.xml 中注册springmvc框架的核心对象DispatcherServlet

  • Dispatcherservlet 叫做中央调度器,是一个servlet,它的父类是继承HttpServlet
  • DispatcherServlet 也叫做前端控制器(front controller)
  • DispatcherServlet 负责接收用户提交的请求,调用其它的控制器对象,并把请求的处理结果显示给用户

​ 为什么要创建DispatcherServlet对象的实例呢?

​ 因为DispatcherServlet在创建过程中,会同时创建springmvc容器对象,读取springmvc的配置文件, 把这个配置文件中的对象都创建好,当用户发起请求时就可以直接使用对象了。

//servlet的初始化会执行init()方法,DispatcherServlet在init()中执行如下程序
init(){
    //创建容器,读取配置文件
    WebApplicationContext ctx = new ClassPathXmlApplicationContext("springmvc.xml");
    //把容器对象放入到ServletContext中
    getServletContext().setAttribute(key,ctx);
}

web.xml

<servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!--自定义springmvc读取的配置文件的位置-->
        <init-param>
        <!--springmvc的配置文件的位置属性-->
        <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>springmvc</servlet-name>
    <url-pattern>*.do</url-pattern>
</servlet-mapping>

解析:

  • springmvc创建容器对象时, 读取的配置文件默认是/WEB - INF/<servlet - name> servlet.xml。

在tomcat启动后,创建Servlet对象

  • load-on-startup:表示tomcat启动后创建对象的顺序。值是整数,数值越小(大于等于0的整数),tomcat 创建对象的时间越早
  • 使用框架的时候,url-pattern 可以使用两种值
    • 使用扩展名方式,语法:*.xxx,xxx是自定义的扩展名。常用的方式 * .do、 *.action、 *.mvc 等等
    • 使用斜杠 " / "
4、创建SpringMVC配置文件

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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans.xsd">

</beans>
5、创建处理器
package cn.edu.huat.controller;

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

@Controller
public class MyController {
    @RequestMapping(value = "/some.do")
    public ModelAndView doSome(){
        ModelAndView mv = new ModelAndView();
        //添加数据,框架在请求的最后把数据放入到request作用域
        //相当于request.setAttribute("msg","欢迎来到SpringMVC的世界");
        mv.addObject("msg","欢迎来到SpringMVC的世界");
        mv.addObject("fun","执行doSome()方法");
        //指定视图,指定视图的完整路径
        //框架对视图执行的forward操作,request.getRequestDispatcher("/show.jsp").forward(request,response);
        mv.setViewName("/show.jsp");
        //返回mv
        return mv;
    }
}

处理用户提交的请求,springmvc中是使用方法来处理的。
方法是自定义的,可以有多种返回值,多种参数 ,方法名称自定义。准备使用doSome方法处理some.do请求。

返回值:ModelAndView表示本次请求的处理结果

  • Model:数据,请求处理完成后,要显示给用户的数据
  • View:视图,比如 jsp等等

@RequestMapping:请求映射,作用是把一个请求地址和一个方法绑定在一起,一个请求指定一个方法处理

  • 属性
    • value是一个string,表示请求的uri 地址(some.do)
    • value的值必须是唯一的,不能重复。在使用时,推荐地址以 “/ ” 开头
  • 位置
    • 在方法的上面(常用)
    • 在类的上面
  • 说明:使用RequestMapping修饰的方法叫做处理器方法或者控制器方法
  • 使用@Reques tMapping修饰的方法可以处理请求的,类似servlet 中的doGet、doPost
6、声明组件扫描器

springmvc.xml

<context:component-scan base-package="cn.edu.huat.controller" />
7、定义目标页面
<h2>Hello SpringMVC!</h2><br>
<h3>msg=${msg}</h3>
<h3>fun=${fun}</h3>
8、修改视图解析器的注册

springmvc.xml

<!--声明SpringMVC框架中的视图解析器,帮助开发人员设置视图文件的路径-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <!--前缀:视图文件的路径-->
    <property name="prefix" value="/WEB-INF/view/" />
    <!--后缀:视图文件的扩展名-->
    <property name="suffix" value=".jsp" />
</bean>
9、修改处理器
//当配置了视图解析器后,可以使用逻辑名称(文件名), 指定视图
//框架会使用视图解析器的前缀 + 逻辑名称 + 后缀,组成完成路径 ,这里就是字符连接操作:/WEB-INF/view/ + show + .jsp
mv.setViewName("show");
10、使用SpringMVC框架web请求
(1)初始页面

在这里插入图片描述

(2)发送请求

在这里插入图片描述

三、SpringMVC的MVC组件

在这里插入图片描述

四、SpringMVC执行流程(理解)

1、springmvc请求的处理流程
  • 发起some .do
  • tomcat(web.xml ------- url-pattern 知道 *.do的请求给 Dispatcherservlet)
  • DispatcherServlet(根据springmvc.xml 配置知道 some.do ------- doSome () )
  • Dispatcherservlet 把 some.do转发给 MyController.doSome() 方法
  • 框架执行doSome () 把得到的 ModelAndView 进行处理,转发到show.jsp
2、上面的过程简化方式

some.do -------- DispatcherServlet -------- MyController

3、视图理解

在这里插入图片描述

4、springmvc执行过程源代码分析
(1)tomcat启动,创建容器的过程

通过 load-on-start 标签指定的1,创建DisaptcherServlet对象,DisaptcherServlet 它的父类是继承HttpServlet 的,它是一个serlvet,在被创建时,会执行init() 方法。
在init() 方法中

//创建容器,读取配置文件
WebApplicationContext ctx = new ClassPathXmlApplicationContext("springmvc.xml");
//把容器对象放入到servletContext中
getServletContext().setAttribute(key,ctx);

上面创建容器作用:创建@controller注解所在的类的对象, 创建MyController对象,这个对象放入到springmvc 的容器中,容器是map,类似 map.put(“myController”,MyController对象)。如下图源码所示:
在这里插入图片描述

(2)请求的处理过程

执行servlet 的service()

  • protected void service (HttpServletRequest request, HttpServletResponse response )

  • protected void doService (HttpServletRequest request, HttpServletResponse response)

  • Dispatcherservlet.doDispatch (request, response) {

    ​ 调用MyController的 .doSome() 方法

    }

五、@RequestMapping定义请求规则

1、指定模块名称

​ 通过@RequestMapping注解可以定义处理器对于请求的映射规则。该注解可以注解在方法上,也可以注解在类上,但意义是不同的。value 属性值常以 “ / ” 开始。

​ @RequestMapping的value属性用于定义所匹配请求的URI。但对于注解在方法上与类上,其value 属性所指定的URI,意义是不同的。

​ 一个@Controller 所注解的类中,可以定义多个处理器方法。当然,不同的处理器方法所匹配的URI 是不同的。这些不同的URI 被指定在注解于方法之上的@RequestMapping的value属性中。但若这些请求具有相同的URI 部分,则这些相同的URI,可以被抽取到注解在类之上的@RequestMapping的value 属性中。此时的这个URI 表示模块的名称。URI 的请求是相对于Web的根目录

​ 换个角度说,要访问处理器的指定方法,必须要在方法指定URI 之前加上处理器类前定义的模块名称

@RequestMapping

  • value:所有请求地址的公共部分, 叫做模块名称
  • 位置:放在类的上面
package cn.edu.huat.controller;

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

@Controller
@RequestMapping("/user")
public class MyController {
    @RequestMapping(value = "/some.do")
    public ModelAndView doSome(){
        ModelAndView mv = new ModelAndView();
        mv.addObject("msg","欢迎来到SpringMVC的世界");
        mv.addObject("fun","执行doSome()方法");
        mv.setViewName("show");
        return mv;
    }
}
2、对请求提交方式的定义

@RequestMapping:请求映射

  • 属性:method,表示请求的方式。它的值是RequestMethod类枚举值
    • 表示get 请求方式,RequestMethod.GET
    • 表示post 请求方式,RequestMethod.POST
(1)指定some.do是GET请求方式
@RequestMapping(value = "/some.do",method = RequestMethod.GET)
(2)指定some.do是POST请求方式
@RequestMapping(value = "/some.do",method = RequestMethod.POST)
(3)不指定请求方式,没有限制
@RequestMapping(value = "/some.do")

六、处理器方法的参数

​ 处理器方法可以包含以下四类参数,这些参数会在系统调用时由系统自动赋值,即程序员可在方法内直接使用

  • HttpServletRequest
  • HttpServletResponse
  • HttpSession
  • 请求中所携带的请求参数
1、逐个参数接收

要求:处理器(控制器)方法的形参名和请求中参数名必须一致,同名的请求参数赋值给同名的形参

框架接收请求参数

  • 使用 request 对象接收请求参数

    String username = request.getParameter("username");
    String password = request.getParameter("password");
    
  • SpringMVC 框架通过 DispatcherServlet 调用 MyController 的 doSome() 方法,调用方法时,按名称对应把接收的参数赋值给形参

    public ModelAndView doSome(String username,String password){}
    

    框架会提供类型转换的功能,把 String 转为 int、long、float、double 等类型。

    注意:经常会出现400错误(400状态码是客户端错误,表示提交请求参数过程中, 发生了问题)

2、请求参数中文乱码问题

​ 对于前面所接收的请求参数,若含有中文,则会出现中文乱码问题。Spring 对于请求参数中的中文乱码问题,给出了专门的字符集过滤器:spring-web-5.2.6.RELEASE.jar 的org.springframework.web.filter 包下的CharacterEncodingFilter 类。

​ 在web.xml 中注册字符集过滤器,即可解决Spring 的请求参数的中文乱码问题。不过,最好将该过滤器注册在其它过滤器之前。因为过滤器的执行是按照其注册顺序进行的。

web.xml

<!--注册声明过滤器,解决post请求乱码问题-->
<filter>
    <filter-name>characterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <!--设置项目中使用的字符编码-->
    <init-param>
        <param-name>encoding</param-name>
        <param-value>utf-8</param-value>
    </init-param>
    <!--强制请求对象(HttpServletRequest)使用encoding编码的值-->
    <init-param>
        <param-name>forceRequestEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
    <!--强制应答对象(HttpServletResponse)使用encoding编码的值-->
    <init-param>
        <param-name>forceResponseEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>characterEncodingFilter</filter-name>
    <!-- /*:表示强制所有的请求先通过过滤器处理 -->
    <url-pattern>/*</url-pattern>
</filter-mapping>

CharacterEncodingFilter部分源码:

protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
    String encoding = this.getEncoding();
    if (encoding != null) {
        if (this.isForceRequestEncoding() || request.getCharacterEncoding() == null) {
            request.setCharacterEncoding(encoding);
        }
        if (this.isForceResponseEncoding()) {
            response.setCharacterEncoding(encoding);
        }
	}
    filterChain.doFilter(request, response);
}
3、校正请求参数名@RequestParar

​ 所谓校正请求参数名,是指若请求URL 所携带的参数名称与处理方法中指定的参数名不相同时,则需在处理方法参数前,添加一个注解@RequestParam("请求参数名”),指定请求URL 所携带参数的名称。该注解是对处理器方法参数进行修饰的。value 属性指定请求参数的名称。

@RequestParam:逐个接受请求参数中,解决请求中参数名形参名不一样的问题

  • 属性

    • value请求中的参数名称
    • required 是一个boolean,默认是true(表示请求中必须包含此参数)
  • 位置:在处理器方法的形参定义的前面

(1)修改index页面

将表单中的参数名称修改的与原来不一样

<form action="some.do" method="post">
    姓名:<input type="text" name="name" /><br>
    密码:<input type="text" name="pwd" /><br>
    <input type="submit" value="登录">
</form>
(2)修改处理器类MyController
public ModelAndView doSome(@RequestParam("name") String username, @RequestParam("pwd") String password){}
4、对象参数接收

​ 将处理器方法的参数定义为一个对象,只要保证请求参数名与这个对象的属性同名即可

  • 处理器方法形参是 java对象,这个对象的属性名和请求中参数名一样
  • 框架会创建形参的 java对象,给属性赋值
  • 请求中的参数是name,框架会调用 setName() 方法
(1)定义类User
package cn.edu.huat.domain;

public class User {
    //属性名和请求参数名一致
    private String username;
    private String password;
    //setting and getting
}
(2)修改处理器类MyController
package cn.edu.huat.controller;

import cn.edu.huat.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class MyController {
    @RequestMapping(value = "/some.do")
    public ModelAndView doSome(User user){
        ModelAndView mv = new ModelAndView();
        mv.addObject("username",user.getUsername());
        mv.addObject("password",user.getPassword());
        mv.addObject("user",user);
        mv.setViewName("show");
        return mv;
    }
}

七、处理器方法的返回值

​ 使用@Controller 注解的处理器的处理器方法,其返回值常用的有四种类型:

  • 第一种:ModelAndView

  • 第二种:String

  • 第三种:无返回值 void

  • 第四种:返回自定义类型对象

    根据不同的情况,使用不同的返回值

1、返回ModelAndView

​ 若处理器方法处理完后,需要跳转到其它资源,且又要在跳转的资源间传递数据,此时处理器方法返回ModelAndView 比较好。当然,若要返回ModelAndView,则处理器方法中需要定义ModelAndView 对象。

​ 在使用时,若该处理器方法只是进行跳转而不传递数据,或只是传递数据而并不向任何资源跳转(如对页面的Ajax异步响应),此时若返回ModelAndView,则将总是有一部分多余:要么Model 多余,要么View 多余。即此时返回ModelAndView 不合适。

2、返回String

​ 处理器方法返回的字符串可以指定逻辑视图名,通过视图解析器解析可以将其转换为物理视图地址

返回内部资源逻辑视图名

​ 若要跳转的资源为内部资源,则视图解析器可以使用 InternalResourceViewResolver 内部资源视图解析器。此时处理器方法返回的字符串就是要跳转页面的文件名去掉文件扩展名后的部分。这个字符串与视图解析器中的 prefix、suffix相结合,即可形成要访问的URI。

<!--注册视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/view/" />
    <property name="suffix" value=".jsp" />
</bean>
(1)逻辑视图名称

​ 处理器方法返回string,表示逻辑视图名称,需要配置视图解析器

package cn.edu.huat.controller;

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

import javax.servlet.http.HttpServletRequest;

@Controller
public class MyController {
    @RequestMapping("/returnString-view.do")
    public String doReturnView(HttpServletRequest request,String username, String password){
        //可以自己手工添加数据到request作用域
        request.setAttribute("username",username);
        request.setAttribute("password",password);
        //show:逻辑视图名称,项目中配置了视图解析器
        //框架对视图执行forward转发操作
        return "show";
    }
}
(2)完整视图路径

​ 处理器方法返回String,表示完整视图路径,此时不能配置视图解析器

return "/WEB-INF/view/show.jsp";
3、返回void(了解)

​ 若处理器对请求处理后,无需跳转到其它任何资源,此时可以让处理器方法返回void

​ 例如,对于AJAX的异步请求的响应。

(1)maven加入jackson依赖

​ 由于本项目中服务端向浏览器传回的是 JSON数据,需要使用一个工具类将字符串包装为 JSON格式,所以需要导入 JSON的依赖

<!--Jackson依赖-->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.9.8</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.8</version>
</dependency>
(2)定义页面(index.jsp)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    <script type="text/javascript" src="js/jquery-1.10.2.js"></script>
    <script type="text/javascript">
        $(function () {
            $("button").click(function () {
                $.ajax({
                    url:"returnVoid-ajax.do",
                    data:{
                        username:"张三",
                        password:"1234"
                    },
                    type:"post",
                    dataType:"json",
                    success:function (resp) {
                        //resp从服务器端返回的是json格式的字符串 {"name":"张三",password:"1234"}
                        //jquery会把字符串转为json对象,赋值给resp形参
                        alert(resp.username + "   " + resp.password);
                    }
                })
            })
        })
    </script>
</head>
<body>
    <button id="btn">发起AJAX请求</button>
</body>
</html>
(3)处理器类(MyController)
package cn.edu.huat.controller;

import cn.edu.huat.domain.User;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

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

@Controller
public class MyController {
    @RequestMapping("/returnVoid-ajax.do")
    public void doReturnVoidAjax(HttpServletResponse response, String username, String password) throws IOException {
        //处理ajax,使用json做数据的格式
        //service调用完成了,使用User表示处理结果
        User user = new User();
        user.setUsername(username);
        user.setPassword(password);
        //把结果的对象转为json格式的数据
        String json = "";
        if (user != null){
            ObjectMapper om = new ObjectMapper();
            json = om.writeValueAsString(user);
            System.out.println("user转换的json = " + json);
        }
        //输出数据,响应ajax请求
        response.setContentType("application/json;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.println(json);
        out.flush();
        out.close();
    }
}
4、返回对象Object

​ 处理器方法也可以返回Object 对象。这个Object 可以是 Integer,String, 自定义对象,Map,List等。但返回的对象不是作为逻辑视图出现的,而是作为直接在页面显示的数据出现的

​ 返回对象,需要使用@ResponseBody 注解,将转换后的 JSON数据放入到响应体中。

实现步骤 :

  • 加入处理 Json的工具库的依赖,springmvc默认使用的 jackson

  • 在sprigmvc 配置文件之间加入<mvc:annotation- driven>注解驱动

    //相当于做了以下程序的工作
    json = om.writeValueAsString(user);
    
  • 在处理器方法的上面加入@ResponseBody注解

    //相当于做了以下程序的工作
    response.setContentType("application/json;charset=utf-8");
    PrintWriter out = response.getWriter();
    out.println(json);
    
(1)环境搭建
A、maven pom.xml

​ 由于返回Object 数据,一般都是将数据转化为了 JSON对象后传递给浏览器页面的。而这个由Object 转换为 JSON,是由 Jackson工具完成的。所以需要导入 Jackson的相关 Jar包。

<!--Jackson依赖-->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.9.8</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.8</version>
</dependency>
B、声明注解驱动

​ 将Object数据转化为 JSON数据,需要由消息转换器 HttpMessageConverter完成。而转换器的开启,需要由<mvc:annotation - driven/>来完成。

​ SpringMVC使用消息转换器实现请求数据和对象,处理器方法返回对象和响应输出之间的自动转换。

​ 当Spring容器进行初始化过程中,在<mvc:annotation - driven/> 处创建注解驱动时,默认创建了七个HttpMessageConverter对象。也就是说,我们注册<mvc:annotation - driven/>,就是为了让容器为我们创建HttpMessageConverter对象

​ HttpMessageConverter接口: HttpMessageConverter<T> 是Spring3.0 新添加的一个接口,负责将请求信息转换为一个对象(类型为T),将对象(类型为T)输出为响应信息

  • 功能:定义了 java转为 json、xml 等数据格式的方法。这个接口有很多的实现类,这些实现类完成 java对象到 json、java对象到xml、java对象到二进制等数据的转换
//下面的两个方法是控制器类把结果输出给浏览器时使用的
boolean canwrite(Class<?> var1, @Nullable MediaType var2);
void write(T var1, @Nullable MediaType var2, HttpoutputMessage var3);

例如处理器方法:

@RequestMapping("/returnVoid-ajax.do")
public void doReturnVoidAjax(HttpServletResponse response, String username, String password) throws IOException {
    User user = new User();
    user.setUsername("zs");
    user.setPassword("123");
    return user;
}
  • canWrite:作用检查处理器方法的返回值,能不能转为 var2表示的数据格式。

    user(“zs”,123);
    //检查user(“zs”,”123”);能不能转为var2表示的数据格式。如果检查能转为json,则canWrite返回true
    

    MediaType:表示数据格式的,例如 json、xml 等等

  • write:把处理器方法的返回值对象,调用 jackson中的 ObjectMapper转为 json字符串

    json = om.writeValueAsString(user);
    

HttpMessageConverter<T> 接口定义的方法:

  •   boolean canRead(Class<?> clazz,MediaType mediaType)
      //指定转换器可以读取的对象类型,即转换器是否可将请求信息转换为clazz类型的对象,同时指定支持MIME类型(text/html、applaiction/json等)
    
  •   boolean canWrite(Class<?> clazz,MediaType mediaType)
      //指定转换器是否可将clazz类型的对象写到响应流中,响应流支持的媒体类型在MediaType中定义
    
  •   LIst<MediaType> getSupportMediaTypes()
      //该转换器支持的媒体类型
    
  •   T read(Class<? extends T> clazz,HttpInputMessage inputMessage)
      //将请求信息流转换为T类型的对象
    
  •   void write(T t,MediaType contnetType,HttpOutputMessgae outputMessage)
      //将T类型的对象写到响应流中,同时指定相应的媒体类型为contentType
    

对于加入注解驱动<mvc:annotation - driven/>后适配器类的messageConverters属性值的前后对比

  • 没有加入注解驱动标签 <mvc:annotation - driven /> 时的状态
    • org.springframework.http.converter.ByteArrayHttpMessageConverter
    • org.springframework.http. converter.StringHttpMessageConverter
    • org.springframework.http.converter.xml.SourceHttpMessageConverter
    • org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter
  • 加入注解驱动标签时 <mvc:annotation - driven /> 的时状态
    • org.springframework.http.converter.ByteArrayHttpMessageConverter
    • org.springframework.http. converter.StringHttpMessageConverter
    • org.springframework.http.converter.ResourceHttpMessageConverter
    • org .springframework.http.converter.ResourceRegionHttpMessageConverter
    • org.springframework.http.converter.xml.SourceHttpMessageConverter
    • org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter
    • org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter
    • org.springframework.http.converter.json.MappingJackson2HttpMessageConverter

<mvc:annotation - driven>注解驱动实现的功能:完成 java对象到 json、xml、text、二进制等数据格式的转换

<mvc:annotation - driven>在加入到springmvc配置文件后,会自动创建HttpMessageConverter 接口的7个实现类对象,包括MappingJackson2HttpMessageConverter(使用 jackson工具库中的 ObjectMapper实现 java对象转为 Json)

HttpMessageConverter接口实现类作用
ByteArrayHttpMessageConverter负责读取二进制格式的数据和写出二进制格式的数据
StringHttpMessageConverter负贵读取字符串格式的数据和写出字符串格式的数据
ResourceHttpMessageConverter负责读取资源文件和写出资源文件数据
SourceHttpMessageConverter能够读/写来自HTTP 的请求与响应的 javax.xml.transform.Source,支持DOMSource,SAXSource,和 StreamSource 的XML 格式
AllEncompassingFormHttpMessageConvert负责处理表单(form)数据
Jaxb2RootElementHttpMessageConverter使用 JAXB负责读取和写入xml 标签格式的数据
MappingJackson2HttpMessageConverter负责读取和写入 json格式的数据。利用 Jackson的 ObjectMapper读写 json数据,操作 Object类型数据,可读取 application/json,响应媒体类型为application/jison
C、@ResponseBody注解

放在处理器方法的上面,通过HttpServletResponse 输出数据, 响应ajax请求的

@ResponseBody:

  • 作用:把处理器方法返回对象转为 json后,通过HttpServletResponse输出给浏览器
  • 位置:方法的定义上面。和其它注解没有先后顺序的关系
(2)返回自定义类型对象
A、注册注解驱动
<mvc:annotation-driven />
B、修改处理器MyController
package cn.edu.huat.controller;

import cn.edu.huat.domain.User;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class MyController {
    @RequestMapping("/returnUserJson.do")
    @ResponseBody
    public User doUserJsonObject(String username, String password) {
        //调用service,获取请求结果,User对象表示结果数据
        User user = new User();
        user.setUsername("王五");
        user.setPassword("333");
        //会被框架转为json
        return user;
    }
}

返回对象框架的处理流程:

  • 框架会返回 User 类型。调用框架中的 ArrayList<HttpMessageConverter> 中每个类的 canWrite() 方法,检查哪一个HttpMessageConverter 接口的实现类能处理 User 类型的数据(MappingJackson2HttpMessageConverter
  • 框架会调用实现类的 write()。MappingJackson2HttpMessageConverter 的 write() 方法,把 “王五” 的 user对象转为 json,调用Jackson 的 ObjectMapper实现转为 json。
    contentType:application/json; charset=utf-8
  • 框架会调用@ResponseBody。把上一步的结果数据输出到浏览器,ajax请求处理完成
(3)返回List集合
A、修改处理器MyController
package cn.edu.huat.controller;

import cn.edu.huat.domain.User;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.ArrayList;
import java.util.List;

@Controller
public class MyController {
    @RequestMapping("/returnUserJsonArray.do")
    @ResponseBody
    public List<User> doUserJsonObjectArray(String username, String password) {
        List<User> userList = new ArrayList<>();
        User user = new User();
        user.setUsername("王五");
        user.setPassword("333");
        userList.add(user);
        
        user = new User();
        user.setUsername("李四");
        user.setPassword("222");
        userList.add(user);
        return userList;
    }
}

返回对象框架的处理流程:

  • 框架会返回 List<User> 类型。调用框架中的 ArrayList<HttpMessageConverter> 中每个类的 canWrite() 方法,检查哪一个HttpMessageConverter 接口的实现类能处理 List<User> 类型的数据(MappingJackson2HttpMessageConverter
  • 框架会调用实现类的 write()。MappingJackson2HttpMessageConverter 的 write() 方法,把 “王五” 的 user对象以及 “李四” 的 user对象转为 json,调用 Jackson 的 ObjectMapper实现转为 json。
    contentType:application/json; charset=utf-8
  • 框架会调用@ResponseBody。把上一步的结果数据输出到浏览器,ajax请求处理完成
B、修改AJAX请求
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    <script type="text/javascript" src="js/jquery-1.10.2.js"></script>
    <script type="text/javascript">
        $(function () {
            $("button").click(function () {
                $.ajax({
                    url:"returnUserJsonArray.do",
                    data:{
                        username:"张三",
                        password:"1234"
                    },
                    type:"post",
                    dataType:"json",
                    success:function (resp) {
                        $.each(resp,function (i,n) {
                            alert(n.username + "   " + n.password);
                        })
                    }
                })
            })
        })
    </script>
</head>
<body>
    <button id="btn">发起AJAX请求</button>
</body>
</html>
(4)返回字符串对象

​ 若要返回非中文字符串,将前面返回数值型数据的返回值直接修改为字符串即可。但若返回的字符串中带有中文字符,则接收方页面将会出现乱码。此时需要使用@RequestMapping的 produces属性指定字符集。

​ produces,产品,结果,即该属性用于设置输出结果类型

​ 处理器方法返回的是String,String表示数据的,不是视图。区分返回值String是数据,还是视图,看有没有@ResponseBody注解。
如果有@ResponseBody注解,返回String就是数据,反之就是视图

A、修改处理器MyController
package cn.edu.huat.controller;

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

@Controller
public class MyController {
    @RequestMapping(value = "/returnString.do",produces = "text/plain;charset=UTF-8")
    @ResponseBody
    public String doStringData(String username,String password){
        return "Hello SpringMVC 返回对象 表示数据";
    }
}

返回对象框架的处理流程:

  • 框架会返回 String 类型。调用框架中的 ArrayList<HttpMessageConverter> 中每个类的 canWrite() 方法,检查哪一个HttpMessageConverter 接口的实现类能处理 String 类型的数据(StringHttpMessageConverter
  • 框架会调用实现类的 write()。StringHttpMessageConverter 的 write() 方法,把字符按照指定的编码处理text/plain; charset= ISO- 8859-1
  • 框架会调用@ResponseBody。把上一步的结果数据输出到浏览器,ajax请求处理完成
B、修改AJAX请求

默认使用 “ text/plain;charset= ISO-8859-1” 作为contentType,导致中文有乱码。

解决方案:给RequestMapping增加一个属性produces,使用这个属性指定新的contentType

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    <script type="text/javascript" src="js/jquery-1.10.2.js"></script>
    <script type="text/javascript">
        $(function () {
            $("button").click(function () {
                $.ajax({
                    url:"returnUserJsonArray.do",
                    data:{
                        username:"张三",
                        password:"1234"
                    },
                    type:"post",
                    //此时格式由json转为text
                    dataType:"text",
                    success:function (resp) {
                        alert("返回的是文本数据 : " + resp);
                    }
                })
            })
        })
    </script>
</head>
<body>
    <button id="btn">发起AJAX请求</button>
</body>
</html>

八、解读<url-pattern/>

1、配置详解
(1)*.do

​ 在没有特殊要求的情况下,SpringMVC 的中央调度器DispatcherServlet的<url-pattern/>,常使用后辍匹配方式,如写为 *.do 或者 *.action、 *.mvc 等。

(2)/

​ 可以写为 /,因为DispatcherServlet会向静态资源获取请求,例如对 .css、 .js、 .jpg、 .png等资源的获取请求,当作是一个普通的Controller 请求。它会替代tomcat中的default。导致所有的静态资源都给DispatcherServlet 处理,默认情况下DispatcherServlet 没有处理静态资源的权限。

中央调度器会调用处理器映射器为其查找相应的处理器,但是没有控制器对象能处理静态资源的访问,所以访问静态资源(html,js,图片,css等等)获取请求均会报404错误。

动态资源some.do是可以访问,因为我们程序中有MyController控制器对象,能处理some.do请求。

2、静态资源访问
(1)使用 <mvc:default- servlet-handler/>

​ 声明了<mvc:default-servlet-handler /> 后,springmvc 框架会在容器中创建DefaultServletHttpRequestHandler 处理器对象。它会像一个检查员,对进入DispatcherServlet 的URL 进行筛查,如果发现是静态资源的请求,就将该请求转由Web应用服务器默认的
Servlet 处理。一般的服务器都有默认的Servlet。

​ 在Tomcat 中,有一个专门用于处理静态资源访问的Servlet 名叫DefaultServlet。 其<servlet-name/>为default。可以处理各种静态资源访问请求。该Servlet 注册在Tomcat 服务器的web.xml 中。在Tomcat 安装目录/conf/web.xml
在这里插入图片描述

<mvc:annotation-driven />
<mvc:default-servlet-handler />

注意:default-servlet-handler 和 @RequestMapping 注解有冲突,需要加入 annotation-driven 解决问题

(2)使用<mvc:resources />(掌握)

​ 在Spring3.0 版本后,Spring定义了专门用于处理静态资源访问请求的处理器ResourceHttpRequestHandler。并且添加了<mvc:resources />标签,专门用于解决静态资源无法访问问题。需要在springmvc配置文件中添加如下形式的配置:

<mvc:annotation-driven />
<mvc:resources mapping="/images/**" location="/images/" />
<mvc:resources mapping="/html/**" location="/html/" />
<mvc:resources mapping="/js/**" location="/js/" />

解析:

  • location:表示静态资源所在目录。当然,目录不要使用/WEB-INF/及其子目录
  • mapping:表示对该资源的请求(以 /images/ 开始的请求,如 /image/beauty.jpg,/images/car.png 等)。注意,后面是两个星号**

注意:resources 和 @RequestMapping 注解有冲突

常用方式

可以在webapp下创建 “ static ” 目录,把所有的静态资源放入其中

<a href="static/html/hello.html">hello</a>
<img src="static/images/333.jpeg" alt="我是一个静态资源,不能显示">

这时候使用一个配置语句,则可以指定多种静态资源的访问

<mvc:annotation-driven />
<mvc:resources mapping="/static/**" location="/static/" />
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值