美文网首页ssm框架Java&JAVA EE
SpringMVC映射的前端后台数据交互总结

SpringMVC映射的前端后台数据交互总结

作者: 行径行 | 来源:发表于2017-11-19 12:12 被阅读232次

    • tags:springmvc
    • categories:笔记
    • date: 2016-08-14 22:19:31

    由于最近在开发项目模块时候,总会涉及到前端后台数据交互过程。其实我们在处理程序时候,无论是框架,实现和逻辑都是以数据为基础的。并且,开发的又是web项目,那当然会涉及到前端和后台的交互了。总而言之,弄清楚数据的流动过程至关重要。我们需要处理的也是数据,所以,若是把数据流的产生,到中间处理,到最后的展示,也可以联系MVC来理解,这个过程都掌控好的时候,开发效率和思路也会清晰很多。所以,来总结总结springmvc中requestmapping参数的时候,和一些前端后端表单交互方式的总结。

    springmvc中requestmapping如何使用?

    由于最近在使用springmvc,所以将一些基础内容总结总结,特别是requestmapping这个注解参数。它是我们映射参数的处理器,将处理和路由不同的http请求和参数映射。spring这个轮子使用起来还是挺方便的,也很强大,拓展伸缩力也挺灵活,对我们日常开发有事半功倍效果。并且,现在的项目开发为了规范代码风格和"约定大于配置"的理念也在不断影响我们,很多公司的后台接口都是按照RESTFUL风格来设计与实现。

    因为我们的web项目都是基于HTTP协议的,在应用程上数据的点对点的传输和请求,无外乎就是HTTP的那几种请求类型,如GET,POST,PUT等等。所以,springmvc也对REST风格开发中这几种HTTP请求方法有定义与实现。因为在B/S架构上的软件大多都是离不开http协议的。所以,在细化到一个java中的一个controller类,该类就相当于一个很大的停车场吧(是在想不到什么好的场景了),将轿车,卡车,赛车等几种不同类型的车分别映射成http的GET,POST,PUT请求。若是将汽车停车这个过程比喻成一个http请求的话:
    我们车主就是发送请求端,停车场就是服务端。
    车的类型式属于轿车还是卡车,还是赛车就相当于是什么类型的请求了:假设我们是开着轿车去XX停车场停车(这就是一个http请求)。轿车对应GET请求,然后将车开到轿车停车区域,在结合轿车牌子,汽车车型(请求参数),找到了停车位(相当于找到了某个controller类的处理方法method)。
    将车子停在具体车位后,停车位管理员给予停车卡,车主拿到卡就可以走了(就相当于请求处理完成,返回数据了)。

    我们就可以将requestMapping这个注解参数比喻成停车场管理员,他职责就是结合你的车子种类(Htpp请求类型),车型,大小,牌子(请求参数)等等,决定停车在那一个停车区位置(处理方法),最后停车完成,也就相当于处理完成了。所以,requestMapping的作用是很大的。下面来看看该注解参数的具体用法:

    @RequestMapping: 是用来处理一个请求地址映射的注解,可用于类或者方法上。用于类上:表示类中的所有方法请求都是以该参数value值中内容作为父路径;用于方法上则是映射到具体的URI参数了。

    我就把RequestMapping的主要六个注解来分别看看,并大致将它们分成了3类说明:

    • Value,method:
      value: 指定请求的实际地址,也就是想http uri中的请求参数是什么内容,才能跳入调用这个方法。
      method: 指定HTTP请求的method类型:GET,POST,PUT,DELETE等。

    eg: 我若是想让以GET方式请求的http请求,并且它uri中包含test/getValue.do结尾,调用getValue方法,那么可以这样定义:

    @RequestMapping(value="/test/getValue.do",method=RequestMethod.GET)
    public String getValue(){...}
    
    • consumes,produces:
      consumes: 指定处理http请求的提交内容类型(也就是HTTP头中的Content-Type参数),eg:application/json,text/html;也就是说,若是希望方法method处理的是json类型数据,那么就要求客户端提交过来到这个方法的请求参数是json类型。
      produces: 指定该方法处理后返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回。这句话意思就是,若是客户端可以接收text/html;application/json等类型的数据类型,那么我服务器端才在该函数处理完数据后,以这些格式将数据封装返回浏览器。

    • params,headers:
      params: 指定request请求中必须包含某些参数值,才让该方法处理。
      headers: 指定request中必须包含某些指定的header值,才让该方法处理。

    下面来个具体点的例子:
    1.value,method:就拿一个用户类的增删改查就行了,也就对应了http的POST,DELETE,PUT,GET方法了。

    
    @Controller
    @RequestMapping("/user")    //下面方法若是想调用,uri中都必须在/user/...后
    public class UserController {
        @Autowired
        private UserService userService;
    
        /*
        * 添加用户。
        * POST类型的../user/add.do请求uri调用该方法。
        */
        @RequestMapping(value = "/add.do",method=RequestMethod.POST)  
        public String addUser(HttpServletRequest request,HttpServletResponse response){
            int iRetVal = 0;
            String nickname = request.getParameter("nickname");
            String state = request.getParameter("state");
            User user = new User();
            user.setNickname(nickname);
            user.setState(Integer.valueOf(state));
            iRetVal = userService.insertUser(user);
            return ResponseUtil.ajax(String.valueOf(iRetVal).toLowerCase(),response,"text/html");
        }
        
        /*
        * 根据id查询用户
        * GET类型的 ../user/sid/10 请求调用该方法。
        * 类似这种 /{param1}/{param2}..的uri请求,那么就可以使用@PathVariables参数对路径参数进行映射封装。
        */
        @RequestMapping(value = "/sid/{sid}",method=RequestMethod.GET)  
        public ModelAndView getUserById(@PathVariable String sid){ //sid参数对应方法上的路径参数{sid}
            ModelAndView mv = new ModelAndView("stulist");  //跳转到stulist.jsp
            User user = userService.getUserById(sid);
            mv.addObject("user",user);
            return mv;
        }
    
        /*
        * 根据id删除用户
        * GET类型的 ../user/sid/10 请求调用该方法。
        * 类似这种 /{param1}/{param2}..的uri请求,那么就可以使用@PathVariables参数对路径参数进行映射封装。
        */
        @RequestMapping(value = "/sid/{sid}",method=RequestMethod.DELETE)  
        public ModelAndView DeleteUserById(@PathVariable String sid){ //sid参数对应方法上的路径参数{sid}
            ModelAndView mv = new ModelAndView("stulist");  //跳转到stulist.jsp
            int ret = userService.DeleteUserById(sid);
            mv.addObject("ret",ret);
            return mv;
        }
    
        //可以看见上述的getUserById和DeleteUserById对应的请求URI都一样,但是是如何区别调用那个方法呢?那就是根据HTTP的method类型。
        //修改方法省略,大致相同,就是method=RequestMethod.PUT而已。
    }
    
    

    2.consumes、produces:就写两个方法分别对应两个参数即可。
    consumes:服务器端要求,在uri和http的method都匹配的情况下,只是处理request请求头中Content-Type="application/json"类型的请求。

    //下面这个方法只是会处理POST的http类型,并且提交的数据是json类型:{"name":"","age":"",...}
    @RequestMapping(value="/addUser",method=RequestMethod.POST,consumes="application/json")
    public String addUser(@RequestBody User user){
      //add User
    }
    

    produces: 服务器端该方法仅处理request请求中Accept头中包含了"application/json"的请求,同时暗示了返回的内容类型为application/json;可以结合@ResponseBody参数一起使用。

    @RequestMapping(value="/getAllUsers",method=RequestMethod.GET,produces="application/json")
    public String getAllUsers(){
        //...
    }
    

    3.params、headers: 也是列举对应的方法来说明。
    params: 若是我们有这样一个需求,某个方法只是处理uri中包含某个指定关键字参数的请求。若是只是想处理uri请求中参数包含kparam=arden的请求。

    //eg: http:.../getUser?kparam=arden
    @RequestMapping(value="/getUser",method=RequestMethod.GET,params="kparam=arden")
    public String getUser(){
        //...
    }
    

    headers: 若是我们有需求,该方法仅仅处理request的请求头中指定"refer"为"www.whoshell.com"的请求。

    @RequestMapping(value="/getWebInfo",method=RequestMethod.GET,headers="Refer=http://www.whoshell.com")
    public String getWebInfo(){
        //...
    }
    

    requestMapping如何绑定request和response参数数据?

    在常规的http协议的request请求格式如下:

    GET /2017/03/09/classLoader-how HTTP/1.1    [请求行:请求类型 请求资源uri http协议版本]
    Accept: */*       [请求头: key = value]
    Accept-Language: zh-cn
    Accept-Encoding: gzip, deflate
    User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;3.5.21022)....
    Host: www.whoshell.com
    Connection: Keep-Alive
    [空行]
    xxxxxx [主体Body]
    

    那么,springmvc中就可以针对request请求的不同部分内容,进行参数绑定。可以大致分为四类:

    • 处理request的uri部分(不包含queryString部分(?key=value) eg:http:{uri}/foo/bar)注解: @PathVariable
    • 处理requeset header部分(request请求头参数)的注解: @RequestHeader @CookieValue
    • 处理request body部分注解: @RequestParam @RequestBody
    • 处理attribute类型的注解:@SessionAttributes @ModelAttribute

    然后就来分别说说针对request请求的不同部分的注解是如何使用的,如何绑定数据的:
    1.@PathVariable:
    当使用@RequestMapping URI的template样式映射参数时候,如http:{uri}/user/{uid},这时候可以通过@PathVariable注解将uri中的uid参数绑定到方法的参数上。
    (方法上的uri中的{sid}参数将会映射传递到方法的sid参数上。若是方法参数名称和uri中传递的{param}名称不一致,需要在方法参数旁显式指定名称。)

        @RequestMapping(value = "/sid/{sid}",method=RequestMethod.DELETE)  
        public ModelAndView DeleteUserById(@PathVariable String sid){ //sid参数对应方法上的路径参数{sid}
            ModelAndView mv = new ModelAndView("stulist");  //跳转到stulist.jsp
            int ret = userService.DeleteUserById(sid);
            mv.addObject("ret",ret);
            return mv;
        }
       //uri/{param}中param名称与方法变量名字不同,需要@PathVariable()显示指定
       @RequestMapping(value="/sid/{userId}",method=RequesetMethod.DELETE)
       public ModelAndView DeleteUserById(@PathVariable("userId") String sid){...}
    

    2.@RequestHeader,@CookieValue:
    @RequestHeader注解,可以把Request请求header部分的值绑定到方法的参数上。
    例如假设我们的一个request请求头为以下内容:

    Host: www.cnblogs.com
    Connection: keep-alive
    Cache-Control: max-age=0
    Upgrade-Insecure-Requests: 1
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
    Referer: https://www.baidu.com/link?url=vMwqr_1CInBYSsvCXnoPrwOFxPvxdChHmN9XWPp7C1Do5MjbnJN8e8WP6VCPjsW5w-edqnKJaCNJPN2sR20eNOb6d73O0ZaFM9Kwe-GRVtK&wd=&eqid=8a738c1d00002ce20000000658c8c3ca
    Accept-Encoding: gzip, deflate, sdch
    Accept-Language: zh-CN,zh;q=0.8
    Cookie: CNZZDATA1260386081=1660805767-1486222861-https%253A%252F%252Fwww.baidu.com%252F%7C1486222861; __utma=226521935.140421385.1488358381.1488899945.1488899945.1; __utmz=226521935.1488899945.1.1.utmcsr=baidu|utmccn=(organic)|utmcmd=organic; CNZZDATA1259029673=860036098-1489063915-%7C1489063915;
    

    那如果服务器端代码要使用request请求头中某些内容,那么我们就可以使用@RequestHeader参数来映射参数:
    下面的方法参数,分别获取请求头中,客户端接收的编码(Accept-Encoding)绑定到encoding参数上,和接收的内容格式(Accept)绑定到accept参数上。

    @RequesetMapping(value="..")
    public void getRequestHeaderInfo(@RequestHeader("Accept-Encoding") String encoding, 
                                     @RequestHeader("Accept") String accept){
    //...
    }
    

    @CookieValue注解,顾名思义,就是将客户端发送的request请求中cookie拿到,绑定到方法参数上。
    我们还是根据上面那个request请求头,我们可以看到最后一行请求头中有:Cookie:..的内容,若是想直接拿到该字段内容,那么可以使用@CookieValue注解来实现数据绑定。

    @RequesetMapping(value="..")
    public void getRequestCookieInfo(@CookieValue("Cookie") String cookie){ //绑定cookie内容到cookie参数
    //...
    }
    

    3.@RequestParam,@RequestBody:
    上面我们在获取request请求资源uri路径,请求头内容后,还有一个重要的request格式中区域就是请求体body了。那么这两个参数就是用于处理这部分内容的。

    @RequestParam注解,通过以下几点来说明:
    (1) 常常用来处理简单类型的数据绑定。什么是简单类型,简单的说,就是在服务器端可以通过request.getParameter("key")方法获取的参数的类型。通常这类的参数在Get请求中是以uri?key=value样式体现的,也就是queryString的值。也能获取POST请求中请求体body data中的值。也就是将一些key=value参数放置在request请求体中。

    (2) 用来处理Content-Type: 为application/x-www-form-urlencoded表单提交的编码内容。

    (3) 该注解有两个属性:value,required。value用来指定传入值的名称,required用于指示参数是否必须存在并绑定。

    //url: http://.../getUser?uid=1
    @RequestMapping(method = RequestMethod.GET)  
    public String doSomething(@RequestParam("uid") int uid, ModelMap model) {//url中queryString参数uid绑定到方法参数uid中。  
        //...
    }
    

    @RequestBody注解:通常用来处理非表单提交(Content-Type={application/json;application/xml})中的post data body内容。

    4.@SessionAttributes,@ModelAttribute:
    @SessionAttributes注解是用来绑定httpSession的attribute对象的值,方便在方法中参数映射并使用。该注解有value,types两个属性,可以通过名字和类型来指定要使用的attribute对象。

    那么为什么要使用这个注解呢?能解决什么问题?这个与spring中的ModelMap有关。因为modelMap中的属性作用域是request级别,也就是说,当本次request结束后,modelMap中的所有属性都会被销毁,那么就造成一个问题?若想在多个request中共享该对象,如何实现?那就可以把对象放置到session域级别中。就是通过@SessionAttributes来完成这个需求的。

    eg:通过@SessionAttributes注解将该request请求域中的ModelMap中的user对象属性放置到session中。在后面jsp视图中我们可以使用常规session操作得到user属性(session.getAttriute("user")):

    @Controller  
    @RequestMapping("/editUser.do")  
    @SessionAttributes(value="user",types={user.class})  
    public class EditUserForm {  
        // ...  
    }  
    

    关于该属性的使用形式还有以下几种:
    (1)字符串数组指定多个属性。@SessionAttributes({"attr1","attr2"})
    (2)也能通过types指定每个value的属性:
    @SessionAttributes(types={User.class})
    @SessionAttributes(types={User.class,Deptment.class},value={"atrr1","attr2"})

    @ModelAttribute注解有两个用法,一个是用于方法上,一个是用于参数上:
    方法上: 通常是用来处理@RequestMapping之前,为请求绑定需要从后台查询的model。
    参数上: 用来通过名称对应,把相应的名称的值绑定到注解的参数bean上,该bean的来源有:
    A. @SessionAttributes配置中的attribute对象。
    B. @ModelAttribute用于方法上时候指定的model对象。
    C. 若是上述情况都没有,new一个需要绑定的bean对象,然后把request中按照同名方式把值绑定到bean。

    在参数上使用该注解的例子:可以看到@ModelAttribute("user")中有user参数与@SessionAttribute("user")中的对象名称一致,那么就会自动将user属性对象注入到ModelMap对象,就可以直接使用该user对象了。

    @RequestMapping(value="/users/{uid}/edit", method = RequestMethod.POST)  
    public String processSubmit(@ModelAttribute("user") User user) {  
         //...
    }  
    

    关于@ModelAttribute属性中对象如何查找,按照如下顺序:先查询@SessionAttribute上有无绑定的同名对象,若是没有则在查询定义在方法上的@ModelAttribute是否绑定有同名对象,最后则是在uri按照属性名称映射查找。

    前端表单提交形式有那些?

    在讲述完spring对request请求数据封装和绑定了,就再看看前端是如何将数据传递到后台的?有那种形式,如何将数据传递到后台?(以后有好方式更新收集.)

    • 通过type=submit提交:
      一般通常的表单提交通过type=subimt来实现,结合input type="submit"或者想SUI这种UI组件中button type="submit"实现按钮提交。通过点击该标签按钮提交表单数据调到action指定uri。
      eg:
        //sui form提交
        <form role="form" id="myform" name="myform" class="sui-form form-horizontal" 
            method="post" action="<%=basePath%>test/form1.do">
            <div class="form-group">
                <label for="name">名称</label> <input type="text" class="form-control"
                    id="name" name="name" placeholder="请输入名称">
            </div>
            <div class="form-group">
                <p class="help-block">这里是块级帮助文本的实例。</p>
            </div>
            <div class="checkbox">
                <label> <input type="checkbox" name="check"> 请打勾 </label>
            </div>
            <button type="submit" class="btn btn-success">提交</button>
        </form>
    
       //常规form input提交
       <form action="/url.do" method="post">
         <input type="text" name="name"/>
         <input type="submit" value="提交">
       </form> 
    
    • 通过js提交form表单:
      还可以使用js来触发表单提交,通过button,超链接等的点击触发事件,在事件中调用js方法,在方法中调用submit提交表单数据。通过js的方法,那挺多前端js框架都能如extjs,jquery,还有原生js等都能实现啦,下面看看这方式如何写:
    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
    <%
    String path = request.getContextPath();
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
    %>
    <!DOCTYPE html>
    <html>
      <head>
        
        <title>back_front</title>
        <meta name="viewport" content="initial-scale=1, maximum-scale=1">
        <jsp:include page="../common/jsp/bootstrap-css.jsp"/> 
        <jsp:include page="../common/jsp/bootstrap-js.jsp"/>
    
       <script type="text/javascript">
        function bsubmit(){
            var form = document.forms[0];
            form.action = "<%=basePath%>test/form1.do";
            form.method = "post";
            form.submit();
        }
       //若是form表单的基础信息都填写完成,想直接提交,那么可以使用:
       // js: document.getElementById("myform").submit();
       //jquery: $("#myform").submit();
    
       </script>
      </head>
      
      <body>
        <form role="form" id="myform" name="myform" method="post" action="<%=basePath%>test/form1_1.do">
            <div class="form-group">
                <label for="name">名称</label> <input type="text" class="form-control"
                    id="name" name="name" placeholder="请输入名称">
            </div>
            <div class="form-group">
                <p class="help-block">这里是块级帮助文本的实例。</p>
            </div>
            <div class="checkbox">
                <label> <input type="checkbox" name="check"> 请打勾 </label>
            </div>
            <input type="button" value="提交" onclick="bsubmit();"/>  //通过调用bsubmit()js方法提交表单。
            <!-- <a href="javascript:void(0);" onclick="bsubmit();" >提交</a>-->
            <!-- <button type="button" onclick="bsubmit();">提交</button>-->
        </form>
    
      <jsp:include page="../common/jsp/sui-js.jsp"/>
      </body>
    </html>
    
    • ajax异步提交表单:
      其实,ajax提交与js提交使用方式大致相同,只是ajax是异步的,用于处理一些对前端交互不阻塞的操作,异步调用后台接口进行服务器端交互,得到信息,返回前端。ajax提交,也是可以通过原生js或者jquery来实现,这里看看在点击提交按钮后,使用jquery简单实现ajax提交:
    $(function() {
            //使用jquery得到id="submit"的按钮组件,绑定点击事件,发ajax异步请求。
            $("#submit").click(function() {
                 $.ajax({
                 type: "POST",
                 url: "/url.do",
                 data: params,
                 dataType : "json",
                 success: function(respMsg){
          }
       });
            });
    
        });
    </script>
    
    <body>
        <form id="form"  method="post">
            <button type="button" name="submit" id="submit"/>
        </form>
    </body>
    

    当前总结,就是这几种,不同的前端框架与UI其实对于表单提交都差不多这几种方式,日后还有不同在更新啦。

    前端后端如何连接传递数据?

    在了解完springmvc的注解参数获取封装数据,和前端的数据提交后,接下来结合上述的前端表单提交数据,后台如何获取。
    springmvc中封装前端数据大致有以下几种:

    • 直接将表单的name参数写在Controller类的方法参数中。:(注意要同名才能映射成功)
    <form action="/url.do" method="post">
     userName:<input name="userName" type="text"/><br>
     password:<input name="password" type="password"/><br>
     <input type="submit" value="submit"/>
    </from>
    
    //后台controller,addUser方法的userName,password参数名称与表单的name同名才能映射得到数据
        @RequestMapping(value = "/url.do",method=RequestMethod.POST)  
        public String addUser(String userName,String password){
            //..add user
            return "userlist";
        }
    
    
    • 后台通过request来获取数据。同样使用上面的表单。:
      通过request.getParameter("name")就可以得到前端数据。
        @RequestMapping(value = "/url.do",method=RequestMethod.POST)  
        public String addUser(HttpServletRequest request){
            String userName = request.getParameter("userName");
            String password = request.getParameter("password");
            //...
            return "userlist";
        }
    
    
    • 封装前端数据到bean中。:
      通过这种方式,在controller的方法中,参数为form表单属性对应的bean。表单的每个提交属性name都要与bean的字段相同,这样在提交的时候,后台会自动调用bean的setXX方法将表单值设置到bean中,这样我们就可以直接对bean操作了。
    public class User{
      private String userName;
      private String password;
      
      //getter
      public void setUserName(String userName){
        this.userName = userName;
      }
      public void setPassword(String password){
        this.password = password;
      }
    }
    
    
    //controller中,就可以通过User user对象封装form表单数据
        @RequestMapping(value = "/url.do",method=RequestMethod.POST)  
        public String addUser(User user){
            String userName = user.getUserName();
            String password = user.getPassword();
            //...
            return "userlist";
        }
    

    另外,除了(1)中的那种常规形式表单提交外,在前端还可以将数据封装成json格式数据提交,也可以通过jquery中的表单序列化($("#myForm").serializeArray())的方法形式提交数据,但是后台获取表单数据也就是这几种形式了。

    上述仅仅是将本人使用过的场景模式中的流程总计出来,当然必然还有其他方式的前后端交互,这里仅供参考啦嘿嘿....


    参考:
    form表单提交方式
    SpringMVC接收页面表单参数

    相关文章

      网友评论

      本文标题:SpringMVC映射的前端后台数据交互总结

      本文链接:https://www.haomeiwen.com/subject/mxbuvxtx.html