深入理解Spring MVC-获取控制器参数

前言

在处理器运行的过程中会调度控制器的方法,只是他在进入控制器方法之前会对HTTP的参数和上下文进行解析,将他们转化为控制器所需要的参数。这一步是处理器首先需要做的事情,只是大部分情况下不需要自己去开发这一步,因为SpringMVC已经提供了大量的转换规则,通过这些规则就能够非常简易的获取大部分的参数。

正如之前章节一样,大部分情况下,我们并不在意如何获取参数,那是因为之前的场景都比较简单,在实际的开发中可能遇到复杂的场景,这样参数的获取就会变得复杂起来。例如,可能前端传递一个格式化的日期参数,又如需要传递复杂的对象给控制器,这个时候需要对SPring MVC参数的获取做进一步学习了。

1. 在无注解下获取参数

在没有注解的情况下,Spring MVC也可以获取参数,且参数允许为空,惟一的要求是参数名称和Http请求的参数名称保持一致,代码清单如下:


@Controller
@RequestMapping("/my")
public class MyController {
    /**
     * 再无注解下获取参数,要求参数名和Http请求参数名称一致
     * @param intVal --整数
     * @param longVal --长整型
     * @param str --字符串
     * @return 响应JSON参数
     */
    @GetMapping("/no/annotation")
    @ResponseBody
    public Map<String, Object> noAnnotation(Integer intVal,
                                            Long longVal, String str){
        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("intVal", intVal);
        paramsMap.put("longVal", longVal);
        paramsMap.put("str",str);
        return paramsMap;
    }
}

启动Spring Boot应用之后,在浏览器请求URL

http://localhost:8243/my/no/annotation?intVal=10&longVal=2200

从代码中可以看出控制器方法参数中还有一个字符串参数str,但是因为参数在默认的规则下可以为空,所以这个请求并不会报错,因为方法标注了@ResponseBody,所以控制器返回的结果就转化为JSON数据集。

{"str":null,"intVal":10,"longVal":2200}

2.使用@RequestParam获取参数

上节谈到过,在无需任何注解的情况下,就要求http参数和控制器方法参数名称保持一致。然而在前后端分离的趋势下,前端的命名规则可能和后端的规则不同,这是就需要把前端的参数与后端的参数对应起来。Spring MVC提供了注解@RequestParam来确定前后端参数名称的映射关系,下面用实例来给予说明

    @GetMapping("/annotation")
    @ResponseBody
    public Map<String, Object> requestParam(
            @RequestParam("int_val") Integer intVal,
            @RequestParam("long_val") Long longVal,
            @RequestParam("str_val") String str){
        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("intVal", intVal);
        paramsMap.put("longVal", longVal);
        paramsMap.put("str",str);
        return paramsMap;
    }

从代码中可以看出,在方法参数处使用了注解@RequestParam,其目的是指定HTTP参数和方法参数的映射关系,这样处理器就会按照其配置的映射关系来得到参数,然后调用控制器的方法。启动Spring Boot应用之后,在浏览器地址输入:http://localhost:8243/my/annotation?int_val=10&long_val=2200&&str_val=str,
就能够看到请求结果了。但是把三个HTTP参数中的任意一个删去,就会得到400的异常报错信息,因为在默认的情况下@RequestParam标注的参数是不能为空的,为了能够让他为空,可以配置其属性required为false,例如,把代码中的字符串参数str修改为

@RequestParam(value = "str_val",required = false) String strVal

这样对应参数就允许为空了。

3. 传递数组

在Spring MVC中,除了可以像上面那样传递一些简单的值以外,还可以传递数组。Spring MVC内部已经能够支持用逗号分隔的数组参数,下面带代码中新增方法

    @GetMapping("/requestArray")
    @ResponseBody
    public Map<String, Object> requestArray(
            @RequestParam("int_val") int[] intVal,
            @RequestParam("long_val") Long[] longVal,
            @RequestParam(value = "str_val") String[] strVal){
        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("intVal", intVal);
        paramsMap.put("longVal", longVal);
        paramsMap.put("str",strVal);
        return paramsMap;
    }

方法定义了采用数组,那么前端就需要依照一定的规则传递给这个方法,例如,输入http://localhost:8243/my/requestArray?int_val=1,2,3&long_val=4,5,6&&str_val=str1,str2,str3,可以看到需要传递数组参数时,每个参数的数组元素只需要通过逗号分隔即可。

4. 传递JSON

在前后端分离的趋势下,使用JSON已经十分普遍了。对于前端的页面和手机应用,可以通过请求后端获取JSOn数据集,这样他们就会很方便的将数据渲染到视图中。有时前端也需要较为复杂的数据到后端,为了更好的组织和提高代码的可读性,可将数据转化为JSON数据集,通过http请求体提交给后端,对此Spring MVC也提供了良好的支持。
下面通过新增角色信息来演示这个过程,先搭建一个表单,具体内容如下所示:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>新增角色</title>
    <!--加载JQuery文件-->
    <script src="https://code.jquery.com/jquery-3.2.0.js"></script>
    <script type="text/javascript">
        $(document).ready(function (){
            $("#submit").click(function () {
                var name=$("#name").val();
                var remark=$("#remark").val();
                if($.trim(name)==''){
                    alert("用户名不能为空");
                    return;
                }
                var params={
                    name : name,
                    remark : remark
                };
                $.post({
                    url : "./insert",
                    //此处需要告知传递参数类型为JSON类型,不能缺少
                    contentType : "application/json",
                    //将JSON转化为字符串传递
                    data : JSON.stringify(params),
                    //成功后的方法
                    success : function (result) {
                        if (result === null || result.id == null ){
                            alert("插入失败");
                            return;
                        }
                        alert("插入成功");
                    }

                })
            })
        })
    </script>
</head>
<body>
    <div style="margin: 20px 0"></div>
    <form id="insertForm">
        <table>
            <tr>
                <td>角色名称</td>
                <td><input id="name" name="name"></td>
            </tr>
            <tr>
                <td>角色备注</td>
                <td><input id="remark" name="remark"></td>
            </tr>
            <tr>
                <td></td>
                <td align="right"><input id="submit" name="submit" type="button" value="提交"></td>
            </tr>
        </table>
    </form>
</body>
</html>

这里定义一个简单的表单,它使用JOuery进行Ajax提交。注意到加粗的代码,他指定了提交的请求地址(url),数据(data),提交类型(contentType)和事后事件(success)。从脚本来看,这里先组织一个JSON数据集,而且把提交类型也设置为JSON类型,然后才提交到控制器。这样控制器就可以得到一个JSON数据集的请求体了。
为了打开这个表单需要在RoleController中编写一个add方法,他将返回一个字符串,映射到这个表单上,则会样就能够通过视图解析器(ViewResolver)找到他了。然后在写一个相应新增用户的请求insert方法,他将从http请求体中读出这个JSON,代码如下:

    /**
     * 注入用户服务类
     * @return
     */
    @RequestMapping("/add")
    public String add(){
        return "/role/add";
    }

    /**
     * 新增用户
     * @param sysRole 通过@RequestBody注解得到JSON参数
     * @return 回填ID后的用户信息
     */
    @RequestMapping("/insert")
    @ResponseBody
    public SysRole insert(@RequestBody SysRole sysRole){
        sysRole.setCreateBy("李登印");
        sysRole.setCreateTime(new Date());
        sysRole.setLastUpdateBy("李登印");
        sysRole.setLastUpdateTime(new Date());
        sysRole.setDelFlag((byte)0);
        sysRoleService.save(sysRole);
        return sysRole;
    }

这里通过请求add方法就可以请求到对应的表单。接着录入表单,点击提交按钮,这样通过JavaScript脚本提交JSON消息,就可以请求控制器的insert方法。这个方法的参数标注为@RequestBody,意味着他将接受前端提交的JSON请求体,而JSON请求体与SysRole类之间的属性名称是保持一致的,这样Spring MVC就会通过这层映射关系将JSON请求体转换为SysRole对象,其测试结果乳腺癌所示
在这里插入图片描述
从途中可以看出请求的add方法就可以打开视图页面,录入表单之后,启动浏览器的监控功能,然后按下提交按钮,在监控区域可以看到后端新增了用户信息,并以JSON数据集基于显示。

5. 通过URL传递参数

在一些网站中,提出了REST风格,这是参数往往通过URL进行传递。例如获取编号为1的角色,URL就要写为/role/1。这里的1代表的是角色编号(id)。Spring MVC对此也提供了良好的支持,可以通过处理器映射和注解@PathVariable的组合获取URL参数。首先通过处理器映射可以定位参数的位置和名称,而@PathVariable则通过名称来获取参数。下面演示通过URL传递参数获取用户信息的例子。在SysRoleController中加入新的方法,代码如下:

    /**
     * {...}表示占位符,还可以配置参数名称
     * @param id
     * @return
     */
    @RequestMapping("/{id}")
    @ResponseBody
    //@PathVariable 通过名称获取参数
    public SysRole get(@PathVariable("id") Long id){
        return sysRoleService.findById(id);
    }

代码中首先通过@GetMapping指定一个URL,然后用{。。。}来标明参数的位置和名称。这里指定名称为id,这样Spring MVC就会根据请求去匹配这个方法。@PathVariable配置的字符串为id,他对应URL的参数声明,这样Spring 就知道如何从URL中获取参数,于是请求http://localhost:8243/role/12,结果如下:

{"id":12,"name":"user4","remark":"shiyanb","createBy":"ldy","createTime":"2020-03-07T01:14:20.000+0000","lastUpdateTime":"2020-03-07T01:14:20.000+0000","lastUpdateBy":"ldy","delFlag":0}

6. 获取格式化参数

在一些应用中往往需要格式化数据,其中最为典型的当属日期和货币。例如在一些系统中日期格式约定为yyyy-MM-dd,金额约定为货币符号和用逗号分隔,如100完美元写作¥1,000,000,00等。同样的,Spring MVC也对此提供了良好的支持。对于日期和数字类型的转换注解进行处理,分别是@DateTimeFormat和@NumberFormat.其中@DateTimeFormat是针对日期进行格式化的,@NumberFormat则是根据数字进行格式化的。为了进行测试,新建表单,代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>格式化</title>
</head>
<body>
    <form action="./commit" method="post">
        <table>
            <tr>
                <td>日期(yyyy-MM-dd)</td>
                <td>
                    <input type="text" name="date" value="2017-08-08" />
                </td>
            </tr>
            <tr>
                <td>金额(#,###.##)</td>
                <td>
                    <input type="text" name="number" value="1,234,567,89"/>
                </td>
            </tr>
            <tr>
                <td colspan="2" align="right">
                    <input type="submit" value="提交"/>
                </td>
            </tr>
        </table>
    </form>
</body>
</html>

表单中存在两个文本框,一个日期一个金额,他们都采用了对应的格式化约定,然后再MyController中加入两个方法,代码清单如下:

    /**
     * 映射HTML页面
     * @return
     */
    @GetMapping("/format/form")
    public String showFormat(){
        return "/format/formatter";
    }

    /**
     * 获取提交参数
     * @param date
     * @param number
     * @return
     */
    @RequestMapping("/format/commit")
    @ResponseBody
    public Map<String, Object> format(
            @DateTimeFormat(iso = DateTimeFormat.ISO.DATE)Date date,
            @NumberFormat(pattern = "#,###.##") Double number
            ){
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("date", date);
        dataMap.put("number", number);
        return dataMap;
    }

这里的showFormat方法,是将请求映射到HTML表单上。format方法参数使用了@DateTimneFormat和@NumberFormat,他们配置了格式化所约定的格式,所以Spring会根据约定的格式把数据转换出来,这样就可以完成参数的转换。启动Spring Boot后,请求http://localhost:8243/my/format/form,就可以看到如下的表单
在这里插入图片描述
提交表单之后就可以看到对应的JSON数据集输出,这样就可以获取那些格式化参数了。
在Spring Boot中,日期参数的格式化也可以不使用@DateTimeFormat,而只是在配置文件application.properties中加入如下配置项即可。

spring:
		  mvc:
    		date-format: yyyy-MM-dd
发布了180 篇原创文章 · 获赞 114 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_43404791/article/details/105647261
今日推荐