美文网首页前端开发专题JS程序员
ajax模拟用户注册和搜索页面

ajax模拟用户注册和搜索页面

作者: lkee6760 | 来源:发表于2017-03-17 13:50 被阅读319次

    概要

    异步简介

    ajax简介

    应用场景1

    应用场景2

    常见问题及排除方法

    小结


    一、异步简介

    你打电话问书店老板有没有《分布式系统》这本书,如果是同步通信机制,书店老板会说,你稍等,”我查一下",然后开始查啊查,等查好了(可能是5秒,也可能是一天)告诉你结果(返回结果)。
    而异步通信机制,书店老板直接告诉你我查一下啊,查好了打电话给你,然后直接挂电话了(不返回结果)。然后查好了,他会主动打电话给你。在这里老板通过“回电”这种方式来回调。[^1]

    "异步模式"非常重要。在浏览器端,耗时很长的操作都应该异步执行,避免浏览器失去响应,最好的例子就是Ajax操作。在服务器端,"异步模式"甚至是唯一的模式,因为执行环境是单线程的,如果允许同步执行所有http请求,服务器性能会急剧下降,很快就会失去响应。[^2]
    [^1]: 引用自<a href="https://www.zhihu.com/question/19732473">知乎--怎样理解阻塞非阻塞与同步异步的区别?</a>
    [^2]: 引用自阮一峰的网络日志


    二、ajax简介

    Asynchronous Javascript And XML ----异步的javascript和xml。
    页面发起请求,会将请求发送给浏览器内核中的Ajax引擎,Ajax引擎会提交请求到服务器,在这段时间里,客户端可以任意进行任意操作,直到服务器端将数据返回给Ajax引擎后,Ajax引擎再将数据给浏览器解析。


    ajax工作原理.jpg

    三、应用场景1

    1.功能演示

    模拟账号注册:注册页面中,如果用户名文本框失去焦点,则进行异步校验;如果用户名已经存在,则在右侧用红色字体提示用户用户名不可用,并且禁用注册按钮,否则提示可用,并解除注册按钮禁用。


    ajax注册.gif

    2.代码

    1. 页面源码(使用了一些Bootstrap样式):
    <div class="form-group">
        <label for="inputname1" class="col-sm-2 col-sm-offset-2 control-label">用户名:</label>
        <div class="col-sm-3">
            <input type="text" name="remitter" class="form-control" id="inputname1" placeholder="请填写全称">
        </div>
        <div class="col-sm-3" id = "msg" style="vertical-align: middle;">
        </div>
    </div>
    
    1. 导入jquery及bootstrap样式
    <link href="${pageContext.request.contextPath}/css/bootstrap.min.css" rel="stylesheet">
    <script src="${pageContext.request.contextPath}/js/jquery-1.11.3.min.js"></script>
    <script src="${pageContext.request.contextPath}/js/bootstrap.min.js"></script>
    
    1. ajax异步校验
    <script type="text/javascript">
        // 页面加载
        $(function(){
            // 触发文本框失去焦点事件
            $("#inputname1").blur(function(){
                // 初步判断文本框非空和去掉空格后仍然非空
                if($(this).val() != "" && $.trim($(this).val()) != "") {
                    // 使用post请求方式传输数据
                    var url = "${pageContext.request.contextPath}/CheckServlet";    // 访问服务器地址
                    var params = "remitter=" + $(this).val();   // 检验参数
                    $.post(url, params, function(d) {   //post请求方式
                        if(d > 0) { //  如果查询到1条记录,则提示用户重新选择用户名
                            $("#msg").html("<font color='red'>该用户名太受欢迎,请重新输入</font>");
                            $("#submit").prop("disabled", true);
                        }else{  //否则提示可以使用该用户名
                            $("#msg").html("用户名可以使用").css("color", "blue");
                            $("#submit").prop("disabled", false);
                        }
                    });
                }else{  //  如果文本框没有有用的信息则将提示内容清空,并禁用注册键
                    $("#msg").html("");
                    $("#submit").prop("disabled", true);
                }
            });
        });
    </script>
    
    1. CheckServlet内容
    try {
        // post请求解决乱码问题
        request.setCharacterEncoding("UTF-8");
        // 获取请求数据
        String remitter = request.getParameter("remitter");
        // 调用service层
        CheckService cs = new CheckService();
        // 返回查询参数
        int count = cs.find(remitter);
        // 传递到客户端
        response.getWriter().print(count);
    } catch (SQLException e) {
        e.printStackTrace();
    }
    
    1. CheckService内容
      略......
    2. CheckDao内容
    public int find(String remitter) throws SQLException {
        // 使用QueryRunner工具类
        QueryRunner qr = new QueryRunner(C3p0Utils.getDataSource());
        // 编写sql语句
        String sql = "select count(*) from searchkey where username = ?";
        // 由于ScalarHandler返回的Object只能强转成Long类型,必须再次调用intValue()方法才能返回int类型
        return ((Long)qr.query(sql, new ScalarHandler(), remitter)).intValue();
    }
    
    1. C3p0Utils自定义工具类请参考使用
    public class C3p0Utils {
        private static DataSource ds = new ComboPooledDataSource("nefu");
        public static DataSource getDataSource() {
            return ds;
        }
    }
    

    配置文件c3p0-config.xml存放在src目录下

    <?xml version="1.0" encoding="UTF-8"?>
    <c3p0-config>
        <named-config name="nefu">
            <!-- 连接数据库的4项基本参数 -->
            <property name="driverClass">com.mysql.jdbc.Driver</property>
            <property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/searchkey_db
            </property>
            <property name="user">root</property>
            <property name="password">123</property>
            <!-- 如果池中数据连接不够时一次增长多少个 -->
            <property name="acquireIncrement">5</property>
            <!-- 初始化连接数 -->
            <property name="initialPoolSize">20</property>
            <!-- 最小连接受 -->
            <property name="minPoolSize">10</property>
            <!-- 最大连接数 -->
            <property name="maxPoolSize">40</property>
            <!-- -JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量 -->
            <property name="maxStatements">0</property>
            <!-- 连接池内单个连接所拥有的最大缓存statements数 -->
            <property name="maxStatementsPerConnection">5</property>
        </named-config>
    </c3p0-config>
    

    应用场景2

    1.功能演示

    模拟搜索引擎:输入关键字,查询数据库,并将查询结果返回到浏览器展示。


    ajax模拟搜索引擎.gif

    2.代码

    1. 页面源码
    <div class="form-group dropdown">
        <input type="text" class="form-control dropdown-toggle" id="key" style="width: 300px"
            data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" />
        <ul id="list" class="dropdown-menu"
            style="width: 100%; display: none;" aria-labelledby="dropdownMenu"></ul>
    </div>
    
    1. ajax代码(导包内容与应用场景2一致)
    <script>
        // 当单击备选条是文本框输入内容
        function selected(obj) {
            $("#key").val($(obj).text());
            $("#list").hide();
        }
        // 页面加载
        $(function(){
            // 当按键弹起事件
            $("#key").keyup(function() {
                // 先将下拉列表清空,并隐藏列表
                $("#list").html("");
                $("#list").hide();
                if($(this).val() != "" && $.trim($(this).val()) != "") {
                    url = "${pageContext.request.contextPath}/SearchingServlet";
                    params = "keyword=" + $(this).val();
                    // post请求
                    $.post(url, params, function(d) {
                        if(d != null) {
                            $(d).each(function(a,b) {   // 遍历d,并将结果追加到列表后面
                                $("#list").append("<li onclick='selected(this)'><a>" + b + "</a></li>");
                                $("#list").show();  // 展示列表内容
                            })
                        }
                    }, "json")  // 使用json的数据形式返回数据
                }
            })
        })
    </script>
    
    1. SearchServlet内容
    try {
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        String keyword = request.getParameter("keyword");
        SearchingService ss = new SearchingService();
        List<Object> list = ss.find(keyword);
        // 随机选择集合中的前10个选项
        Collections.shuffle(list);
        ArrayList<Object> temp = new ArrayList<Object>();
        for (Object object : list) {
            if(temp.size() < 10) {
                temp.add(object);
            }
        }
        // 将temp集合转换成json格式
        JSONArray jsonarray = JSONArray.fromObject(temp);
        String json = jsonarray.toString(); 
        // 传递给浏览器
        response.getWriter().print(json);
    } catch (SQLException e) {
        e.printStackTrace();
    }
    
    1. SearchingService层
      略......
    2. SearchingDao层
    public List<Object> find(String keyword) throws SQLException {
        QueryRunner qr = new QueryRunner(C3p0Utils.getDataSource());
        // 将关键字拆分单个字符
        char[] array = keyword.toCharArray();
        StringBuilder sql = new StringBuilder();
        // where 1 = 1 拼接字符串过程中,避免无法确定and的开始位置
        sql.append("select distinct username from searchkey where 1 = 1");
        // 建立一个list集合存储参数 注意空格
        List<String> params = new ArrayList<>();
        if(array != null) {
            for (char c : array) {
                if(c != ' ') {
                    sql.append( " and username like ?");
                    params.add("%" + c + "%");
                }
            }
        }
        List<Object> list = qr.query(sql.toString(), new ColumnListHandler(), params.toArray());
        return list;
    }
    
    1. C3p0Utils自定义工具类及配置文件
      略.....

    五、常见问题及排除方法

    由于html没有语法检查功能(HBuilder好像有,但是加载半天你能忍),所以事件触发后没有响应的错误很难排查,根据笔者的经验给出几点建议

    • 排查语法格式,例如$("inputname1")没有#号,var url=写成了val url=(我好像暴露了什么dog脸)
    • 注释一部分内容,并使用alert("字符串"),来判断错误的地方,如果是页面加载也没有弹框,可能是没有导入jquery库
    • 使用junit进行单元测试,主要是sql语句,再者容易出现的问题就是数据库连接失败,注意C3p0Utils的配置文件是否错误
    • 页面500错误提示信息,控制台异常信息都可以帮助定位错误内容。

    六、小结

    1. 内容较杂,很多细节无法面面俱到,不清楚的请询问;
    2. ajax的格式本人了解到的有三种,第二种常用
    $.get(url,[params],[fn],[type]):发送了一个get请求
    
    $.post(url,[params],[fn],[type]):发送一个post请求
    
    $.ajax({选项});
        常见的选项:
            url:路径,
            data:发送的参数,
            type:请求的方式,
            success:成功时候的回调,
            error:错误时候的回调,
            async:是否异步 默认就是异步的方式,
            dataType:返回内容的格式 默认字符串
    
    1. 本文涉及到json数据格式一般有{"key":value,"key1":value1}[e1,e2],可以使用jsonlib调用方法直接将数组、集合等转成json数据类型。
    2. 使用到的jar包


      jar包

    相关文章

      网友评论

      本文标题:ajax模拟用户注册和搜索页面

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