zoukankan      html  css  js  c++  java
  • 前后端交互之封装Ajax+SpringMVC源码分析

    为什么需要封装呢?因为用的多,我想将其封装成函数,当我想用它时,只需将那个函数对应的js文件引入即可,而不要重复写很多相同代码,利于开发效率的提高。

    无论是$.ajax或$.post、$.get等,在开发中是经常用到的。再比如一些前端框架,例如easyui、ext.js等,ajax也是封装的。

    编程的世界,封装无处不在。

    具体js代码如下:

    /**
     * 增删改通用ajax请求
     * @param type
     * @param url
     * @param datatype
     * @param contentType
     * @param data
     * @returns
     */
    function global_ajax_method(type, url, datatype,contentType, data) { //封装ajax的一些常用参数  //data数据可以为空
        $.ajax({
    
            type: type,
            url: url,
            dataType: datatype,
            contentType:contentType,
            data: JSON.stringify(data),
            error: function (data) {
                //请求失败时被调用的函数 
                alert("传输失败:" + data);
            },
            success: function (data) {
                if(data.returnCode=="000000"){
                    alert(data.returnMsg);
                }else if(data.returnCode="111111"){
                    alert(data.returnMsg);
                }else{
                    alert("其他异常");
                }
                  
            }
        });
    }

    ajax比较常用的要么是$.ajax或者$.post,从名字看就可以知道,$.post肯定只能支持POST请求,非POST请求肯定是不行的。

    而$.ajax同时兼$.post和$.get的特性,只需将type定义为POST或GET便可知其是什么请求。

    上面封装的是我目前项目在用的,就是这一个便可以将我前后端增删改异步交互全部做到。

    至于查询的话,查询的话,通常需要遍历数据,和生成一些js或者html、css等,当然,那是因为业务需要。

    查询的话,返回较多,通常为了灵活性暂不做封装。

    当然也可以封装,不过目前对于我公司项目而言,没有多大的需要。

    下面是示例:

    common.js

    /**
     * 全局js文件
     * 说明:公共复用的js统一放在这里
     */
    
    //项目名
    var path='/test';
    
    /**
     * 全局函数调用路径(资源管理系统需要用到的,接口路径统一写在这)
     * 
     */
    var ZL=ZL||{
        url:function(){
            var base=path;
            return {
                base:base,
                api:{
                     sys_User_Role_Insert:base+'/UserRole/insert',
                     sys_User_Role_Delete:base+'/UserRole/delete'
                }
            }
        }()                    
    }
    
    /**
     * 增删改通用ajax请求
     * @param type
     * @param url
     * @param datatype
     * @param contentType
     * @param data
     * @returns
     */
    function global_ajax_method(type, url, datatype,contentType, data) { //封装ajax的一些常用参数  //data数据可以为空
        $.ajax({
    
            type: type,
            url: url,
            dataType: datatype,
            contentType:contentType,
            data: JSON.stringify(data),
            error: function (data) {
                //请求失败时被调用的函数 
                alert("传输失败:" + data);
            },
            success: function (data) {
                if(data.returnCode=="000000"){
                    alert(data.returnMsg);
                }else if(data.returnCode="111111"){
                    alert(data.returnMsg);
                }else{
                    alert("其他异常");
                }
                  
            }
        });
    }

    test.html

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>test</title>
    <script type="text/javascript" src="../js/jquery-1.8.0.min.js"></script>
    <script type="text/javascript" src="../js/common.js"></script>
    <script>
    alert(ZL.url.api.sys_User_Role_Delete);
    
    $(function(){
        var data= "{'userCode':'3','roleCode':'3'}";
        var json = eval("("+data+")");
        ajax_all_Filed("POST", ZL.url.api.sys_User_Role_Insert,"json","application/json;charset=utf-8",json);//调用函数
    
        
    });
    
    
    </script>
    </head>
    <body>
    
    
    
    </body>
    </html>

    Controller代码:

    @PostMapping(value="/insert",produces="application/json;charset=utf-8")
        @ApiOperation(value="添加用户-角色信息",notes="测试")
        public JSONObject insert(@RequestBody SysUserRole sysUserRole) {
            JSONObject json = new JSONObject();
            boolean isAdd = sys.insert(sysUserRole);
            if(isAdd) {
                json.put("returnCode", "000000");
                json.put("returnMsg", "success");
            }else {
                json.put("returnCode", "111111");
                json.put("returnMsg", "error");
            }
            return json;
            
        }

    关于Controller提一下@RequestBody

    源码如下:

    /*
     * Copyright 2002-2015 the original author or authors.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package org.springframework.web.bind.annotation;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    import org.springframework.http.converter.HttpMessageConverter;
    
    /**
     * Annotation indicating a method parameter should be bound to the body of the web request.
     * The body of the request is passed through an {@link HttpMessageConverter} to resolve the
     * method argument depending on the content type of the request. Optionally, automatic
     * validation can be applied by annotating the argument with {@code @Valid}.
     *
     * <p>Supported for annotated handler methods in Servlet environments.
     *
     * @author Arjen Poutsma
     * @since 3.0
     * @see RequestHeader
     * @see ResponseBody
     * @see org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
     * @see org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
     */
    @Target(ElementType.PARAMETER)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface RequestBody {
    
        /**
         * Whether body content is required.
         * <p>Default is {@code true}, leading to an exception thrown in case
         * there is no body content. Switch this to {@code false} if you prefer
         * {@code null} to be passed when the body content is {@code null}.
         * @since 3.2
         */
        boolean required() default true;
    
    }

    为什么要在传参对象加上@RequestBody呢?

    加上@RequestBody又有什么用呢?

    简单概述下:通过@requestBody可以将请求体中的JSON字符串绑定到相应的bean上,也就实体类。

    当然前台的ajax请求中需包含content-type:"application/json charset=utf-8"。

    在ajax中添加content-type,也意味着发送信息至服务器,并告诉服务器内容编码类型。所以为了对应发送数据的类型,即对象,所以在对应的@RequestMapping中,在对应的方法参数列表,我对指定的对象需要添加@RequestBody。

    关于ajax参数的意思,帮助我自己和大家做个小小的回顾。

    大家可以参考下:

    参考原文博客地址为:https://www.jb51.net/article/73803.htm

    1.url:

    要求为String类型的参数,(默认为当前页地址)发送请求的地址。

    2.type:

    要求为String类型的参数,请求方式(post或get)默认为get。注意其他http请求方法,例如put和delete也可以使用,但仅部分浏览器支持。

    3.timeout:

    要求为Number类型的参数,设置请求超时时间(毫秒)。此设置将覆盖$.ajaxSetup()方法的全局设置。

    4.async:

    要求为Boolean类型的参数,默认设置为true,所有请求均为异步请求。如果需要发送同步请求,请将此选项设置为false。注意,同步请求将锁住浏览器,用户其他操作必须等待请求完成才可以执行。

    5.cache:

    要求为Boolean类型的参数,默认为true(当dataType为script时,默认为false),设置为false将不会从浏览器缓存中加载请求信息。

    6.data:

    要求为Object或String类型的参数,发送到服务器的数据。如果已经不是字符串,将自动转换为字符串格式。get请求中将附加在url后。防止这种自动转换,可以查看  processData选项。对象必须为key/value格式,例如{foo1:"bar1",foo2:"bar2"}转换为&foo1=bar1&foo2=bar2。如果是数组,JQuery将自动为不同值对应同一个名称。例如{foo:["bar1","bar2"]}转换为&foo=bar1&foo=bar2。

    7.dataType:

    要求为String类型的参数,预期服务器返回的数据类型。如果不指定,JQuery将自动根据http包mime信息返回responseXML或responseText,并作为回调函数参数传递。可用的类型如下:
    xml:返回XML文档,可用JQuery处理。
    html:返回纯文本HTML信息;包含的script标签会在插入DOM时执行。
    script:返回纯文本JavaScript代码。不会自动缓存结果。除非设置了cache参数。注意在远程请求时(不在同一个域下),所有post请求都将转为get请求。
    json:返回JSON数据。
    jsonp:JSONP格式。使用SONP形式调用函数时,例如myurl?callback=?,JQuery将自动替换后一个“?”为正确的函数名,以执行回调函数。
    text:返回纯文本字符串。

    8.beforeSend:

    要求为Function类型的参数,发送请求前可以修改XMLHttpRequest对象的函数,例如添加自定义HTTP头。在beforeSend中如果返回false可以取消本次ajax请求。XMLHttpRequest对象是惟一的参数。
                function(XMLHttpRequest){
                   this;   //调用本次ajax请求时传递的options参数
                }

    9.complete:

    要求为Function类型的参数,请求完成后调用的回调函数(请求成功或失败时均调用)。参数:XMLHttpRequest对象和一个描述成功请求类型的字符串。
              function(XMLHttpRequest, textStatus){
                 this;    //调用本次ajax请求时传递的options参数
              }

    10.success:要求为Function类型的参数,请求成功后调用的回调函数,有两个参数。

             (1)由服务器返回,并根据dataType参数进行处理后的数据。
             (2)描述状态的字符串。
             function(data, textStatus){
                //data可能是xmlDoc、jsonObj、html、text等等
                this;  //调用本次ajax请求时传递的options参数
             }

    11.error:

    要求为Function类型的参数,请求失败时被调用的函数。该函数有3个参数,即XMLHttpRequest对象、错误信息、捕获的错误对象(可选)。ajax事件函数如下:
           function(XMLHttpRequest, textStatus, errorThrown){
              //通常情况下textStatus和errorThrown只有其中一个包含信息
              this;   //调用本次ajax请求时传递的options参数
           }

    12.contentType:

    要求为String类型的参数,当发送信息至服务器时,内容编码类型默认为"application/x-www-form-urlencoded"。该默认值适合大多数应用场合。

    13.dataFilter:

    要求为Function类型的参数,给Ajax返回的原始数据进行预处理的函数。提供data和type两个参数。data是Ajax返回的原始数据,type是调用jQuery.ajax时提供的dataType参数。函数返回的值将由jQuery进一步处理。
                function(data, type){
                    //返回处理后的数据
                    return data;
                }

    14.dataFilter:

    要求为Function类型的参数,给Ajax返回的原始数据进行预处理的函数。提供data和type两个参数。data是Ajax返回的原始数据,type是调用jQuery.ajax时提供的dataType参数。函数返回的值将由jQuery进一步处理。
                function(data, type){
                    //返回处理后的数据
                    return data;
                }

    15.global:

    要求为Boolean类型的参数,默认为true。表示是否触发全局ajax事件。设置为false将不会触发全局ajax事件,ajaxStart或ajaxStop可用于控制各种ajax事件。

    16.ifModified:

    要求为Boolean类型的参数,默认为false。仅在服务器数据改变时获取新数据。服务器数据改变判断的依据是Last-Modified头信息。默认值是false,即忽略头信息。

    17.jsonp:

    要求为String类型的参数,在一个jsonp请求中重写回调函数的名字。该值用来替代在"callback=?"这种GET或POST请求中URL参数里的"callback"部分,例如{jsonp:'onJsonPLoad'}会导致将"onJsonPLoad=?"传给服务器。

    18.username:

    要求为String类型的参数,用于响应HTTP访问认证请求的用户名。

    19.password:

    要求为String类型的参数,用于响应HTTP访问认证请求的密码。

    20.processData:

    要求为Boolean类型的参数,默认为true。默认情况下,发送的数据将被转换为对象(从技术角度来讲并非字符串)以配合默认内容类型"application/x-www-form-urlencoded"。如果要发送DOM树信息或者其他不希望转换的信息,请设置为false。

    21.scriptCharset:

    要求为String类型的参数,只有当请求时dataType为"jsonp"或者"script",并且type是GET时才会用于强制修改字符集(charset)。通常在本地和远程的内容编码不同时使用。

    以上内容大家可以做小小的参考。

    关于Controller代码,这里我还补充讲一下@PostMapping源码:

    源码如下:

    /*
     * Copyright 2002-2016 the original author or authors.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package org.springframework.web.bind.annotation;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    import org.springframework.core.annotation.AliasFor;
    
    /**
     * Annotation for mapping HTTP {@code POST} requests onto specific handler
     * methods.
     *
     * <p>Specifically, {@code @PostMapping} is a <em>composed annotation</em> that
     * acts as a shortcut for {@code @RequestMapping(method = RequestMethod.POST)}.
     *
     * @author Sam Brannen
     * @since 4.3
     * @see GetMapping
     * @see PutMapping
     * @see DeleteMapping
     * @see PatchMapping
     * @see RequestMapping
     */
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @RequestMapping(method = RequestMethod.POST)
    public @interface PostMapping {
    
        /**
         * Alias for {@link RequestMapping#name}.
         */
        @AliasFor(annotation = RequestMapping.class)
        String name() default "";
    
        /**
         * Alias for {@link RequestMapping#value}.
         */
        @AliasFor(annotation = RequestMapping.class)
        String[] value() default {};
    
        /**
         * Alias for {@link RequestMapping#path}.
         */
        @AliasFor(annotation = RequestMapping.class)
        String[] path() default {};
    
        /**
         * Alias for {@link RequestMapping#params}.
         */
        @AliasFor(annotation = RequestMapping.class)
        String[] params() default {};
    
        /**
         * Alias for {@link RequestMapping#headers}.
         */
        @AliasFor(annotation = RequestMapping.class)
        String[] headers() default {};
    
        /**
         * Alias for {@link RequestMapping#consumes}.
         */
        @AliasFor(annotation = RequestMapping.class)
        String[] consumes() default {};
    
        /**
         * Alias for {@link RequestMapping#produces}.
         */
        @AliasFor(annotation = RequestMapping.class)
        String[] produces() default {};
    
    }

    看到上述代码,我们很容易发现一点,它少了一个method

    这是@RequestMapping源码

     再回过头看@PostMapping,发现在该类上面定义了一个@PostMapping,从而当Controller对应的方法使用该注解时,自动默认为Post请求。

    这个与@RestController很相似,@RestController,定义了所有返回为JSON格式的数据。也是因为在全局类上定义一个@ResponseBody

    我发现我又想贴代码了,不过我还是忍着。

    再补充一点,@RequestMapping和@PostMapping及其@GetMapping的区别主要在于一个method方法,而PostMapping和GetMapping没有method的,只因其全局类的注解差异,而导致作用不同。

    下面说一下相关方法的作用:

    @RequestMapping

    RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。

    RequestMapping注解有六个属性,下面我们把她分成三类进行说明。

    value:     指定请求的实际地址;

    method:  指定请求的method类型, GET、POST、PUT、DELETE等;

    consumes: 指定处理请求的提交内容类型(Content-Type),例如application/json, text/html;

    produces:    指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回;

    params: 指定request中必须包含某些参数值是,才让该方法处理。

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

    我个人开发中比较常用的就是一个value和produces,其他的除了method之前项目应用过,其他大的目前没有接触过。不过既然@ReqeustMapping、@PostMapping、@GetMapping源码中都有这个。可以好好了解一下。这年头多学点总比不学要强。

  • 相关阅读:
    LeetCode OJ 107. Binary Tree Level Order Traversal II
    LeetCode OJ 116. Populating Next Right Pointers in Each Node
    LeetCode OJ 108. Convert Sorted Array to Binary Search Tree
    LeetCode OJ 105. Construct Binary Tree from Preorder and Inorder Traversal
    LeetCode OJ 98. Validate Binary Search Tree
    老程序员解Bug的通用套路
    转载 四年努力,梦归阿里,和大家聊聊成长感悟
    转载面试感悟----一名3年工作经验的程序员应该具备的技能
    Web Service和Servlet的区别
    关于spring xml文件中的xmlns,xsi:schemaLocation
  • 原文地址:https://www.cnblogs.com/youcong/p/9265216.html
Copyright © 2011-2022 走看看