SpringMVC(下)

一、访问静态资源

在进行Spring MVC的配置时,通常我们会配置一个dispatcher servlet用于处理对应的URL

在设置url-pattern时可以设置三种形式

(1)/* :拦截所有 jsp js png .css 真的全拦截。不建议使用。

(2)/ :拦截所有,不包括jsp,包含.js .png.css 建议使用。

(3).action .do :拦截以do action 结尾的请求。

<!-- 配置SpringMVC前端控制器 -->
<servlet>
    <servlet-name>mySpringMVC</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- 指定SpringMVC配置文件 -->
    <!-- SpringMVC的配置文件的默认路径是/WEB-INF/${servlet-name}-servlet.xml -->
    <init-param>
        <!-- DispatcherServlet类的初始化参数 -->
        <param-name>contextConfigLocation</param-name>
        <!-- 初始化参数的值,即springmvc配置文件的路径 -->
        <param-value>classpath:springmvc.xml</param-value>
    </init-param>
    <!-- 表示web应用启动即加载该servlet -->
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>mySpringMVC</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>
知识兔

url-pattern为 / 时,访问静态资源,会被拦截,找不到静态资源

解决方法:

(1)在springmvc.xml中配置

<mvc:default-servlet-handler/>
知识兔

自动的根据访问地址看下是不是静态资源,如果是直接放行,如果不是就去找 @RequestMapping

(2)在springmvc.xml中配置 mvc:resources (推荐使用)

<mvc:resources location="/img/" mapping="/img/**"/>   
<mvc:resources location="/js/" mapping="/js/**"/>    
<mvc:resources location="/css/" mapping="/css/**"/>
知识兔

描述:

  • location元素表示webapp目录下的static包下的所有文件;
  • mapping元素表示以/static开头的所有请求路径,如/static/a 或者/static/a/b;
  • 该配置的作用是:DispatcherServlet不会拦截以/static开头的所有请求路径,并当作静态资源交由Servlet处理。

二、Json处理

概述

当前端使用Ajax发送请求时,服务器要以JSON的数据格式响应给浏览器。

使用方式

@ResponseBody来实现;注解方式

@ResponseBody

(1)添加 json处理 相关jar包

+ jackson 2.9.9
    - jackson-annotations-2.9.9.jar
    - jackson-core-2.9.9.jar
    - jackson-databind-2.9.9.jar
知识兔

(2)在springmvc.xml配置文件当中写上

<mvc:annotation-driven/>
知识兔

(3)设置映射方法的返回值为@ResponseBody

请求发送页

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>Title</title>
    <script src="${pageContext.request.contextPath}/js/jquery-3.3.1.min.js"></script>
  </head>
  <body>
  
  <input type="button" value="请求JSON" id="btn">

  <script>
    $(function () {
        $('#btn').click(function () {
            // 发送Ajax 请求
            $.post("${pageContext.request.contextPath}/getJson",function (data) {
                console.log(data);
            })
        });
    });
  </script>
  </body>
</html>
知识兔
方式1-直接返回一个对象
@Controller
public class MyController {
    @RequestMapping("getJson")
    @ResponseBody
    public User show(){
        User user = new User();
        user.setUsername("user2");
        user.setPassword("159357");
        user.setAge(20);
        user.setHobby(new String[]{"篮球","足球"});
        return user;
    }
}
知识兔
方式2-返回一个List集合
@Controller
public class MyController {
    @RequestMapping("getJson")
    @ResponseBody
    public ArrayList<User> show(){
        User user1 = new User();
        user1.setUsername("user2");
        user1.setPassword("159357");
        user1.setAge(20);
        user1.setHobby(new String[]{"篮球","足球"});

        User user2 = new User();
        user2.setUsername("user1");
        user2.setPassword("123456");
        user2.setAge(18);
        user2.setHobby(new String[]{"篮球","足球"});

        ArrayList<User> users = new ArrayList<>();
        users.add(user1);
        users.add(user2);

        return users;
    }
}
知识兔
方式3-返回一个Map集合
@Controller
public class MyController {
    @RequestMapping("getJson")
    @ResponseBody
    public HashMap<String, Object> show(){
        User user1 = new User();
        user1.setUsername("user2");
        user1.setPassword("159357");
        user1.setAge(20);
        user1.setHobby(new String[]{"篮球","足球"});

        User user2 = new User();
        user2.setUsername("user1");
        user2.setPassword("123456");
        user2.setAge(18);
        user2.setHobby(new String[]{"篮球","足球"});

        ArrayList<User> users = new ArrayList<>();
        users.add(user1);
        users.add(user2);

        HashMap<String, Object> map = new HashMap<>();
        map.put("name", "hashmap");
        map.put("list", users);
        return map;
    }
}
知识兔

表单序列化

serialize()
知识兔

请求发送页

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>Title</title>
    <script src="${pageContext.request.contextPath}/js/jquery-3.3.1.min.js"></script>
  </head>
  <body>

  <form id="myform">
    <p>用户Id :<input type="text" name="id"></p>
    <p>用户名 :<input type="text" name="username"></p>
    <p>密码 :<input type="text" name="password"></p>
    <p>性别 :
      <input type="radio" name="sex" value="男">男
      <input type="radio" name="sex" value="女">女
    </p>
    <p>年龄 :<input type="text" name="age"></p>
    <p>爱好 :
      <input type="checkbox" name="like" value="篮球">篮球
      <input type="checkbox" name="like" value="足球">足球
      <input type="checkbox" name="like" value="排球">排球
      <input type="checkbox" name="like" value="乒乓球">乒乓球
    </p>
  </form>

  <input type="button" value="发送form" id="btn">

  <script>
    $(function () {
        $('#btn').click(function () {
            // 获取表单所有参数,发送给服务器
            var serialize = $('#myform').serialize();
            console.log(serialize);
            // output: 参数=值&参数=值&参数=值
        });
    });
  </script>
  </body>
</html>
知识兔

我们希望获取的是json格式的数据:

序列化转Json

(function($){
    $.fn.serializeJson=function(){
        var serializeObj={};
        var array=this.serializeArray();
        var str=this.serialize();
        $(array).each(function(){
            if(serializeObj[this.name]){
                if($.isArray(serializeObj[this.name])){
                    serializeObj[this.name].push(this.value);
                }else{
                    serializeObj[this.name]=[serializeObj[this.name],this.value];
                }
            }else{
                serializeObj[this.name]=this.value;
            }
        });
        return serializeObj;
    };
})(jQuery);
知识兔

请求发送页

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>Title</title>
    <script src="${pageContext.request.contextPath}/js/jquery-3.3.1.min.js"></script>
  </head>
  <body>

  <form id="myform">
    <p>用户Id :<input type="text" name="id"></p>
    <p>用户名 :<input type="text" name="username"></p>
    <p>密码 :<input type="text" name="password"></p>
    <p>性别 :
      <input type="radio" name="gender" value="男">男
      <input type="radio" name="gender" value="女">女
    </p>
    <p>年龄 :<input type="text" name="age"></p>
    <p>爱好 :
      <input type="checkbox" name="hobby" value="篮球">篮球
      <input type="checkbox" name="hobby" value="足球">足球
      <input type="checkbox" name="hobby" value="排球">排球
      <input type="checkbox" name="hobby" value="乒乓球">乒乓球
    </p>
  </form>

  <input type="button" value="发送form" id="btn">

  <script>
    (function($){
        $.fn.serializeJson=function(){
            var serializeObj={};
            var array=this.serializeArray();
            var str=this.serialize();
            $(array).each(function(){
                if(serializeObj[this.name]){
                    if($.isArray(serializeObj[this.name])){
                        serializeObj[this.name].push(this.value);
                    }else{
                        serializeObj[this.name]=[serializeObj[this.name],this.value];
                    }
                }else{
                    serializeObj[this.name]=this.value;
                }
            });
            return serializeObj;
        };
    })(jQuery);

    $(function () {
        $('#btn').click(function () {
            // 获取表单所有参数,发送给服务器
            var serialize = $('#myform').serializeJson();
            console.log(serialize);
        });
    });
  </script>
  </body>
</html>
知识兔

这时候的 serialize 就是以json格式的数据,我们再把数据发送给服务器

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>Title</title>
    <script src="${pageContext.request.contextPath}/js/jquery-3.3.1.min.js"></script>
  </head>
  <body>

  <form id="myform">
    <p>用户Id :<input type="text" name="id"></p>
    <p>用户名 :<input type="text" name="username"></p>
    <p>密码 :<input type="text" name="password"></p>
    <p>性别 :
      <input type="radio" name="gender" value="男">男
      <input type="radio" name="gender" value="女">女
    </p>
    <p>年龄 :<input type="text" name="age"></p>
    <p>爱好 :
      <input type="checkbox" name="hobby" value="篮球">篮球
      <input type="checkbox" name="hobby" value="足球">足球
      <input type="checkbox" name="hobby" value="排球">排球
      <input type="checkbox" name="hobby" value="乒乓球">乒乓球
    </p>
  </form>

  <input type="button" value="发送form" id="btn">

  <script>
    (function($){
        $.fn.serializeJson=function(){
            var serializeObj={};
            var array=this.serializeArray();
            var str=this.serialize();
            $(array).each(function(){
                if(serializeObj[this.name]){
                    if($.isArray(serializeObj[this.name])){
                        serializeObj[this.name].push(this.value);
                    }else{
                        serializeObj[this.name]=[serializeObj[this.name],this.value];
                    }
                }else{
                    serializeObj[this.name]=this.value;
                }
            });
            return serializeObj;
        };
    })(jQuery);

    $(function () {
        $('#btn').click(function () {
            // 获取表单所有参数,发送给服务器
            var serialize = $('#myform').serializeJson();
            console.log(serialize);

            $.post("${pageContext.request.contextPath}/formJson",serialize,function (data) {
                console.log(data);
            })
        });
    });
  </script>
  </body>
</html>
知识兔

Controller

@Controller
public class MyController {
    @RequestMapping("formJson")
    @ResponseBody
    public String show(User user){
        System.out.println(user);
        return "success";
    }
}
知识兔

发现问题

运行后会发现,当爱好选一个的时候可以正常运行,当选择大等于两个的时候,会报错。

当传递复杂类型的时候,服务器不能接收。

这是因为,默认情况下,在发送请求的时候 Content-Type 都是 application/x-www-form-urlencoded; 直接使用@RequestParam接收参数。 urlencoded 只能发送简单的 key-value 字符串类型。

@RequestBody

默认情况下我们发送的都是 Content-Type: application/x-www-form-urlencoded,直接使用@RequestParam接收参数。

如果不是Content-Type: application/x-www-form-urlencoded 编码的内容,例如application/json, application/xml等;使用@RequestBody接收。

解决方法

在发送的时候以 json 的形式发送,接受的时候以 json 的形式接收。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>Title</title>
    <script src="${pageContext.request.contextPath}/js/jquery-3.3.1.min.js"></script>
  </head>
  <body>

  <form id="myform">
    <p>用户Id :<input type="text" name="id"></p>
    <p>用户名 :<input type="text" name="username"></p>
    <p>密码 :<input type="text" name="password"></p>
    <p>性别 :
      <input type="radio" name="gender" value="男">男
      <input type="radio" name="gender" value="女">女
    </p>
    <p>年龄 :<input type="text" name="age"></p>
    <p>爱好 :
      <input type="checkbox" name="hobby" value="篮球">篮球
      <input type="checkbox" name="hobby" value="足球">足球
      <input type="checkbox" name="hobby" value="排球">排球
      <input type="checkbox" name="hobby" value="乒乓球">乒乓球
    </p>
  </form>

  <input type="button" value="发送form" id="btn">

  <script>
    (function($){
        $.fn.serializeJson=function(){
            var serializeObj={};
            var array=this.serializeArray();
            var str=this.serialize();
            $(array).each(function(){
                if(serializeObj[this.name]){
                    if($.isArray(serializeObj[this.name])){
                        serializeObj[this.name].push(this.value);
                    }else{
                        serializeObj[this.name]=[serializeObj[this.name],this.value];
                    }
                }else{
                    serializeObj[this.name]=this.value;
                }
            });
            return serializeObj;
        };
    })(jQuery);

    $(function () {
        $('#btn').click(function () {
            // 获取表单所有参数,发送给服务器
            var serialize = $('#myform').serializeJson();
            console.log(serialize);

            $.ajax({
                type:"post",
                url:"${pageContext.request.contextPath}/formJson",
                data:JSON.stringify(serialize),
                dataType:'json',
                contentType:'application/json',
                success:function (data) {
                    console.log(data);
                }
            });
        });
    });
  </script>
  </body>
</html>
知识兔

Controller

@Controller
public class MyController {
    @RequestMapping("formJson")
    @ResponseBody
    public String show(@RequestBody User user){
        System.out.println(user);
        return "success";
    }
}
知识兔

这样当爱好选择两个以上的时候就可以接收复杂类型的数据。

现在还有一个小问题:当爱好选择一个时,服务器接收不了。

原因是 当选择一个时,json串中hobby的数据为String类型,而hobby需要数组类型,Content-Type:application/x-www-form-urlencoded; 会自动帮我们解析,而 application/json 不会。所以我们要自己解析。

解决方法:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>Title</title>
    <script src="${pageContext.request.contextPath}/js/jquery-3.3.1.min.js"></script>
  </head>
  <body>

  <form id="myform">
    <p>用户Id :<input type="text" name="id"></p>
    <p>用户名 :<input type="text" name="username"></p>
    <p>密码 :<input type="text" name="password"></p>
    <p>性别 :
      <input type="radio" name="gender" value="男">男
      <input type="radio" name="gender" value="女">女
    </p>
    <p>年龄 :<input type="text" name="age"></p>
    <p>爱好 :
      <input type="checkbox" name="hobby" value="篮球">篮球
      <input type="checkbox" name="hobby" value="足球">足球
      <input type="checkbox" name="hobby" value="排球">排球
      <input type="checkbox" name="hobby" value="乒乓球">乒乓球
    </p>
  </form>

  <input type="button" value="发送form" id="btn">

  <script>
    (function($){
        $.fn.serializeJson=function(){
            var serializeObj={};
            var array=this.serializeArray();
            var str=this.serialize();
            $(array).each(function(){
                if(serializeObj[this.name]){
                    if($.isArray(serializeObj[this.name])){
                        serializeObj[this.name].push(this.value);
                    }else{
                        serializeObj[this.name]=[serializeObj[this.name],this.value];
                    }
                }else{
                    serializeObj[this.name]=this.value;
                }
            });
            return serializeObj;
        };
    })(jQuery);

    $(function () {
        $('#btn').click(function () {
            // 获取表单所有参数,发送给服务器
            var serialize = $('#myform').serializeJson();
            console.log(serialize);
            // 解析
            if (typeof serialize.hobby == "string") {
                serialize.hobby = new Array(serialize.hobby);
            }

            $.ajax({
                type:"post",
                url:"${pageContext.request.contextPath}/formJson",
                data:JSON.stringify(serialize),
                dataType:'json',
                contentType:'application/json',
                success:function (data) {
                    // alert(data.responseText)
                    console.log(data);
                }
            });
        });
    });
  </script>
  </body>
</html>
知识兔

@RequestBody 获取文件信息

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>Title</title>
    <script src="${pageContext.request.contextPath}/js/jquery-3.3.1.min.js"></script>
  </head>
  <body>
  <form action="${pageContext.request.contextPath}/myfile" method="post" enctype="multipart/form-data">
    <input type="file" name="myfile">
    <input type="submit" value="提交">
  </form>
  </body>
</html>
知识兔

Controller

@RequestMapping("myfile")
@ResponseBody
public String file(@RequestBody String file){
    System.out.println(file);
    return "success";
}
知识兔

三、视图解析器

视图解析器

请求处理方法执行完成后,最终返回一个 ModelAndView 对象

对于那些返回 String,View 或 ModeMap 等类型的处理方法,Spring MVC 也会在内部将它们装配成一个 ModelAndView 对象。

它包含了逻辑名和模型对象的视图,Spring MVC 借助视图解析器(ViewResolver)得到最终的视图对象(View),最终的视图可以是 JSP 。

视图

视图的作用是渲染模型数据,将模型里的数据以某种形式呈现给客户,视图对象由视图解析器负责实例化

在org.springframework.web.servlet 包中定义了一个高度抽象的 View 接口

常见实现类:InternalResourceView,将JSP或其它资源封装成一个视图,是InternalResourceViewResoler默认使用的实现类。

源码分析

执行DispatcherServlet

(1)获取mapping映射

(2)获取适配器

(3)调用处理器,执行映射方法,返回MV

(4)处理转发页面

(5)在方法内部渲染页面

(6)创建视图对象

(7)调用View对象渲染页面

(8)在render内部解析数据

(9)转发到jsp页面

计算机