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

Java3y發表於2018-02-14

股票案例

我們要做的是股票的案例,它能夠無重新整理地更新股票的資料。當滑鼠移動到具體的股票中,它會顯示具體的資訊。

我們首先來看一下要做出來的效果:

這裡寫圖片描述

伺服器端分析

首先,從效果圖我們可以看見很多股票基本資訊:昨天收盤價、今天開盤價、最高價、最低價、當前價格、漲幅。這些資訊我們用一個類來描述出來。

我們發現資料是定時重新整理的,於是我們需要一個定時器。

伺服器端的資料和客戶端互動,我們使用JSON吧

伺服器端程式碼

Stock股票類的程式碼

  • 股票基本資訊:

    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);    
    }

複製程式碼

Servlet的程式碼

  • 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%'}
})

複製程式碼

客戶端分析之一

客戶端要做的就是顯示資料,每隔兩秒就和伺服器進行一次互動

  • 用到Ajax和setInterval()方法

html程式碼

使用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>

複製程式碼

javaScript程式碼

  • 解析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';

                        }
                    }

                }
            }
        }
複製程式碼
  • 效果

這裡寫圖片描述


客戶端分析之二

當滑鼠移動到具體的股票超連結的時候,會顯示具體的資料,並且資料是動態的

  • 在超連結上繫結事件
  • 取出和伺服器互動的資料,顯示在頁面上

html程式碼:

繫結事件,只要滑鼠移動到超連結上就觸發事件


<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>
複製程式碼

css程式碼

詳細框的資訊預設是隱藏的

    <style type="text/css">

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

    </style>
複製程式碼

javaScript程式碼

得到互動的資料,設定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';
        }


複製程式碼

最終效果:

這裡寫圖片描述

總結要點

①:這是由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和具體股票物件應該是全域性的變數【這樣才能夠在別的方法中用到】

驗證碼校驗

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

我們當時是同步檢查驗證碼是否正確的,其實沒有必要。因為就驗證一個輸入框的資料,沒必要使用同步的方式驗證【使用非同步對使用者體驗更加友好】

a

分析

當使用者輸入完4位數字的時候,就去伺服器端驗證是否需要相同,如果相同,那麼返回一個打鉤的圖片。如果不同,那麼就返回一個打叉的圖片

前臺分析

  • 繫結鍵盤輸入事件
  • 當輸入數達到4的時候,就與伺服器互動
  • 得到伺服器帶過來的圖片,使用DOM新增到對應的位置

後臺分析

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

編寫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);

    }
}

複製程式碼

測試

這裡寫圖片描述


總結

  • 使用AJAX驗證校驗碼主要是監聽鍵盤的響應事件
    • 要獲取td標籤的資料,外邊一定要套有table標籤!【別偷懶不寫table標籤】
    • 當輸入框的數值數為4的時候就與伺服器進行互動,伺服器返回一張圖片。
    • 可以用自定義的trim()把資料的前後空格去掉,通過正規表示式來去除空格。
    • 當輸入框的數值數不為4的時候就把圖片的內容清空

如果文章有錯的地方歡迎指正,大家互相交流。習慣在微信看技術文章的同學,可以關注微信公眾號:Java3y

相關文章