使用jQuery+spring+json实现二级联动菜单

实现效果

GIF.gif

完整代码
链接:https://pan.baidu.com/s/1nvkSNVV 密码:qsyb

1 创建项目及准备工作

DAY11-01-AJAX-DropDownMenu Maven的war项目

导入springmvc和jackson的jar包

pom.xml

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>3.2.8.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.2.3</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.2.3</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.2.3</version>
        </dependency>
    </dependencies>

web.xml


    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>utf-8</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <servlet>
        <servlet-name>SpringMVC</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:applicationContext.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>SpringMVC</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>

applicationContext.xml

    <context:component-scan base-package="cn.tedu.spring" />
    
    <mvc:annotation-driven>
        <mvc:message-converters>
            <bean
                class="org.springframework.http.converter.StringHttpMessageConverter">
                <property name="supportedMediaTypes">
                    <list>
                        <value>text/html;charset=utf-8</value>
                        <value>application/json;charset=utf-8</value>
                        <value>*/*;charset=utf-8</value>
                    </list>
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>

    <bean
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

2 设计数据

----- 请选择 -----
1.广东省              1.广州,2.深圳,3.珠海 
2.河北省              4.石家庄,5.保定,6.秦皇岛

3 设计服务端的功能:

URL : getCities.do
请求类型:GET
参数:provinceId
返回:ResponseResult,其中的数据部分是List<City>,City中至少封装id,name

a) 创建cn.tedu.spring.bean.ResponseResult,属性包括:int state,String message,Object data;
package cn.tedu.spring.bean;

public class ResponseResult {

    private int state;
    private String message;
    private Object data;

    public ResponseResult() {
        super();
    }

    public ResponseResult(int state) {
        super();
        this.state = state;
    }

    public ResponseResult(int state, String message) {
        super();
        this.state = state;
        this.message = message;
    }

    public ResponseResult(int state, Object data) {
        super();
        this.state = state;
        this.data = data;
    }

    public ResponseResult(int state, String message, Object data) {
        super();
        this.state = state;
        this.message = message;
        this.data = data;
    }

    public int getState() {
        return state;
    }

    public void setState(int state) {
        this.state = state;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

}
  • b) 创建cn.tedu.spring.bean.City,属性包括:int id,String name;
package cn.tedu.spring.bean;

public class City {

    private int id;
    private String name;
    
    public City() {
        super();
    }

    public City(int id, String name) {
        super();
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}
  • c) 创建cn.tedu.spring.controller.CityController,添加public String getCities(int provinceId)方法,映射到getCites.do路径,在方法内部,根据参数provinceId进行判断,然后得到List<City>,封装到ResponseResult中,最后转换为JSON字符串,作为方法的返回值
@Controller
public class CityController {
    
    @RequestMapping("getCities.do")
    @ResponseBody
    public String getCities(int provinceId){
        List<City> cityes = new ArrayList<City>();
        switch (provinceId){
            case 1:
                cityes.add(new City(1,"广州"));
                cityes.add(new City(2,"深圳"));
                cityes.add(new City(3,"珠海"));
            case 2:
                cityes.add(new City(4,"石家庄"));
                cityes.add(new City(5."保定"));
                cityes.add(new City(6,"秦皇岛"));
                break;
            default:
                break;
        }
    }

}
2017-12-26 20-27-20.png
  • d) 通过浏览器测试
2017-12-26 20-27-35屏幕截图.png
2017-12-26 20-28-15屏幕截图.png

4 创建前端页面index.html,并添加2个下拉菜单,其中第1个下拉菜单中添加1广东省、2河北省这2个有效选项。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Ajax -- 二级联动菜单</title>
</head>
<body>
    <select style="width: 120px;" onchange="getCities(this.value)">
        <option value="0">----- 请选择  -----</option>
        <option value="1">广东省</option>
        <option value="2">河北省</option>
    </select>

    <select style="width: 120px;" id="cities">
    </select>
</body>
</html>

5 设计AJAX请求

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Ajax -- 二级联动菜单</title>
<script type="text/javascript">
    function $(id) {
        return document.getElementById(id);
    }

    function getXMLHttpRequest() {
        var xmlhttp = null;
        if (window.XMLHttpRequest) {
            xmlhttp = new XMLHttpRequest();
        } else {
            xmlhttp = new ActiveObject("Microsoft.XMLHttp");
        }
        return xmlhttp;
    }

    function getCities(provinceId) {
        // 无论选中哪个选项,先清空“城市”列表
        while ($("cities").firstChild) {
            $("cities").removeChild($("cities").firstChild);
        }
        // 判断provinceId是否有效
        if (provinceId == 0) {
            return;
        }
        // 获取XMLHttpRequest
        var xmlhttp = getXMLHttpRequest();
        // 设计响应函数
        xmlhttp.onreadystatechange = function() {
            if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
                // 获取响应的正文文本
                var text = xmlhttp.responseText;
                // 将响应的正文文本转换为JSON对象
                var jsonObject = JSON.parse(text);
                // 判断JSON对象中state是否正确
                if (jsonObject.state == 1) {
                    // 遍历JSON对象中的data对应的数组
                    for (var i = 0; i < jsonObject.data.length; i++) {
                        // 将数组中的每个数据设计为一个个<option>
                        var opt = document.createElement("option");
                        // <option value="3">珠海</option>  
                        // "data":[
                        //      {"id":1,"name":"广州"},
                        //      {"id":2,"name":"深圳"},
                        //      {"id":3,"name":"珠海"}
                        //  ]
                        opt.value = jsonObject.data[i].id;
                        opt.innerHTML = jsonObject.data[i].name;
                        // 将<option>添加到“城市”列表中
                        $("cities").appendChild(opt);
                    }
                }
            }
        };
        // 发出请求
        var url = "getCities.do?provinceId=" + provinceId;
        xmlhttp.open("GET", url, true);
        xmlhttp.send();
    }
</script>
</head>
<body>
    <select style="width: 120px;" onchange="getCities(this.value)">
        <option value="0">----- 请选择  -----</option>
        <option value="1">广东省</option>
        <option value="2">河北省</option>
    </select>

    <select style="width: 120px;" id="cities">
    </select>
</body>
</html>

测试效果

2017-12-27 21-01-08屏幕截图.png
2017-12-27 21-02-55 的屏幕截图.png

AJAX的数据缓存问题

如果反复向同一个URL发出请求,并且请求参数没有发生变化的话,可能会获取到缓存的数据,即获取到的不是最新数据!

针对这个问题的解决方案:使得每次请求参数都不同!例如为每次的请求多添加1个参数,参数名可以自定义,参数值使用随机数即可!

jQuery AJAX 实现二级联动

JQuery AJAX - load()

在使用了JQuery后,关于AJAX的应用也得到了极大的简化,通过load()函数可以快速的提交AJAX的异步请求,并且将响应的结果填充到某个标签中。

注意:这种做法适用于(但不局限于)将结果直接填充到标签中!

这种做法的语法格式是:

$(选择器).load(URL,参数);

在以上语法中,$(选择器)表示需要将结果填充到哪个标签中,URL表示请求路径,参数表示发出请求时向服务器提交的参数,参数值的格式可以是字符串格式,例如:

username=tomcat&password=123456

参数值的格式还可以是JSON对象格式:

{"username":"tomcat","password":"123456"}

其实,load()函数的完整格式是:

$(选择器).load(URL,参数,处理响应结果的函数);

也就是说,load()函数还可以有第3个参数,第3个参数是一个函数,专门用于处理结果,类似于传统方式中的xmlhttp.onreadystatechange属性的值。

另外,其实在jQuery中,还有另一个也叫做load()的函数,也是被某个标签对象所调用的,但是,其参数是某个函数,用于表示标签加载完成时的自定义处理,这2个load()函数,至于执行的是哪个,取决于参数的设计。

  • 1 引入jQuery
2017-12-27 21-05-47屏幕截图.png
  • 2 添加load.html页面,使用load()函数提交AJAX请求

load.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>JQuery AJAX -- load</title>
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript">
    function loadContent(){
        $("#content").load("getCities.do","provinceId=1");
    }
</script>
</head>
<body>
    <div id="content" style="border:1px solid #999; width:300px;height:200px;"></div>
    <p>
        <input type="button" value="使用JQuery提交AJAX请求" onclick="loadContent()" />
    </p>
</body>
</html>
  • 3 测试效果
2017-12-27 21-31-30屏幕截图.png

jQuery AJAX - ajax()

在使用jQuery时,通过ajax()函数可以设置AJAX请求过程中所有的可设置项!

使用ajax()的基本语法是:

$.ajax({配置});

以上语法中,“配置”及左右两侧的{}整体表现为一个JSON对象格式。

在“配置”中,通常会设置的属性有:

url:请求的路径

例如:

    $.ajax({
        "url":"getCities.do",
        "success":function(obj){

        }
    });

还会设置的属性有:

type:请求的类型(请求方式),取值为"GET"或"POST"

data:请求的参数,参数值可以是字符串格式的,也可以是JSON对象格式的

dataType:响应结果的数据的类型,常用的取值有"text"、"json",当取值为"text"时,后续success属性对应的处理函数中的参数将是字符串类型的,当取值为"json"时,后续success属性对应的处理函数中参数将是JSON对象

success:成功得到响应结果时的处理函数,即该属性的值是某个函数,该函数仅会在成功得到响应结果后被调用,所以,在函数内部,无须再判断状态码为4或响应码为200,并且,在编写处理函数时,请为该函数添加参数,参数名称可自行定义,参数将是成功得到响应结果时的响应结果,类似于xmlhttp.responseTest

在配置以上属性时,不区分先后顺序,即先配置哪个,并没有要求!

除此以外,ajax()函数还可以配置许多属性,如有需要,请参考相关文档。

  • 1 使用$.ajax({配置});提交AJAX请求
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>JQuery Ajax -- 二级联动菜单</title>
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript">
    // 为了便于可能存在的事件绑定,
    // 凡是与事件相关的函数,
    // 能不定义参数就不要定义参数
    // 对于那些动态的、可能变化的值,
    // 推荐在函数内部去动态获取
    function getCities(){
        // 清空“城市”的下拉列表
        $("#cities").empty(); // 相当于 innerHTML=""
        
        // 获取当前选中的“省份”的value
        var pid = $("#provinces").val();
        
        // 如果获取到的是0,则不处理
        if(pid == 0){
            return;
        }
        
        // 发出请求并处理响应结果
        $.ajax({
            "url":"getCities.do", // 请求地址
            "type":"GET", // 请求方式
            "data":"provinceId="+pid, // 请求参数
            "dataType":"json", // 服务器返回的数据类型
            "success":function(obj){ // 服务器处理正常对应的回调函数
                // 判断JSON对象中的state
                if(obj.state == 1){
                    //"data":[
                    //  {"id":1,"name":"广州"},
                    //  {"id":2,"name":"深圳"},
                    //  {"id":3,"name":"珠海"}
                    //]
                    // 遍历JSON对象中的data(数组)
                    for(var i = 0;i<obj.data.length;i++){
                        // 创建<option>的HTML代码(字符串)
                        var op = "<option value="+obj.data[i].id+">"+obj.data[i].name+"</option>"
                        // 将<option>的HTML代码添加到"城市"下拉菜单
                        $("#cities").append(op);
                    }
                }
            }
        });
    }
</script>
</head>
<body>
    <h3>jQuery Ajax -- 二级联动菜单</h3>
    
    <select id="provinces" style="width: 120px" onchange="getCities()">
        <option value="0">----- 请选择 -----</option>
        <option value="1">广东省</option>
        <option value="2">河北省</option>
    </select>
    
    <select style="width: 120px;" id="cities">
    </select>
</body>

  • 2 测试效果
2017-12-27 21-32-18屏幕截图.png
  • 3 动态效果
GIF.gif

回顾

[*****] HTML

用于规划网页内容,需要掌握有哪些标签,什么时候用什么标签,什么样的标签默认有什么样式

[***] CSS

[***] Javascript

处理界面与用户的交互

[***] jQuery

[*****] jQuery AJAX

[***] Servlet

用于接收用户的请求,并向客户返回响应结果。

需要掌握:定位、注册、注册时配置参数

[**] Filter

用于对请求进行过滤,运行在Servlet之前

需要掌握:字符编码过滤器

[*****] JSP

向客户端提供响应的视图

需要掌握:EL、JSTL

a + b
a > b

EL是表达式,JSTL进行逻辑处理

[*****] SQL

需要掌握:创建库、创建表、增删改查、关联表查询、事务

需要了解:聚合函数、Having、Group By、存取过程、触发器

[*****] Spring

Spring解决了创建对象的问题,使得开发者可以不通过new语法获取对象。

DI(依赖注入)是实现的手段,IOC(控制反转)是最终的实现效果。

*****] Spring MVC

Spring MVC提供完整的接收请求、分发请求、响应请求的机制,最终表现为开发者可以自定义Controller类,并在Controller自定义方法去处理请求。

[*****] Mybatis

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