咱們要作的是股票的案例,它可以無刷新地更新股票的數據。當鼠標移動到具體的股票中,它會顯示具體的信息。javascript
咱們首先來看一下要作出來的效果:css
首先,從效果圖咱們能夠看見不少股票基本信息:昨天收盤價、今天開盤價、最高價、最低價、當前價格、漲幅。這些信息咱們用一個類來描述出來。html
咱們發現數據是定時刷新的,因而咱們須要一個定時器。java
服務器端的數據和客戶端交互,咱們使用JSON吧node
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
/** * 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; }
/** * 每次設置當前價錢的時候,最高、最低、漲幅都應該隨着當前價錢而變化的 */ 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); }
/** * 重寫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-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>
//封裝成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());
({ 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
使用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>
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'; } } } } }
當鼠標移動到具體的股票超連接的時候,會顯示具體的數據,而且數據是動態的json
綁定事件,只要鼠標移動到超連接上就觸發事件瀏覽器
<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>
詳細框的信息默認是隱藏的服務器
<style type="text/css"> #toolTip { border: 1px solid #000; width: 150px; position: absolute; display: none; } </style>
獲得交互的數據,設置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的時候已經使用過了驗證碼檢查了。詳細可參考:http://blog.csdn.net/hon_3y/article/details/54799494#t11
咱們當時是同步檢查驗證碼是否正確的,其實沒有必要。由於就驗證一個輸入框的數據,不必使用同步的方式驗證【使用異步對用戶體驗更加友好】
當用戶輸入完4位數字的時候,就去服務器端驗證是否須要相同,若是相同,那麼返回一個打鉤的圖片。若是不一樣,那麼就返回一個打叉的圖片
值得注意的是:要獲取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>
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驗證校驗碼主要是監聽鍵盤的響應事件
若是文章有錯的地方歡迎指正,你們互相交流。習慣在微信看技術文章的同窗,能夠關注微信公衆號:Java3y