系列文章:
Servlet向JSP傳遞數據以及JSP頁面DIV定時局部刷新
STM32 ESP8266和Java服務器透傳模式下的雙向通信
jsp向servlet傳輸數據
ESP8266的AP模式與STA模式簡單測試
工作流程:
login.jsp->ValidateTest.java->ControlTest.jsp和SocketTest.java->Control.java->8266->STM32
以上文件中後綴名爲.jsp的就是JSP文件,Control.java
和ValidateTest.java
就是所謂的Servlet文件,SocketTest.java
就是普通的Java Class文件。即只要是和JSP文件有數據傳遞關係的都得創建Servlet文件,而不是創建Class文件,當然了,你創建Class文件也行,只不過裏面還是都得有Servlet文件所必須的doPost之類的方法。
Servlet是用來和JSP進行通信的文件,Servelt與JSP關係
工作流程文字描述:
第一步:進入登錄頁面login.jsp
,輸入賬號和密碼
第二步:進入賬號密碼驗證程序ValidateTest.java
,驗證成功後進入第三步,驗證失敗返回第一步
第三步:先進入控制系統頁面ControlTest.jsp
,然後再進入創建服務器並等待客戶端的連接請求SocketTest.java
,若有客戶端連接成功,則進入第四步,若一直沒有客戶端連接請求,則一直在這裏等待客戶端的連接,直至人爲終止程序
第四步:點擊控制按鈕,向客戶端發送數據
第五步:客戶端即工作在透傳模式下的ESP8266把收到的數據傳遞給STM32
第六步:STM32解析並處理數據
首先運行第一個登錄頁面:
login.jsp
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>登錄</title>
<style>
body{margin: 0;
padding: 0;
font-family: sans-serif;
background-image: url(img/login_background.png);
background-size: cover;
}
.box{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
width: 400px;
padding: 40px;
background: rgba(0,0,0,.8);
box-sizing: border-box;
box-shadow: 0 15px 25px rgba(0,0,0,.5);
border-radius: 10px;
}
.box h2{
margin: 0 0 30px;
padding: 0;
color: #fff;
text-align: center;
}
.box .inputBox{
position: relative;
}
.box .inputBox input{
width: 100%;
padding: 10px,0;
font-size: 16px;
color: #fff;
letter-spacing: 1px;
margin-bottom: 30px;
border: none;
border-bottom: 1px solid #fff;
outline: none;
background: transparent;
}
.box .inputBox label{
position: absolute;
top: 0;
left: 0;
padding: 10px,0;
font-size: 16px;
color: #fff;
letter-spacing: 1px;
pointer-events: none;
transition: .5s;
}
.box .inputBox input:focus ~ label,
.box .inputBox input:valid ~ label
{
top: -18px;
left: 0;
color: #03a9f4;
font-size: 12px;
}
.box input[type="submit"]{
background: transparent;
border: none;
outline: none;
color: #fff;
background: #03a9f4;
padding: 10px 20px;
cursor: pointer;
border-radius: 5px;
margin-left: 120px;
}
</style>
</head>
<body>
<div class="box">
<h2>Login</h2>
<!-- 下面這句話很重要,由它決定跳轉到哪個文件執行,並且說明了使用post方法,
所以不能只用點擊事件來觸發,點擊事件沒有說明使用的是post方法 ,
另外注意當使用get方法時,賬號密碼會暴露在地址欄中 -->
<form action="ValidateTest" method="post">
<div class="inputBox">
<input type="text" name="Username" required="" />
<label>Username</label>
</div>
<div class="inputBox">
<input type="password" name="password" required="" />
<label>password</label>
</div>
<!-- 注意提交按鈕不用設置成點擊事件,直接使用form的action屬性即可設置跳轉到哪個頁面 -->
<input type="submit" name="" value="submit" />
</form>
</div>
</body>
<!-- <script>
function login(){
location.replace("LoginServlet");
}
</script> -->
</html>
運行結果:
輸入賬號密碼之後,數據會通過<form action="ValidateTest" method="post">
這句話來進行相應的跳轉,action後面的參數就是指的是要把用戶輸入的賬號和密碼傳輸到哪一個程序中執行,method後面的參數是指採用哪種傳輸方式,傳輸方式有post和get。
ValidateTest.java
package servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class LoginServlet
*/
//@WebServlet是採用注入的方式表示這是一個Servlet類,採用此方法比較方便,因爲此方法不用再去配置web.xml文件
@WebServlet("/ValidateTest")
public class ValidateTest extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public ValidateTest() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
//doGet響應get請求,doPost響應post請求,爲了保證不管在login.jsp中選擇post方法還是get方法,在這裏都能有所迴應,所以
//這裏只在doPost中寫相應的代碼,而在doGet中直接調用doPost函數即可
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
// response.getWriter().append(info);
}
private void alert(String string) {
// TODO Auto-generated method stub
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//從login頁面中獲取用戶名和密碼
String name = request.getParameter("Username");
String password = request.getParameter("password");
response.setCharacterEncoding("utf-8");
response.setContentType("text/html");
if(name == null || password == null || name.equals("") || password.equals("")) {
response.getWriter().append("賬號/密碼不能爲空");
return;
}else {
if(name.equals("asddssdf") && password.equals("sdjfhjhffjshbfgk")) {
RequestDispatcher dispatcher = getServletContext().getRequestDispatcher("/ControlTest.jsp");//這句話的意思是當驗證賬號密碼都正確後,要繼續跳轉到哪一個頁面,這裏是跳轉到ControlTest頁面
dispatcher.forward(request, response);
SocketTest.getSocket();//這句話是用來創建一個服務器等待客戶端(連接在STM32上的8266)的連接,連接成功後生成一個Socket用來雙方的通信。注意創建Socket以及等待客戶端連接一定要在頁面跳轉到控制頁面之後進行,因爲等待客戶端連接是一個阻塞函數,程序會一直死在那裏等待客戶端的連接
}else {
//response.sendRedirect("login.jsp");//直接重定向到登錄頁面,無任何提示信息
//有登錄失敗的提示信息,但是跳到了一個新頁面,點擊確定之後重新回到登錄頁面回到指定頁面
PrintWriter out = response.getWriter();
out.print("<script>alert('賬號/密碼錯誤,請重新登錄!');window.location.href='login.jsp'</script>");
}
}
}
}
ControlTest.jsp
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>控制系統</title>
</head>
<body>
<h2>這裏是控制系統</h2>
<button onclick="power()">控制按鈕</button>
</body>
<script src="js/jquery-3.2.1.min.js"></script>
<script type="application/javascript"></script>
<script type="text/javascript">
var switch_flag = "0";
function power(){
if(switch_flag == "0"){
switch_flag = "1";
//使用ajax向servlet傳遞數據
$.ajax({
type:"post",
url:"Control",
data:{
'switch_flag':"1",
},
dataType:"json" //數據類型爲json格式
});
}
else if(switch_flag == "1"){
switch_flag = "0";
$.ajax({
type:"post",
url:"Control",
data:{
'switch_flag':"0",
},
dataType:"json" //預期服務器返回來的數據類型,而不是此處發送的數據類型
});
}
}
</script>
</html>
這個控制按鈕的作用就是每次點擊,他就會使switch_flag
改變一次值,值在0和1之間來回改變,並且通過Ajax技術把switch_flag
的值傳遞給參數url
所指定的程序中,即url:"Control",
。然後在Control.java文件中再把相應的數據通過Socket發送給客戶端8266.
Control.java
package servlet;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
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 servlet.SocketDemo;
/**
* Servlet implementation class LoginServlet
*/
//@WebServlet是採用注入的方式表示這是一個Servlet類,採用此方法比較方便,因爲此方法不用再去配置web.xml文件
@WebServlet("/Control")
public class Control extends HttpServlet {
private static final long serialVersionUID = 1L;
private Socket socket;
/**
* @see HttpServlet#HttpServlet()
*/
public Control() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
//doGet響應get請求,doPost響應post請求,爲了保證不管在login.jsp中選擇post方法還是get方法,在這裏都能有所迴應,所以
//這裏只在doPost中寫相應的代碼,而在doGet中直接調用doPost函數即可
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
// response.getWriter().append(info);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
String switch_flag = request.getParameter("switch_flag");
response.setCharacterEncoding("utf-8");
response.setContentType("text/html");
System.out.println("收到ajax請求");
System.out.println("總電源:"+switch_flag);
Socket client = SocketTest.getClient();
// DataInputStream input = new DataInputStream(socket.getInputStream());
DataOutputStream out = new DataOutputStream(client.getOutputStream());
// System.out.print("請向客戶端發送數據:\n");
String s = switch_flag;
// String s = new BufferedReader(new InputStreamReader(System.in)).readLine();
out.writeUTF(s); //注意必須是UTF格式
System.out.print("向客戶端發送的數據爲:"+s+"\n");
}
}
SocketTest.java
package servlet;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class SocketTest {
private static Socket Client = null;
private static ServerSocket serverSocket = null;
private static final int SERVER_PORT = 12444;
private static String resultFromClient = "";
//以下是一個靜態方法(static 表示這是一個靜態方法),靜態方法的作用就是可以在不進行創建對象(即不進行實例化)的情況下調用此方法
//由於本方法需要返回一個值,故不能用void了,由於返回值類型是一個Socket,故應該在static的後面加上返回值的類型(就相當於int cha等等)Socket
public static Socket getSocket() throws IOException {
try {
serverSocket = new ServerSocket(SERVER_PORT);
System.out.print("服務器已建立\n");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.print("等待客戶端的連接...\n");
Client = serverSocket.accept();
System.out.println("Socket client" + Client.getRemoteSocketAddress() + "成功連接");
return Client;
}
public static Socket getClient() {
return Client;
}
}
運行結果:
每點擊一次控制按鈕,就會向客戶端發送一次數據
以上實驗有一個問題,就是在輸入完正確的賬號密碼並且點擊提交之後,按邏輯來說應該是先顯示控制系統的頁面即ControlTest.jsp
,然後再調用SocketTest函數去創建ServerSocket並且一直等待客戶端的連接請求,也就是說我們看到的應該是在控制系統的頁面去等待客戶端的連接,我之前寫好的程序也是這樣的,但是我又寫了這個博客實驗的時候,它總是停留在登錄頁面一直等待客戶端的連接,我也不知道咋回事。
下載客戶端(STM32端)代碼(不完整,完整的請下載後面的)
至此就完成了服務器向客戶端發送數據
客戶端向服務器發送數據並局部實時刷新到JSP頁面進行顯示請點擊
STM32端較完整代碼下載:
鏈接:https://pan.baidu.com/s/1reuUT-HItQsyJ7YcqcBdfQ
提取碼:4r5b
注意:串口接收處理程序請以下面博客中的爲準
STM32 ESP8266和Java服務器透傳模式下的雙向通信