1. 在使用TCP协议时,如果输入流迟迟等不到消息,可能会一直阻塞,导致程序无响应,可以给客户端Socket设置一个最大等待时间。超过这个时间Socket将会自动关闭,从而结束阻塞的状态。
Socket s = ...; // 客户端连接
s.setSoTimeout(10000); // 设置10秒超时时间
可通过捕获SocketTimeOutException异常对阻塞情况进行处理
2. 向MySQL数据库插入数据的时候,如果已经存在关键数据都相同的数据,将会抛出异常。所以为了尽量避免异常可以先判断是否存在相同数据,再确定是否执行新增数据操作。
String username = UsernameGenerator.generateUsername();
while ( FindRowNumber.toFindRowNumber(username) > 0 ) {
username = UsernameGenerator.generateUsername();
} //用于保证生成的 username 不会重复
其中UsernameGenerator.generateUsername()是一个用于生成随机字符串的静态方法
FindRowNumber.toFindRowNumber(username)则是用于寻找数据所在数据库的行数,如果没有找到将会返回-1,其源代码如下所示
import java.sql.*;
public class FindRowNumber {
public static int toFindRowNumber(String keyname) {
// 数据库配置
String url = "jdbc:mysql://localhost:3306/ydll";
String user = "root";
String password = "1234";
String tableName = "logindata";
String keyColumn = "username";
String keyValue = keyname; // 你要查找的关键键值
// 查找关键键所在的行号
int rowNumber = findRowNumber(url, user, password, tableName, keyColumn, keyValue);
/*if (rowNumber > 0) {
System.out.println("关键键值 " + keyValue + " 在第 " + rowNumber + " 行。");
} else {
System.out.println("未找到关键键值 " + keyValue + " 的行。");
}*/
return rowNumber;
}
public static void main(String[] args) {
toFindRowNumber("10");
}
private static int findRowNumber(String url, String user, String password, String tableName, String keyColumn, String keyValue) {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
int rowNumber = -1;
try {
// 加载数据库驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 建立连接
conn = DriverManager.getConnection(url, user, password);
// 首先,检查关键键值是否存在于表中
String checkSql = "SELECT COUNT(*) FROM " + tableName + " WHERE " + keyColumn + " = ?";
pstmt = conn.prepareStatement(checkSql);
pstmt.setString(1, keyValue);
rs = pstmt.executeQuery();
if (rs.next() && rs.getInt(1) == 0) {
// 关键键值不存在
return -1;
}
// SQL查询,使用子查询来计算行号
String sql = "SELECT COUNT(*) + 1 AS row_num FROM " + tableName + " WHERE " + keyColumn + " < ? ORDER BY " + keyColumn + ";";
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, keyValue);
rs = pstmt.executeQuery();
// 获取行号
if (rs.next()) {
rowNumber = rs.getInt("row_num");
}
} catch (ClassNotFoundException e) {
System.out.println("JDBC Driver not found.");
e.printStackTrace();
} catch (SQLException e) {
System.out.println("Database access error.");
e.printStackTrace();
} finally {
// 关闭资源
try {
if (rs != null) rs.close();
if (pstmt != null) pstmt.close();
if (conn != null) conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return rowNumber;
}
}
*3. 目前使用的客户端计时限制方法需要额外开辟一个线程,这样才能使表示时间限制的int变量timeRemaining自动递减。源码如下:
import java.util.Timer;
import java.util.TimerTask;
public class TimerWithTimerTask {
public static int timeRemaining = 0;
private Timer timer;
public TimerWithTimerTask() {
//this.timeRemaining = initialTime;
this.timer = new Timer();
}
public void startCountdown() {
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
if (timeRemaining > 0) {
timeRemaining--;
System.out.printf("剩余时间: %02d:%02d\n", timeRemaining / 60, timeRemaining % 60);
} else {
System.out.println("时间到!");
timer.cancel();
}
}
}, 0, 1000);
}
public static void main(String[] args) {
TimerWithTimerTask timer = new TimerWithTimerTask();
timer.startCountdown();
}
}
只需给TimerWithTimerTask.timeRemaining赋值,就可以改变需要等待的时间。使用下面的两行代码将会开辟线程,实现该int变量随着时间的递减
TimerWithTimerTask timer = new TimerWithTimerTask(); timer.startCountdown();
(由于是线程处理,可以将timeRemaining设置为非静态,实现多个倒数计算器)
3.5 由于是在线程中运行,所以当timer.startCountdown()跑完前,即使关闭所有JavaFX生成的窗口也不会停止线程运行。以下是解决方法
其实窗口全部关闭是JavaFX的launch()语句跑完的标志,只需在launch()语句后使TimerWithTimerTask.timeRemaining=0即可,如果timeRemaining设置为非静态,也可以设置其他静态变量在TimerWithTimerTask类中,并作为线程结束的标志之一。
4.忘记密码功能模块不需要设置新的...Message类去传输,只用邮箱实现可以共用 (获取验证码)Message ,需要使用用户名实现可以将 (获取验证码)Message 和 (登录信息)Message 一起进行TCP传输。