AJAX應用【股票案例、驗證碼校驗】

1、股票案例

咱們要作的是股票的案例,它可以無刷新地更新股票的數據。當鼠標移動到具體的股票中,它會顯示具體的信息。javascript

咱們首先來看一下要作出來的效果:css

這裏寫圖片描述

1.1服務器端分析

首先,從效果圖咱們能夠看見不少股票基本信息:昨天收盤價、今天開盤價、最高價、最低價、當前價格、漲幅。這些信息咱們用一個類來描述出來。html

咱們發現數據是定時刷新的,因而咱們須要一個定時器。java

服務器端的數據和客戶端交互,咱們使用JSON吧node

1.2服務器端代碼

1.2.1Stock股票類的代碼

  • 股票基本信息:
private String id;

  private String name;

  private double yesterday;

  private double today ;

  private double highest;

  private double lowest;

  private double current;

  private String range ;

//各類setter和getter
  • Stock的構造函數:
/**
 * id,name,yesterday這三個參數都是固定的,其餘的屬性都是可變的。
 * 所以咱們構造函數就傳入這三個值
 * */
public Stock(String id, String name, double yesterday) {
    this.id = id;
    this.name = name;
    this.yesterday = yesterday;

    //把開盤價設定爲-1,後面在定時器計算出來的隨機數,若是發現開盤價是-1,就設置第一次的隨機數爲開盤價
    this.today = -1;

    //把最高、最低、當前的價格都暫且設置成昨天的開盤價,後面咱們能夠變化的
    this.highest = yesterday;
    this.current = yesterday;
    this.lowest = yesterday;

}
  • setCurrent()方法代碼:
/**
 * 每次設置當前價錢的時候,最高、最低、漲幅都應該隨着當前價錢而變化的
 */
public void setCurrent(double current) {

    //計算出漲幅或跌幅
    double range = (current - this.yesterday) / this.yesterday;

    //設置漲幅和跌幅不能超過10%,當前的價格只能是昨天開盤價的1.1倍或0.9倍

    //當前價格應該是兩位小數
    DecimalFormat formatPrice = new DecimalFormat("#.00");

    if (range > 0.1) {
        current = Double.parseDouble(formatPrice.format(this.yesterday * 1.1));
    }

    if (range < -0.1) {
        current = Double.parseDouble(formatPrice.format(this.yesterday * 0.9));
    }
    this.current = current;

    //若是今天開盤價沒設定,那麼就將第一次的當前價做爲今天的開盤價
    if (this.today == -1) {
        this.today = this.current;
    }

    //比較最大值和最小值
    if (this.current > this.highest) {
        this.highest = this.current;
    }
    if (this.current < this.lowest) {
        this.lowest = this.current;
    }

    //格式化漲幅的字符串,整數兩位,小數兩位
    DecimalFormat formatRange = new DecimalFormat("##.##%");
    this.range = formatRange.format(range);    
}

1.2.2Servlet的代碼

  • init()初始化代碼:
/**
 * 重寫init()方法,加入一些配置內容
 */
@Override
public void init(ServletConfig config) throws ServletException {

    map = new HashMap<>();

    //新建幾隻固定的股票
    final Stock zhong = new Stock("1", "百度", 1110.1);
    final Stock fu = new Stock("2", "阿里", 222.2);
    final Stock cheng = new Stock("3", "騰訊", 333.3);
    final Stock ou = new Stock("4", "谷歌", 1133.5);

    //添加到容器中
    map.put("1", zhong);
    map.put("2", fu);
    map.put("3", cheng);
    map.put("4", ou);

    //生成隨機數
    final Random random = new Random();

    //格式化生成的隨機數
    final DecimalFormat format = new DecimalFormat("#.00");

    //Servlet被啓動後1秒開始,每兩秒掃描一次

    timer = new Timer();
    timer.schedule(new TimerTask() {
        @Override
        public void run() {

            double baidu = random.nextDouble() * 1.1;
            double ali = random.nextDouble() * 2;
            double tengxun = random.nextDouble() * 0.3;
            double geogle = random.nextDouble() * 4;

            //機率大體都是50%,咱們用來作正負
            if (random.nextBoolean()) {
                baidu = 0 - baidu;
            }
            if (random.nextBoolean()) {
                ali = 0 - ali;
            }

            if (random.nextBoolean()) {
                tengxun = 0 - tengxun;
            }
            if (random.nextBoolean()) {
                geogle = 0 - geogle;
            }

            //設置它們的當前價格
            zhong.setCurrent(Double.parseDouble(format.format(zhong.getCurrent()+baidu)));
            fu.setCurrent(Double.parseDouble(format.format(fu.getCurrent()+ali)));
            cheng.setCurrent(Double.parseDouble(format.format(cheng.getCurrent()+tengxun)));
            ou.setCurrent(Double.parseDouble(format.format(ou.getCurrent()+geogle)));

        }
    }, 1000, 2000);


}
  • 服務器一啓動就應該初始化Servlet
<servlet>
    <servlet-name>Refresh</servlet-name>
    <servlet-class>Refresh</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>Refresh</servlet-name>
    <url-pattern>/Refresh</url-pattern>
</servlet-mapping>
  • doPost()代碼:
//封裝成JSON格式,返回給瀏覽器
StringBuffer buffer = new StringBuffer();


//這裏咱們拼接成4個對象
buffer.append("({");
for (Map.Entry<String, Stock> entry : map.entrySet()) {
    String id = entry.getKey();
    Stock stock = entry.getValue();

    buffer.append(id).append(":{yesterday:").append(stock.getYesterday()).append(",today:").append(stock.getToday()).append(",high:").append(stock.getHighest()).append(",low:").append(stock.getLowest()).append(",current:").append(stock.getCurrent()).append(",range:'").append(stock.getRange()).append("'}").append(",");

}
//消除最後一個逗號
buffer.deleteCharAt(buffer.lastIndexOf(","));

//最後補上括號
buffer.append("})");

//返回給瀏覽器
response.getWriter().write(buffer.toString());
  • 拼接成的JSON數據:
({
  3:{yesterday:333.3,today:333.48,high:333.48,low:333.3,current:333.48,range:'0.05%'},
  2:{yesterday:222.2,today:223.46,high:223.46,low:222.2,current:223.46,range:'0.57%'},
  1:{yesterday:1110.1,today:1109.73,high:1110.1,low:1109.73,current:1109.73,range:'-0.03%'},
  4:{yesterday:1133.5,today:1135.49,high:1135.49,low:1133.5,current:1135.49,range:'0.18%'}
})

1.3客戶端分析之一

客戶端要作的就是顯示數據,每隔兩秒就和服務器進行一次交互ajax

  • 用到Ajax和setInterval()方法

1.3.1html代碼

使用div嵌套span和a標籤來進行顯示,span裝載的就是服務端返回json的current數據正則表達式

<body onload="show()">

<div>
    <a href="#">百度:</a>
    <span id="1"></span>
</div>
<div>
    <a href="#">阿里巴巴:</a>
    <span id="2"></span>
</div>
<div>
    <a href="#">騰訊:</a>
    <span id="3"></span>
</div>
<div>
    <a href="#">谷歌:</a>
    <span id="4"></span>
</div>


</body>

1.3.2javaScript代碼

  • 解析JSON,並設置span的內容
function show() {

    getStock();

    //每兩秒就取一次數據
    setInterval(getStock, 2000);

}
var httpRequest;
function getStock() {

//力求是最新的響應數據,若是存在httpRequest,那麼將上次的httpRequest終止
    if(httpRequest) {
        httpRequest.abort();
    }

    httpRequest= new XMLHttpRequest();
    httpRequest.open("GET", "Refresh", true);
    httpRequest.onreadystatechange = callBackFunction;
    httpRequest.send(null);

}

function callBackFunction() {
    if(httpRequest.readyState==4) {
        if(httpRequest.status==200) {

            //獲得服務器端返回的JSON數據
            var text = httpRequest.responseText;

            //解析成JavaScript對象
            var json = eval(text);

            //遍歷出每一個JSON對象【也就是json的id】
            for(var id in json) {

                //獲得每一個stock對象
                var stock = json[id];

                //將當前的價格設置到span節點裏面
                document.getElementById(id).innerHTML = stock.current;

                //比較當前價格和昨天開盤價格,若是大於就是紅色,小於就是綠色
                if(stock.current>stock.yesterday) {
                    document.getElementById(id).style.color = 'red';
                }else {
                    document.getElementById(id).style.color = 'green';

                }
            }

        }
    }
}
  • 效果

這裏寫圖片描述


1.4客戶端分析之二

當鼠標移動到具體的股票超連接的時候,會顯示具體的數據,而且數據是動態的json

  • 在超連接上綁定事件
  • 取出和服務器交互的數據,顯示在頁面上

1.4.1html代碼:

綁定事件,只要鼠標移動到超連接上就觸發事件瀏覽器

<body onload="show()">

<div>
    <a href="#" onmouseover="showTool(this)" onmouseleave="clearTool()">百度:</a>
    <span id="1"></span>
</div>
<div>
    <a href="#" onmouseover="showTool(this)" onmouseleave="clearTool()">阿里巴巴:</a>
    <span id="2"></span>
</div>
<div>
    <a href="#" onmouseover="showTool(this)" onmouseleave="clearTool()">騰訊:</a>
    <span id="3"></span>
</div>
<div>
    <a href="#" onmouseover="showTool(this)" onmouseleave="clearTool()">谷歌:</a>
    <span id="4"></span>
</div>

<div id="toolTip">
    <div>
        昨收:<span id="yesterday"></span>
    </div>

    <div>
        今收:<span id="today"></span>
    </div>

    <div>
        最低:<span id="low"></span>
    </div>
    <div>
        當前:<span id="current"></span>
    </div>
    <div>
        最高:<span id="high"></span>
    </div>
    <div>
        漲幅:<span id="range"></span>
    </div>
</div>


</body>

1.4.2css代碼

詳細框的信息默認是隱藏的服務器

<style type="text/css">

    #toolTip {
        border: 1px solid #000;
        width: 150px;
        position: absolute;
        display: none;
    }

</style>

1.4.3javaScript代碼

獲得交互的數據,設置span裏面的值

function update() {

    var stock = json[sid];

    //獲得相對應的控件
    var yesterday = document.getElementById("yesterday");
    var today = document.getElementById("today");
    var low = document.getElementById("low");
    var high = document.getElementById("high");
    var range = document.getElementById("range");
    var current = document.getElementById("current");

    //設置具體信息的值

    high.innerHTML = stock.high;
    range.innerHTML = stock.range;
    current.innerHTML = stock.current;
    yesterday.innerHTML = stock.yesterday;
    today.innerHTML = stock.today;
    low.innerHTML = stock.low;

    //若是數值比昨天開盤價低,反則就是紅色
    if (stock.today > stock.yesterday) {
        today.style.color = 'red';
    } else {
        today.style.color = 'green';
    }

    if (stock.low > stock.yesterday) {
        low.style.color = 'red';
    } else {
        low.style.color = 'green';
    }
    if (stock.high > stock.yesterday) {
        high.style.color = 'red';
    } else {
        high.style.color = 'green';
    }

    //若是如今的價格比昨天開盤高,那麼漲幅是紅色
    if (stock.current > stock.yesterday) {
        range.style.color = 'red';
        current.style.color = 'red';
    } else {
        range.style.color = 'green';
        current.style.color = 'green';
    }
}

只有鼠標移到超連接上,才明確id的值是多少!

function callBackFunction() {
    if (httpRequest.readyState == 4) {
        if (httpRequest.status == 200) {

            //獲得服務器端返回的JSON數據
            json= eval(httpRequest.responseText);

            //更新詳細框的數據,當鼠標移動到超連接上才肯定有id,因而判斷有沒有id
            if(sid) {
                update();
            }

            //遍歷出每一個JSON對象【也就是json的id】
            for (var id in json) {

                //獲得每一個stock對象
                var stock = json[id];

                //將當前的價格設置到span節點裏面
                document.getElementById(id).innerHTML = stock.current;

                //比較當前價格和昨天開盤價格,若是大於就是紅色,小於就是綠色
                if (stock.current > stock.yesterday) {
                    document.getElementById(id).style.color = 'red';
                } else {
                    document.getElementById(id).style.color = 'green';

                }
            }


        }
    }
}

function showTool(node) {

    //獲得鼠標移動到具體股票的id
    sid = node.parentNode.getElementsByTagName("span")[0].id;

    //把詳細框框顯示出來
    document.getElementById("toolTip").style.display = 'block';

}
function clearTool() {
    document.getElementById("toolTip").style.display = 'none';
}

1.5最終效果:

這裏寫圖片描述

1.6總結要點

①:這是由AJAX來實現的,由於它無刷新的動態交互數據。

②:服務器端應該保存着股票的基本信息。因而乎,咱們用一個類來裝載着這些信息【信息之間的關係就不一一說明了,由於每一個案例用的可能都不同】

③:用到了DecimalFormat類來格式化小數變爲本身想要的格式

④:使用HashMap來裝載這些股票,使用Map集合主要是在客戶端中,能夠經過鍵來訪問具體的股票,只要能訪問到股票了,那麼一切就好說了。

⑤:固然啦,裝載股票的任務就交給init()方法,由於只須要裝載一次。

⑥:咱們會發現,股票的信息是不斷會變化的,因此咱們使用定時器和Random類來不斷修改股票的信息

⑦:JavaScript和服務端交互使用AJAX,要麼使用XML,要麼就是JSON,此次咱們採用的是JSON

⑧:JavaScript使用XMLHttpRequest對象獲得Servlet返回給瀏覽器的JSON數據,解析JSON數據,變成是JavaScript對象

⑨:在頁面上顯示服務端帶過來的數據,通常都是使用div來顯示【塊級】,用控件綁定id,在JavaScript中獲得控件,填充數據。這樣就是動態地修改頁面的數據了。

⑩:瀏覽器想要不斷地從服務端獲取股票的數據,那麼就須要不斷地與服務端交互,解析JSON,填充數據.....這種咱們能夠經過setInterval()定時器來作

①①:想要修改字體的顏色,只要獲取它的控件再style.color就能夠修改了。

①②:鼠標移動到具體的股票連接的時候,會出現股票的詳細信息時,這明顯就是爲超連接綁定了事件

①③:股票的詳細信息用一個框框裝載着,那麼咱們就在css中初始化這個框框,它平時是不顯示出來的,只用在鼠標移到它那裏的時候才顯示,咱們把display=「none」就好了。

①④:在響應事件的時候,咱們須要知道用戶是移動到哪個超連接上,因此要獲取獲得具體的超連接id。知道id之後,咱們就知道用戶想要知道的股票是哪個了。

①⑤:股票的信息也想要及時的更新,那麼咱們想把它抽取成一個方法,在AJAX回調方法中加入進去就好了。固然了,id和具體股票對象應該是全局的變量【這樣纔可以在別的方法中用到】

2、驗證碼校驗

對於驗證碼檢查咱們並不會陌生,咱們在學習Session的時候已經使用過了驗證碼檢查了。詳細可參考:http://blog.csdn.net/hon_3y/article/details/54799494#t11

咱們當時是同步檢查驗證碼是否正確的,其實沒有必要。由於就驗證一個輸入框的數據,不必使用同步的方式驗證【使用異步對用戶體驗更加友好】

a

2.1分析

當用戶輸入完4位數字的時候,就去服務器端驗證是否須要相同,若是相同,那麼返回一個打鉤的圖片。若是不一樣,那麼就返回一個打叉的圖片

2.1.1前臺分析

  • 綁定鍵盤輸入事件
  • 當輸入數達到4的時候,就與服務器交互
  • 獲得服務器帶過來的圖片,使用DOM添加到對應的位置

2.1.2後臺分析

  • 獲得前臺帶過來的值
  • 判斷該值與Session保存的是否相同
  • 根據判斷值返回對應的圖片

2.2編寫JSP

值得注意的是:要獲取td定義的id,外邊必定要套上table標籤。。。我在剛開始寫的時候,是沒有table標籤的。而後死活得不到td的標籤....很煩...

<%--
  Created by IntelliJ IDEA.
  User: ozc
  Date: 2017/5/17
  Time: 20:52
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>驗證碼校驗</title>
    <script type="text/javascript" src="js/ajax.js"></script>
</head>
<body>


<%--###################展現頁面#############################--%>

<table>
    <tr>
        <td>驗證碼:</td>
        <td><input type="text" id="checkCode" name="checkCode"></td>
        <td><img src="01_image.jsp"/></td>
        <td id="result"></td>
    </tr>
</table>


<%--###################去除空格方法#############################--%>
<script type="text/javascript">

    function trim(str) {

        //去除左邊的空格
        str.replace("/^\s*/", "");

        //去除右邊的空格
        str.replace("/\s*$/", "");
        return str;

    }
</script>


<%--###################綁定鍵盤事件#############################--%>

<script type="text/javascript">


    document.getElementById("checkCode").onkeyup = function () {

        //獲得輸入框的內容,把的先後空格都去除
        var keyValue = this.value;
        keyValue = trim(keyValue);

        /*******************ajax代碼*******************************/
        if (keyValue.length == 4) {


            var ajax = createAJAX();
            var method = "post";
            var url = "${pageContext.request.contextPath}/CheckCodeServlet?time=" + new Date().getTime();
            ajax.open(method, url);
            ajax.setRequestHeader("content-type", "application/x-www-form-urlencoded");
            ajax.send("keyValue=" + keyValue);


            /*******************ajax回調函數*******************************/
            ajax.onreadystatechange = function () {
                if (ajax.readyState == 4) {
                    if (ajax.status == 200) {

                        //獲得服務器帶過來的數據
                        var tip = ajax.responseText;

                        /*******************使用DOM把數據添加到頁面上*******************************/
                        var img = document.createElement("img");
                        img.src = tip;
                        img.style.width = "14px";
                        img.style.height = "14px";
                        var td = document.getElementById("result");
                        td.innerHTML = "";
                        td.appendChild(img);
                    }
                }
            };


        }else {
            //清空圖片
            var td = document.getElementById("result");
            td.innerHTML = "";
        }


    };


</script>


</body>
</html>
  • 處理請求的Servlet
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * Created by ozc on 2017/5/17.
 */
@WebServlet(name = "CheckCodeServlet",urlPatterns = "/CheckCodeServlet")
public class CheckCodeServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        //獲得帶過來的數據
        String keyValue = request.getParameter("keyValue");
        //獲得Session中的數據
        String checkCodeInSession = (String) request.getSession().getAttribute("CHECKNUM");
        response.setContentType("text/html;charset=UTF-8");

        String src = "images/MsgError.gif";

        //判斷倆數據是否相同
        if (keyValue.equals(checkCodeInSession)) {
            src = "images/MsgSent.gif";
        }
        PrintWriter writer = response.getWriter();
        writer.write(src);

        writer.flush();
        writer.close();


    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        this.doPost(request, response);

    }
}

2.3測試

這裏寫圖片描述


2.4總結

  • 使用AJAX驗證校驗碼主要是監聽鍵盤的響應事件

    • 要獲取td標籤的數據,外邊必定要套有table標籤!【別偷懶不寫table標籤】
    • 當輸入框的數值數爲4的時候就與服務器進行交互,服務器返回一張圖片。
    • 能夠用自定義的trim()把數據的先後空格去掉,經過正則表達式來去除空格。
    • 當輸入框的數值數不爲4的時候就把圖片的內容清空

若是文章有錯的地方歡迎指正,你們互相交流。習慣在微信看技術文章的同窗,能夠關注微信公衆號:Java3y
相關文章
相關標籤/搜索