SpringMVC接受请求参数、

1. 接收请求参数

1.1. 【不推荐】通过HttpServletRequest

在处理请求的方法中,添加HttpServletRequest对象作为参数,在方法体中,直接调用参数对象的getParameter()或类似功能的方法,即可获取请求参数:

@RequestMapping("handle_reg.do")

public String handleReg(

        HttpServletRequest request) {

    System.out.println("UserController.handleReg()");

    String username

        = request.getParameter("username");

    String password

        = request.getParameter("password");

    Integer age

        = Integer.valueOf(request.getParameter("age"));

    String phone

        = request.getParameter("phone");

    String email

        = request.getParameter("email");

    System.out.println("username=" + username);

    System.out.println("password=" + password);

    System.out.println("age=" + age);

    System.out.println("phone=" + phone);

    System.out.println("email=" + email);

    return null;

}

1.2. 【推荐】在处理请求的方法中声明同名参数

假设用户提交的参数是username=root,则参数名是username,当需要获取这个参数的值时,直接在处理请求的方法中声明String username即可,框架会把root值直接用于调用处理请求的方法,即String username的值就已经是root了:

@RequestMapping("handle_reg.do")

public String handleReg(

        String username, String password,

        Integer age, String phone, String email) {

    System.out.println("[2] username=" + username);

    System.out.println("[2] password=" + password);

    System.out.println("[2] age=" + (age + 1));

    System.out.println("[2] phone=" + phone);

    System.out.println("[2] email=" + email); 

    return null;

}

使用这种做法时,可以无视数据类型,例如希望age是Integer类型的,则直接声明为Integer类型即可,无须自行转换!

使用这种做法时,必须保证提交的请求参数的名称,与处理请求的方法中的参数名称是一致的!如果不一致,则处理请求的方法中,对应的参数值会是null值!

如果参数名称无法统一,后续有解决方案。

这种做法最大的缺陷是:不适用于数据项目太多的表单!否则,会导致处理请求的方法中需要添加大量的参数!

1.3. 【推荐】使用自定义类型获取多项数据

假设请求参数中包含多项数据,例如:username=admin&password=123456&age=22&phone=13900139001&email=admin%40tedu.cn,而这些数据都可以封装在同一个类型中,则直接使用该类型作为处理请求的参数即可:

@RequestMapping("handle_reg.do")

public String handleReg(User user) {

    System.out.println("[3] username=" + user.getUsername());

    System.out.println("[3] password=" + user.getPassword());

    System.out.println("[3] age=" + (1 + user.getAge()));

    System.out.println("[3] phone=" + user.getPhone());

    System.out.println("[3] email=" + user.getEmail());

    return null;

}

这种做法,适用于请求参数较多的场合!

注意:如果请求参数的参数名称,与类中的属性名称不一致,则类对象中对应的属性值为null!

注意:这种做法可以与前序介绍的第2种做法组合来使用!

1.4. 小结

关于获取请求参数,首先,并不推荐使用HttpServletRequest,主要原因是相对比较原始,编码比较繁琐!而声明同名参数,或声明对象,都是推荐的做法,至于使用哪一种,可以根据参数的数量及数据是否适合被封装到同一个类中,综合评定,并且,这2种做法可以组合使用!

2. 控制器的响应

2.1. 常见的响应方式

【转发】在转发过程中,客户端只发出过1次请求!在浏览器的地址栏中,也只会显示第1次请求的路径!转发是在服务器内部完成的,可以传递数据!

【重定向】当服务器响应重定向时,客户端会发出第2次请求!最终,在浏览器的地址栏中,会显示第2次请求的路径!由于是2次不同的请求,基于Http协议是无状态协议,没有经过特殊处理(Session/Cookie/数据库存取……)的数据是无法在2次请求之间传递的!

2.2. 常见的响应码

被服务器接收到的每个请求,在最终响应时,服务器端都会给出一个响应码,例如200、404等。通常:

2xx:正确的响应,例如200、206等……

3xx:重定向,例如302、301等……

4xx:请求错误,例如请求的资源不存在,或者请求类型错误、或者请求参数错误等等,例如400、404、405、406等……

5xx:服务器内部错误,通常可能是出现某种异常,例如500等……

3. 转发数据

3.1. 【不推荐】将转发的数据封装在HttpServletRequest对象中

可以为处理请求的方法添加HttpServletRequest request参数,当需要转发数据时,将数据封装在request中即可,后续也不需要显式的执行转发,在SpringMVC的控制器中,默认的响应方式就是转发。

@RequestMapping("handle_reg.do")

public String handleReg(User user,

        HttpServletRequest request) {

    // 假定输入的用户名已经被占用

    // 提示:您输入的用户名XXX已经被占用

    request.setAttribute("msg",

        "您输入的用户名" + user.getUsername() + "已经被占用!");

    // 返回视图名,也可以理解为文件的文件名

    return "error"; // 页面:/WEB-INF/error.jsp

}

3.2. 【不推荐】使用ModelAndView

可以将处理请求的方法的返回值设置为ModelAndView类型,该类型的常用构造方法有:

ModelAndView()

ModelAndView(String viewName)

ModelAndView(String viewName, Map<String, ?> model)

当需要转发数据时,可以使用以上3种中的最后一种:

@RequestMapping("handle_reg.do")

public ModelAndView handleReg(String username) {

    String viewName = "error";

    Map<String, Object> model

        = new HashMap<String, Object>();

    model.put("msg",

            "[2] 您输入的用户名" + username + "已经被占用!");

    ModelAndView mav

        = new ModelAndView(viewName, model);

    return mav;

}

由于这种方式使用相对比较复杂,所以,一般不推荐使用这种做法!

3.3. 【推荐】使用ModelMap封装需要转发的数据

使用ModelMap的流程与使用HttpServletRequest完全相同,即:方法的返回值依然使用String类型,在方法中声明该参数,然后在方法体中直接封装数据,最后,返回视图名:

@RequestMapping("handle_reg.do")

public String handleReg(String username,

        ModelMap modelMap) {

    modelMap.addAttribute("msg",

        "[3] 您输入的用户名" + username + "已经被占用!");

    return "error";

}

3.4. 小结

在SpringMVC中,转发数据共有3种做法,第1种使用HttpServletRequest的做法简单直接,但是,并不推荐这样处理,主要是因为框架已经帮我们处理了request需要执行的任务,而我们在编写代码时应该尽量不干预框架的处理过程,第2种使用ModelAndView,是框架的核心处理方式,但是,因为使用方式过于麻烦,所以,也不推荐这样使用,第3种使用ModelMap,使用简洁,推荐使用。

3.5. 附:重定向

在SpringMVC中,当需要重定向时,首先,应该保证处理请求的方法的返回值是String类型(与转发一样),然后,返回值使用redirect:作为前缀即可,例如:

@RequestMapping("handle_reg.do")

public String handleReg() {

    // 假设注册成功,需要登录

    return "redirect:login.do";

}

需要注意的是:在redirect:右侧的不是视图名,而是重定向的目标的路径,可以是绝对路径,也可以是相对路径。

当处理的请求的返回值类型是String时,如果返回值使用redirect:作为前缀,是重定向,否则,是转发!

4. 关于@RequestMapping注解

通过配置@RequestMapping,可以绑定请求路径与处理请求的方法,例如:

@RequestMapping("login.do")

public String showLogin() { ...

即:通过以上配置,当接收到login.do请求时,SpringMVC会自动调用showLogin()方法。

除了在方法之前添加该注解以外,该注解还可以添加在控制器类的声明之前,例如:

@RequestMapping("user")

@Controller

public class UserControler { ...

当方法之前添加了该注解之后,方法内配置的所有请求路径,在最终访问时都必须添加user路径,例如:http://localhost:8080/SPRINGMVC-02-USER/user/reg.do。

通常,推荐在类之前也添加该注解,方便管理路径,例如在某个新闻管理的应用中,可能存在news_list.do、news_info.do的请求,而在这个应用中,也会有用户数据,就存在user_list.do、user_info.do,可以发现,为了保证请求路径是唯一的,都需要在路径之前添加xxx_作为前缀,这样的管理方式是非常不方便的,在类之前添加@RequestMapping注解就可以很好的解决这个问题,每个路径之前根本就不需要配置前缀字符,也不会发生冲突!

在@RequestMapping的使用过程中,路径可以使用/作为第1个字符,也可以不需要这个字符,例如:

/user      /login.do

user        login.do

/user      login.do

user        /login.do

以上4种配置都是正确的!通常,推荐使用/作为第1个字符,即以上第1种方式!

除了配置请求路径以外,使用@RequestMapping还可以限制请求方式,即某个路径可以设置为只允许POST请求,而不接收GET请求!

【GET】会将请求的参数与值体现在URL中;请求的参数与值会受到URL长度限制,不适用于传递大量的数据;

【POST】请求的参数与值不会体现在URL中;可以传递大量的数据;

【选取】请求的参数与值涉及隐私(例如密码)则必须使用POST;数据量可能较大时必须使用POST;需要共享URL且其中包含参数时必须使用GET;支持页面刷新必须使用GET。

【复杂度】如果要发出POST请求,只能通过<form>中的<input type="submit" />或<button />,或者通过JS技术,否则,在Web领域无法发出POST请求,而这2种方式也都可以用于发出GET请求,除此以外,直接在浏览器中输入某个URL发出的也是GET请求,总的来说,发GET请求要简单得多。

【小结】参考以上“选取”原则,选择请求方式,如果两者均可,则使用GET即可。

在@RequestMapping中配置method属性可以限制请求类型:

@RequestMapping(value="handle_reg.do",

        method=RequestMethod.POST)

public String handleReg() {

例如以上代码限制了handle_reg.do必须通过POST方式来请求,如果使用GET方式,则会返回405错误!

只有需要限定请求方式时,才需要显式的配置value="handlereg.do",否则,直接将"handlereg.do"配置在注解中即可!

小结:关于@RequestMapping注解,主要作用是配置请求路径,推荐在控制器类和处理请求的方法之前都添加该注解,类之前的注解是用于配置请求路径中的层次,方法之前的注解是用于配置请求的资源,关于路径的配置是该属性的value属性,如果只配置请求路径,可以不用显式的声明这是配置value属性,而是直接把值写出来即可,例如不需要写成@RequestMapping(values="login.do"),而可以直接写成@RequestMapping("login.do"),在配置路径时,推荐使用/作为第1个字符,例如@RequestMapping("/login.do"),如果还需要限制请求方式,则必须显式的声明路径为value属性的值,并且添加配置method属性,例如:@RequestMapping(value="handle_reg.do", method=RequestMethod.POST)。

5. 关于@RequestParam注解

使用@RequestParam注解,可以解决请求参数名称与处理请求的方法的参数名称不一致的问题,例如:

public String handleLogin(

    @RequestParam("name") String username,

        String password) { ...

则请求参数的名称是name,而处理请求的方法中的参数名称却是username,这是可以正常运行的!

一旦使用了@RequestParam注解,默认情况下,参数就是必须的!例如配置了@RequestParam("passwd") String password后,如果请求中并不存在名为passwd的参数,则会出现400错误:

HTTP Status 400 - Required String parameter 'passwd' is not present

没有提交名为passwd的参数,与提交了空值,是两码事!即:如果提交了passwd参数却没有值(例如输入框中没有输入值),在服务器将得到空字符串(""),程序并不会出现错误!如果根本就没有提交名为passwd的参数,则会导致400错误!

如果使用了@RequestParam注解,却又不想设置为必须提交该参数,可以:

@RequestParam(value="name", required=false)

则将根据name去接收参数,如果有值,会正确接收,如果没有(没有提交该名称的参数),则会是null值!

当required=false时,意味着可以不必提交该参数,还可以多配置一项defaultValue属性(The default value to use as a fallback when the request parameter value is not provided or empty. Supplying a default value implicitly sets required() to false.),表示如果请求中没有提交该参数,则默认值是多少!例如:

@RequestParam(value="passwd", required=false, defaultValue="888999") String password

以上代码表示:希望请求中包含名为passwd的参数,如果有,则值用于方法的String password的参数,如果没有,也不是必须要提供(required=false),并且使用"888999"作为默认值(defaultValue="888999"),即:在这种情况下,String password的值是"888999"。

小结:@RequestParam注解是用于处理请求的方法中的参数之前,可以配置3项属性,分别是value表示请求参数名称,required表示请求中是否必须包含该参数,defaultValue表示参数的默认值,当有以上任何一种需求时,都需要配置该注解,即:请求参数名称与处理请求的方法的参数名称不一致;强制必须提交某个参数;为某个参数配置默认值。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,123评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,031评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,723评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,357评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,412评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,760评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,904评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,672评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,118评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,456评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,599评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,264评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,857评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,731评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,956评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,286评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,465评论 2 348

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,628评论 18 139
  • Spring Web MVC Spring Web MVC 是包含在 Spring 框架中的 Web 框架,建立于...
    Hsinwong阅读 22,351评论 1 92
  • 你费力讨好别人的样子并不漂亮 是的,一点都不漂亮! 前段时间,同事们相约带孩子一起旅游,孩子们特别高兴,我们也是相...
    温而泽润阅读 775评论 0 0
  • 由于自己工作的原因,经常接触|非常多的“自由职业者”,开始并不了解自由职业者到底可以做些什么?但随着自己接触...
    林奎阅读 235评论 0 1
  • 每个细胞,器官都有他的意识。次人格一般有十几、二十几个,在好多特定场景中出现,怎么出来的不知道,次人格特别想被我们...
    盛蓝阅读 732评论 0 0