控制台配置文件调整,验证码发送功能修复,添加启动时自动检测功能。
This commit is contained in:
75752
bash/hs_err_pid12840.log
Normal file
75752
bash/hs_err_pid12840.log
Normal file
File diff suppressed because it is too large
Load Diff
1223
bash/replay_pid12840.log
Normal file
1223
bash/replay_pid12840.log
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,14 +1,43 @@
|
||||
# 配置文件编码:UTF-8(关键,避免中文昵称乱码)
|
||||
# 邮件服务配置段(必须保留[EmailConfig]这个小节名,不能改)
|
||||
; AuthCenter 配置文件模板(INI格式)
|
||||
; 适配 smtp_auth_code 双校验逻辑,所有【】内为占位模板,需替换为实际有效值,注释可按需删除
|
||||
[GlobalConfig]
|
||||
; 日志输出级别:可选 DEBUG/INFO/WARN/ERROR,默认填INFO
|
||||
log_level=INFO
|
||||
; 服务心跳间隔(毫秒),默认500ms无需修改,保持默认即可
|
||||
service_heartbeat_interval=500
|
||||
|
||||
[EmailConfig]
|
||||
# 邮箱SMTP服务器(按需选,常用如下)
|
||||
# QQ邮箱:smtp.qq.com | 163邮箱:smtp.163.com | 网易企业邮:smtp.163.com
|
||||
smtp_host=smtp.qq.com
|
||||
# SMTP SSL端口(固定465,通用大部分邮箱)
|
||||
smtp_port=465
|
||||
# 发送方完整邮箱(比如 123456@qq.com)
|
||||
from_email=你的邮箱地址@qq.com
|
||||
# 邮箱SMTP授权码(不是登录密码!需去邮箱后台生成)
|
||||
smtp_auth_code=你的邮箱授权码
|
||||
# 发送方显示昵称(可选,可自定义)
|
||||
from_nickname=Winboll验证服务
|
||||
; 邮件SMTP服务器【必填】,示例:QQ邮箱=smtp.qq.com | 163邮箱=smtp.163.com | 企业邮箱按实际填写
|
||||
smtp_host=【填写SMTP服务器地址】
|
||||
; SMTP端口【必填】,推荐SSL端口465(兼容性强),普通端口25需服务器开放,默认填465
|
||||
smtp_port=【填写端口号,推荐465】
|
||||
; 发送方完整邮箱账号【必填】,格式为xxx@xxx.com
|
||||
send_email_account=【填写发送方完整邮箱地址】
|
||||
; 邮箱SMTP授权码【必填】,非登录密码,QQ/163邮箱需在设置中开启SMTP服务后生成
|
||||
smtp_auth_code=【填写邮箱SMTP授权码】
|
||||
; 发件人显示昵称【可选】,收件箱会显示该名称,不填默认显示邮箱账号
|
||||
from_nickname=【自定义发件人昵称,可留空】
|
||||
; 邮件连接超时时间(毫秒),默认5000ms无需修改
|
||||
smtp_connect_timeout=5000
|
||||
; 验证码邮件主题前缀【可选】,可自定义文案
|
||||
email_subject_prefix=【自定义邮件主题前缀,如AuthCenter认证中心】
|
||||
; 验证码邮件内容模板,{code}为固定占位符不可删,文本可微调
|
||||
verify_code_email_content=您的认证验证码为:{code},有效期5分钟,请及时使用,请勿泄露给他人!
|
||||
|
||||
[ServerConfig]
|
||||
; 远程服务器基础地址【可选】,本地测试填http://localhost:8080,跨设备填服务器局域网IP(如http://192.168.1.100:8080)
|
||||
server_base_url=【填写服务器地址,本地测试默认http://localhost:8080】
|
||||
|
||||
[VerifyCodeConfig]
|
||||
; 验证码长度,默认6位纯数字,无需修改
|
||||
verify_code_length=6
|
||||
; 验证码有效期(分钟),默认5分钟,无需修改
|
||||
verify_code_expire_minutes=5
|
||||
; 过期验证码清理间隔(分钟),默认1分钟,无需修改
|
||||
expire_code_clean_interval=1
|
||||
|
||||
[HttpServiceConfig]
|
||||
; HTTP服务监听端口,默认8080,若端口被占用可修改为其他未占用端口(如8081)
|
||||
http_server_port=【填写服务端口,默认8080】
|
||||
; HTTP服务启动超时时间(毫秒),默认3000ms无需修改
|
||||
http_start_timeout=3000
|
||||
|
||||
123
src/Main.java
123
src/Main.java
@@ -1,52 +1,95 @@
|
||||
import cc.winboll.LogUtils;
|
||||
import cc.winboll.auth.AuthCenterHttpService;
|
||||
import cc.winboll.auth.MailAuthUtils;
|
||||
import cc.winboll.util.ConsoleInputUtils;
|
||||
import cc.winboll.util.EnvInfoUtils;
|
||||
import cc.winboll.util.IniConfigUtils;
|
||||
import cc.winboll.util.ServerUtils;
|
||||
import cc.winboll.util.InitCheckUtils;
|
||||
import cc.winboll.util.EmailSendUtils;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 程序入口类,负责初始化运行环境检测与AuthCenter HTTP服务启动
|
||||
* 适配Java7语言规范,兼容Android API30运行环境,支持优雅停机
|
||||
* 启动参数规则:1. -detail(可选,显示详细环境信息) 2. 服务器地址(可选,覆盖默认)
|
||||
* 启动参数规则:1. -detail(可选,显示详细环境信息) 2. 服务器地址(可选,覆盖默认/INI配置)
|
||||
* 支持控制台输入交互,输入help查帮助、输入exit退出、其他指令提示未识别
|
||||
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
|
||||
* @Date 2026/01/14 00:00:00
|
||||
* @LastEditTime 2026/01/17 10:10:00
|
||||
* @LastEditTime 2026/01/18 10:00:00
|
||||
*/
|
||||
public class Main {
|
||||
// 全局静态属性(常量→变量,顺序清晰)
|
||||
private static final String TAG = "AuthCenterMain";
|
||||
private static final String DEFAULT_SERVER_URL = "http://localhost:8080";
|
||||
private static final String ARG_DETAIL = "-detail";
|
||||
private static final String INI_SERVER_SECTION = "ServerConfig";
|
||||
private static final String INI_SERVER_KEY = "server_base_url";
|
||||
// 新增:HTTP端口配置项,读取INI适配灵活性
|
||||
private static final String INI_HTTP_SECTION = "HttpServiceConfig";
|
||||
private static final String INI_HTTP_PORT_KEY = "http_server_port";
|
||||
private static final int DEFAULT_HTTP_PORT = 8080;
|
||||
private static AuthCenterHttpService httpService;
|
||||
private static int httpPort; // 全局HTTP端口变量
|
||||
|
||||
/**
|
||||
* 程序主入口方法,统一调度初始化、服务启动、常驻阻塞全流程
|
||||
* @param args 启动参数,支持-detail(详细环境)、自定义服务器地址
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
// 新增这1行:启动就加载项目根目录的config.ini,必须放在最前面
|
||||
IniConfigUtils.loadRootConfig();
|
||||
IniConfigUtils.loadRootConfig();
|
||||
LogUtils.d(TAG, "【函数调用】main(),传入参数:" + arrayToString(args));
|
||||
|
||||
boolean showDetailEnv = parseDetailArg(args);
|
||||
String serverUrl = parseServerUrlArg(args);
|
||||
String serverUrl = getFinalServerUrl(args);
|
||||
httpPort = getHttpPortFromConfig(); // 新增:读取HTTP端口配置
|
||||
|
||||
EnvInfoUtils.printEnvReport(showDetailEnv);
|
||||
initServerUtils(serverUrl);
|
||||
// 新增:先初始化邮件配置,保障邮件校验能读取到完整配置
|
||||
EmailSendUtils.initEmailConfig();
|
||||
|
||||
// 启动初始化校验(邮件+服务器)
|
||||
boolean initCheckPass = InitCheckUtils.checkAllInitConfig();
|
||||
if (!initCheckPass) {
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
System.out.println("Hello World!");
|
||||
|
||||
startAuthCenterHttpService();
|
||||
ConsoleInputUtils.initConsoleScanner();
|
||||
consoleBlockForService();
|
||||
|
||||
// 适配加固:退出循环后,兜底释放所有资源,形成闭环
|
||||
releaseAllResources();
|
||||
LogUtils.i(TAG, "【函数结束】main(),程序正常退出");
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增:从INI读取HTTP端口,无配置兜底默认8080
|
||||
*/
|
||||
private static int getHttpPortFromConfig() {
|
||||
LogUtils.d(TAG, "【函数调用】getHttpPortFromConfig(),读取HTTP服务端口配置");
|
||||
String portStr = IniConfigUtils.getConfigValue(INI_HTTP_SECTION, INI_HTTP_PORT_KEY);
|
||||
if (portStr == null || portStr.trim().isEmpty()) {
|
||||
LogUtils.i(TAG, "未读取到HTTP端口配置,使用默认端口:" + DEFAULT_HTTP_PORT);
|
||||
return DEFAULT_HTTP_PORT;
|
||||
}
|
||||
try {
|
||||
int port = Integer.parseInt(portStr.trim());
|
||||
if (port > 0 && port <= 65535) {
|
||||
LogUtils.i(TAG, "从INI读取HTTP端口成功:" + port);
|
||||
return port;
|
||||
} else {
|
||||
LogUtils.w(TAG, "HTTP端口配置非法,使用默认端口:" + DEFAULT_HTTP_PORT);
|
||||
return DEFAULT_HTTP_PORT;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogUtils.w(TAG, "HTTP端口配置解析失败,使用默认端口:" + DEFAULT_HTTP_PORT);
|
||||
return DEFAULT_HTTP_PORT;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析启动参数,判断是否输出详细环境信息
|
||||
* @param args 启动参数数组
|
||||
@@ -73,28 +116,49 @@ public class Main {
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析启动参数,提取自定义服务器地址,非-detail参数均视为服务器地址
|
||||
* 整合多来源服务器地址,优先级 启动参数 > INI配置 > 默认地址,适配config.ini
|
||||
* @param args 启动参数数组
|
||||
* @return 解析到的服务器地址,无则返回默认地址
|
||||
* @return 最终生效的服务器地址
|
||||
*/
|
||||
private static String getFinalServerUrl(String[] args) {
|
||||
LogUtils.d(TAG, "【函数调用】getFinalServerUrl(),整合服务器地址(启动参数>INI>默认)");
|
||||
String argUrl = parseServerUrlArg(args);
|
||||
if (argUrl != null && !argUrl.trim().isEmpty()) {
|
||||
LogUtils.i(TAG, "服务器地址优先级1:启动参数 → " + argUrl);
|
||||
return argUrl;
|
||||
}
|
||||
String iniUrl = IniConfigUtils.getConfigValue(INI_SERVER_SECTION, INI_SERVER_KEY);
|
||||
if (iniUrl != null && !iniUrl.trim().isEmpty()) {
|
||||
LogUtils.i(TAG, "服务器地址优先级2:INI配置 → " + iniUrl);
|
||||
return iniUrl;
|
||||
}
|
||||
LogUtils.i(TAG, "服务器地址优先级3:默认地址 → " + DEFAULT_SERVER_URL);
|
||||
return DEFAULT_SERVER_URL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从启动参数提取自定义服务器地址,非-detail参数均视为服务器地址
|
||||
* @param args 启动参数数组
|
||||
* @return 解析到的地址,无则返回null
|
||||
*/
|
||||
private static String parseServerUrlArg(String[] args) {
|
||||
LogUtils.d(TAG, "【函数调用】parseServerUrlArg(),入参args:" + arrayToString(args));
|
||||
if (args == null || args.length == 0) {
|
||||
LogUtils.d(TAG, "【函数返回】parseServerUrlArg(),无启动参数,返回默认地址:" + DEFAULT_SERVER_URL);
|
||||
return DEFAULT_SERVER_URL;
|
||||
LogUtils.d(TAG, "【函数返回】无启动参数,返回null");
|
||||
return null;
|
||||
}
|
||||
|
||||
for (String arg : args) {
|
||||
String trimArg = arg.trim();
|
||||
if (!ARG_DETAIL.equalsIgnoreCase(trimArg) && !trimArg.isEmpty()) {
|
||||
LogUtils.i(TAG, "【参数检测】匹配自定义服务器地址,覆盖默认值:" + trimArg);
|
||||
LogUtils.d(TAG, "【函数返回】parseServerUrlArg(),解析到地址,返回:" + trimArg);
|
||||
LogUtils.d(TAG, "【函数返回】解析到地址,返回:" + trimArg);
|
||||
return trimArg;
|
||||
}
|
||||
}
|
||||
|
||||
LogUtils.d(TAG, "【函数返回】parseServerUrlArg(),未解析到自定义地址,返回默认地址:" + DEFAULT_SERVER_URL);
|
||||
return DEFAULT_SERVER_URL;
|
||||
LogUtils.d(TAG, "【函数返回】未解析到自定义地址,返回null");
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -137,11 +201,10 @@ public class Main {
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化并启动AuthCenter HTTP服务,绑定8080端口监听,异常则退出程序
|
||||
* 初始化并启动AuthCenter HTTP服务,绑定配置端口监听,异常则退出程序
|
||||
*/
|
||||
private static void startAuthCenterHttpService() {
|
||||
LogUtils.d(TAG, "【函数调用】startAuthCenterHttpService(),开始启动HTTP服务");
|
||||
int httpPort = 8080;
|
||||
httpService = new AuthCenterHttpService(httpPort);
|
||||
|
||||
try {
|
||||
@@ -153,7 +216,6 @@ public class Main {
|
||||
String errMsg = "HTTP服务启动失败!端口 " + httpPort + " 可能被占用";
|
||||
System.err.println(errMsg);
|
||||
LogUtils.e(TAG, "【函数异常】startAuthCenterHttpService(),HTTP服务启动失败", e);
|
||||
// 启动失败时,兜底释放已初始化资源,避免残留
|
||||
ConsoleInputUtils.forceExit();
|
||||
releaseAllResources();
|
||||
System.exit(1);
|
||||
@@ -166,26 +228,22 @@ public class Main {
|
||||
*/
|
||||
private static void consoleBlockForService() {
|
||||
LogUtils.d(TAG, "【函数调用】consoleBlockForService(),开始注册关闭钩子与常驻阻塞");
|
||||
// 注册JVM关闭钩子,接收kill信号或exit指令执行优雅停机(kill -9 不触发)
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
LogUtils.i(TAG, "收到服务停止信号,执行优雅停机流程");
|
||||
// 适配加固:优先调用强制退出,确保状态同步
|
||||
@Override
|
||||
public void run() {
|
||||
LogUtils.i(TAG, "收到服务停止信号,执行优雅停机流程");
|
||||
ConsoleInputUtils.forceExit();
|
||||
ConsoleInputUtils.closeConsoleScanner();
|
||||
if (httpService != null && httpService.isRunning()) {
|
||||
httpService.stop();
|
||||
LogUtils.i(TAG, "HTTP服务已优雅停止");
|
||||
}
|
||||
}
|
||||
}));
|
||||
ConsoleInputUtils.closeConsoleScanner();
|
||||
if (httpService != null && httpService.isRunning()) {
|
||||
httpService.stop();
|
||||
LogUtils.i(TAG, "HTTP服务已优雅停止");
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
System.out.println("\n服务已常驻运行,输入exit可退出服务,或执行kill 对应Java进程号停机");
|
||||
// 低功耗无限阻塞,根据指令状态判断是否退出循环
|
||||
while (true) {
|
||||
try {
|
||||
// 适配加固:优先判断退出标识,减少无效调用,提速退出响应
|
||||
if (ConsoleInputUtils.isExit() || ConsoleInputUtils.checkConsoleCommand()) {
|
||||
break;
|
||||
}
|
||||
@@ -202,17 +260,16 @@ public class Main {
|
||||
}
|
||||
|
||||
/**
|
||||
* 兜底释放所有资源,适配加固后工具类,形成退出闭环(核心适配点)
|
||||
* 兜底释放所有资源,适配加固后工具类,形成退出闭环
|
||||
*/
|
||||
private static void releaseAllResources() {
|
||||
LogUtils.d(TAG, "【函数调用】releaseAllResources(),兜底释放所有服务资源");
|
||||
// 1. 停止HTTP服务
|
||||
if (httpService != null && httpService.isRunning()) {
|
||||
httpService.stop();
|
||||
LogUtils.i(TAG, "HTTP服务兜底停止完成");
|
||||
}
|
||||
// 2. 关闭控制台扫描器,彻底释放终端输入流(解决Termux阻塞关键)
|
||||
ConsoleInputUtils.closeConsoleScanner();
|
||||
MailAuthUtils.getInstance().shutdownScheduler();
|
||||
LogUtils.d(TAG, "【函数结束】releaseAllResources(),所有资源释放完成");
|
||||
}
|
||||
|
||||
|
||||
222
src/cc/winboll/auth/MailAuthUtils.java
Normal file
222
src/cc/winboll/auth/MailAuthUtils.java
Normal file
@@ -0,0 +1,222 @@
|
||||
package cc.winboll.auth;
|
||||
|
||||
import cc.winboll.LogUtils;
|
||||
import cc.winboll.util.EmailSendUtils;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 邮件验证码认证工具类,单例模式,统一管理验证码发送、存储、校验与过期清理
|
||||
* 适配Java7语法,兼容项目邮件工具类与Termux环境,支持验证码时效自动管控
|
||||
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
|
||||
* @Date 2026-01-17
|
||||
* @LastEditTime 2026-01-17
|
||||
*/
|
||||
public class MailAuthUtils {
|
||||
private static final String TAG = "MailAuthUtils";
|
||||
// 单例核心:静态私有实例 + 私有构造,volatile保证多线程可见性
|
||||
private static volatile MailAuthUtils instance;
|
||||
// 存储映射表:key=邮箱,value=验证码_过期时间戳(下划线分隔)
|
||||
private final Map<String, String> emailCodeExpireMap;
|
||||
// 验证码配置常量(可按需调整)
|
||||
private static final int CODE_LENGTH = 6;
|
||||
private static final int CODE_EXPIRE_MINUTES = 5; // 验证码有效期5分钟
|
||||
private static final Random random = new Random();
|
||||
// 定时清理线程池,后台自动清理过期验证码
|
||||
private final ScheduledExecutorService scheduler;
|
||||
|
||||
/**
|
||||
* 私有构造:禁止外部实例化,初始化映射表+定时清理任务
|
||||
*/
|
||||
private MailAuthUtils() {
|
||||
emailCodeExpireMap = new HashMap<String, String>();
|
||||
// 初始化定时任务:延迟1分钟启动,每1分钟执行1次清理,低消耗
|
||||
scheduler = Executors.newSingleThreadScheduledExecutor();
|
||||
scheduler.scheduleAtFixedRate(new ExpiredCodeCleanTask(), 1, 1, TimeUnit.MINUTES);
|
||||
LogUtils.d(TAG, "MailAuthUtils 初始化完成,定时清理任务已启动,验证码有效期" + CODE_EXPIRE_MINUTES + "分钟");
|
||||
}
|
||||
|
||||
/**
|
||||
* 单例获取方法:双重校验锁,线程安全+高效初始化
|
||||
* @return 全局唯一MailAuthUtils实例
|
||||
*/
|
||||
public static MailAuthUtils getInstance() {
|
||||
if (instance == null) {
|
||||
synchronized (MailAuthUtils.class) {
|
||||
if (instance == null) {
|
||||
instance = new MailAuthUtils();
|
||||
}
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 核心方法:发送邮箱验证码,发送成功存入<验证码_过期时间>并返回验证码
|
||||
* @param email 目标收件邮箱
|
||||
* @return 发送成功返回验证码,失败返回null
|
||||
*/
|
||||
public String sendVerifyCode(String email) {
|
||||
LogUtils.d(TAG, "sendVerifyCode 函数调用,目标邮箱:" + email);
|
||||
if (email == null || email.trim().isEmpty()) {
|
||||
LogUtils.w(TAG, "发送验证码失败:邮箱地址为空");
|
||||
return null;
|
||||
}
|
||||
String trimEmail = email.trim();
|
||||
// 1. 生成6位数字验证码
|
||||
String verifyCode = generateVerifyCode();
|
||||
// 2. 计算过期时间戳(当前时间+有效期,单位毫秒)
|
||||
long expireTime = System.currentTimeMillis() + CODE_EXPIRE_MINUTES * 60 * 1000L;
|
||||
// 3. 发送验证码邮件
|
||||
boolean sendResult = EmailSendUtils.sendVerifyCodeEmail(trimEmail, verifyCode);
|
||||
if (sendResult) {
|
||||
// 存储格式:验证码_过期时间戳
|
||||
emailCodeExpireMap.put(trimEmail, verifyCode + "_" + expireTime);
|
||||
LogUtils.i(TAG, "验证码发送成功|邮箱[" + trimEmail + "] 验证码[" + verifyCode + "] 有效期至" + CODE_EXPIRE_MINUTES + "分钟后");
|
||||
return verifyCode;
|
||||
} else {
|
||||
LogUtils.e(TAG, "验证码发送失败|邮箱:" + trimEmail);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 核心方法:校验邮箱与验证码,自动判断是否过期
|
||||
* @param email 待校验邮箱
|
||||
* @param code 待校验验证码
|
||||
* @return 匹配且未过期返回true,否则返回false
|
||||
*/
|
||||
public boolean checkVerifyCode(String email, String code) {
|
||||
LogUtils.d(TAG, "checkVerifyCode 函数调用,校验邮箱[" + email + "] 验证码[" + code + "]");
|
||||
// 1. 空值校验
|
||||
if (email == null || code == null || email.trim().isEmpty() || code.trim().isEmpty()) {
|
||||
LogUtils.w(TAG, "校验失败|邮箱或验证码为空");
|
||||
return false;
|
||||
}
|
||||
String trimEmail = email.trim();
|
||||
String trimCode = code.trim();
|
||||
String storeValue = emailCodeExpireMap.get(trimEmail);
|
||||
|
||||
// 2. 无对应记录校验
|
||||
if (storeValue == null || !storeValue.contains("_")) {
|
||||
LogUtils.w(TAG, "校验失败|邮箱[" + trimEmail + "] 无验证码记录或记录异常");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3. 拆分验证码与过期时间
|
||||
String[] codeExpire = storeValue.split("_", 2);
|
||||
if (codeExpire.length != 2) {
|
||||
emailCodeExpireMap.remove(trimEmail);
|
||||
LogUtils.w(TAG, "校验失败|邮箱[" + trimEmail + "] 记录格式异常,已清理无效记录");
|
||||
return false;
|
||||
}
|
||||
String storedCode = codeExpire[0];
|
||||
long expireTime;
|
||||
try {
|
||||
expireTime = Long.parseLong(codeExpire[1]);
|
||||
} catch (NumberFormatException e) {
|
||||
emailCodeExpireMap.remove(trimEmail);
|
||||
LogUtils.w(TAG, "校验失败|邮箱[" + trimEmail + "] 过期时间格式异常,已清理", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 4. 过期判断
|
||||
long currentTime = System.currentTimeMillis();
|
||||
if (currentTime > expireTime) {
|
||||
emailCodeExpireMap.remove(trimEmail);
|
||||
LogUtils.w(TAG, "校验失败|邮箱[" + trimEmail + "] 验证码已过期,已清理过期记录");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 5. 验证码匹配判断
|
||||
boolean match = trimCode.equals(storedCode);
|
||||
if (match) {
|
||||
emailCodeExpireMap.remove(trimEmail);
|
||||
LogUtils.i(TAG, "校验成功|邮箱[" + trimEmail + "] 验证码匹配且未过期,已清理记录");
|
||||
} else {
|
||||
LogUtils.w(TAG, "校验失败|邮箱[" + trimEmail + "] 验证码不匹配|存储码[" + storedCode + "] 输入码[" + trimCode + "]");
|
||||
}
|
||||
return match;
|
||||
}
|
||||
|
||||
/**
|
||||
* 辅助方法:生成指定长度纯数字验证码
|
||||
* @return 6位数字验证码
|
||||
*/
|
||||
private String generateVerifyCode() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < CODE_LENGTH; i++) {
|
||||
sb.append(random.nextInt(10));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 内部定时任务:清理过期验证码,避免内存堆积
|
||||
*/
|
||||
private class ExpiredCodeCleanTask implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
long currentTime = System.currentTimeMillis();
|
||||
int cleanCount = 0;
|
||||
// 迭代器遍历,支持安全删除
|
||||
for (Map.Entry<String, String> entry : emailCodeExpireMap.entrySet()) {
|
||||
String value = entry.getValue();
|
||||
if (value == null || !value.contains("_")) {
|
||||
emailCodeExpireMap.remove(entry.getKey());
|
||||
cleanCount++;
|
||||
continue;
|
||||
}
|
||||
String[] codeExpire = value.split("_", 2);
|
||||
if (codeExpire.length != 2) {
|
||||
emailCodeExpireMap.remove(entry.getKey());
|
||||
cleanCount++;
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
long expireTime = Long.parseLong(codeExpire[1]);
|
||||
if (currentTime > expireTime) {
|
||||
emailCodeExpireMap.remove(entry.getKey());
|
||||
cleanCount++;
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
emailCodeExpireMap.remove(entry.getKey());
|
||||
cleanCount++;
|
||||
}
|
||||
}
|
||||
if (cleanCount > 0) {
|
||||
LogUtils.d(TAG, "定时清理完成|本次清理过期/无效验证码记录共" + cleanCount + "条");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 兜底方法:关闭定时线程池,程序退出时调用,避免线程泄露
|
||||
* 可在Main类释放资源方法中调用
|
||||
*/
|
||||
public void shutdownScheduler() {
|
||||
if (scheduler != null && !scheduler.isShutdown()) {
|
||||
scheduler.shutdown();
|
||||
LogUtils.d(TAG, "定时清理线程池已关闭");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 公开方法:清空所有验证码记录(适配控制台手动清理指令)
|
||||
*/
|
||||
public void clearAllVerifyCode() {
|
||||
if (emailCodeExpireMap.isEmpty()) {
|
||||
LogUtils.d(TAG, "清空验证码记录:当前无任何验证码记录,无需清理");
|
||||
System.out.println("当前无验证码记录,无需清空");
|
||||
return;
|
||||
}
|
||||
int recordCount = emailCodeExpireMap.size();
|
||||
emailCodeExpireMap.clear();
|
||||
LogUtils.i(TAG, "已手动清空所有验证码记录,本次清空数量:" + recordCount + "条");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,24 @@
|
||||
package cc.winboll.util;
|
||||
|
||||
import cc.winboll.LogUtils;
|
||||
import cc.winboll.auth.MailAuthUtils;
|
||||
import java.util.Scanner;
|
||||
|
||||
/**
|
||||
* 控制台输入工具类,封装输入监听、指令处理、资源释放逻辑
|
||||
* 适配Java7语言规范,兼容Android Termux与标准JVM环境
|
||||
* 支持help查看帮助、exit退出服务、selftestmail邮件自测,预留指令扩展入口
|
||||
* 支持help/exit/selftestmail/clearverifycode/testserver 5大指令
|
||||
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
|
||||
* @Date 2026/01/14 00:00:00
|
||||
* @LastEditTime 2026/01/17 11:20:00
|
||||
* @LastEditTime 2026/01/17 17:00:00
|
||||
*/
|
||||
public class ConsoleInputUtils {
|
||||
private static final String TAG = "ConsoleInputUtils";
|
||||
public static final String CMD_HELP = "help";
|
||||
public static final String CMD_EXIT = "exit";
|
||||
public static final String CMD_SELF_TEST_MAIL = "selftestmail"; // 新增邮件自测指令
|
||||
public static final String CMD_SELF_TEST_MAIL = "selftestmail";
|
||||
public static final String CMD_CLEAR_VERIFY_CODE = "clearverifycode";
|
||||
public static final String CMD_TEST_SERVER = "testserver"; // 新增:服务器连通性测试指令
|
||||
private static Scanner scanner;
|
||||
private static volatile boolean isExit = false;
|
||||
private static boolean isScannerInit = false;
|
||||
@@ -32,8 +35,8 @@ public class ConsoleInputUtils {
|
||||
try {
|
||||
scanner = new Scanner(System.in);
|
||||
isScannerInit = true;
|
||||
// 提示新增指令
|
||||
System.out.println("\n💡 输入 " + CMD_HELP + " 查看帮助,输入 " + CMD_EXIT + " 退出服务,输入 " + CMD_SELF_TEST_MAIL + " 邮件自测");
|
||||
// 提示语补充 testserver 指令
|
||||
System.out.println("\n💡 输入 " + CMD_HELP + " 查看帮助,输入 " + CMD_EXIT + " 退出服务,输入 " + CMD_SELF_TEST_MAIL + " 邮件自测,输入 " + CMD_CLEAR_VERIFY_CODE + " 清空验证码记录,输入 " + CMD_TEST_SERVER + " 测试服务器连通性");
|
||||
LogUtils.d(TAG, "【函数结束】initConsoleScanner(),控制台输入扫描器初始化完成");
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "【函数异常】initConsoleScanner(),扫描器初始化失败", e);
|
||||
@@ -60,13 +63,17 @@ public class ConsoleInputUtils {
|
||||
String input = scanner.nextLine().trim();
|
||||
LogUtils.d(TAG, "检测到控制台输入指令:" + input);
|
||||
|
||||
// 指令分发-新增selftestmail分支
|
||||
// 指令分发-新增 testserver 分支
|
||||
if (CMD_HELP.equalsIgnoreCase(input)) {
|
||||
handleHelpCmd();
|
||||
} else if (CMD_EXIT.equalsIgnoreCase(input)) {
|
||||
handleExitCmd();
|
||||
} else if (CMD_SELF_TEST_MAIL.equalsIgnoreCase(input)) {
|
||||
handleSelfTestMailCmd();
|
||||
} else if (CMD_CLEAR_VERIFY_CODE.equalsIgnoreCase(input)) {
|
||||
handleClearVerifyCodeCmd();
|
||||
} else if (CMD_TEST_SERVER.equalsIgnoreCase(input)) {
|
||||
handleTestServerCmd();
|
||||
} else if (!input.isEmpty()) {
|
||||
handleCustomCmd(input);
|
||||
}
|
||||
@@ -105,21 +112,54 @@ public class ConsoleInputUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增:处理邮件自测指令,自动生成测试码,发送到发送方邮箱
|
||||
* 处理邮件自测指令,自动生成测试码,发送到发送方邮箱
|
||||
*/
|
||||
private static void handleSelfTestMailCmd() {
|
||||
LogUtils.d(TAG, "【指令处理】执行selftestmail指令,启动邮件自测流程");
|
||||
System.out.println("\n🔍 开始邮件配置自测,正在初始化邮件服务...");
|
||||
// 接收初始化结果,失败直接提示,不执行后续自测
|
||||
boolean initResult = EmailSendUtils.initEmailConfig();
|
||||
if (!initResult) {
|
||||
System.err.println("❌ 邮件配置初始化失败,自测终止!请先完善INI文件[EmailConfig]配置");
|
||||
LogUtils.w(TAG, "邮件初始化失败,自测流程终止");
|
||||
return;
|
||||
}
|
||||
String testCode = String.valueOf((int)((Math.random() * 900000) + 100000));
|
||||
EmailSendUtils.sendSelfTestEmail(testCode);
|
||||
}
|
||||
private static void handleSelfTestMailCmd() {
|
||||
LogUtils.d(TAG, "【指令处理】执行selftestmail指令,启动邮件自测流程");
|
||||
System.out.println("\n🔍 开始邮件配置自测,正在初始化邮件服务...");
|
||||
boolean initResult = EmailSendUtils.initEmailConfig();
|
||||
if (!initResult) {
|
||||
System.err.println("❌ 邮件配置初始化失败,自测终止!请先完善INI文件[EmailConfig]配置");
|
||||
LogUtils.w(TAG, "邮件初始化失败,自测流程终止");
|
||||
return;
|
||||
}
|
||||
String testCode = String.valueOf((int)((Math.random() * 900000) + 100000));
|
||||
EmailSendUtils.sendSelfTestEmail(testCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理清空验证码指令,调用MailAuthUtils清空所有记录
|
||||
*/
|
||||
private static void handleClearVerifyCodeCmd() {
|
||||
LogUtils.d(TAG, "【指令处理】执行clearverifycode指令,清空所有验证码记录");
|
||||
try {
|
||||
MailAuthUtils.getInstance().clearAllVerifyCode();
|
||||
System.out.println("✅ 所有验证码记录已清空完成");
|
||||
LogUtils.i(TAG, "全部验证码记录清空成功");
|
||||
} catch (Exception e) {
|
||||
System.err.println("❌ 验证码记录清空失败");
|
||||
LogUtils.e(TAG, "清空验证码记录异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增:处理服务器连通性测试指令,调用ServerUtils一键测试
|
||||
*/
|
||||
private static void handleTestServerCmd() {
|
||||
LogUtils.d(TAG, "【指令处理】执行testserver指令,启动服务器连通性测试");
|
||||
System.out.println("\n🔍 开始服务器连通性测试...");
|
||||
try {
|
||||
boolean testResult = ServerUtils.testServerConnectivity();
|
||||
if (testResult) {
|
||||
System.out.println("✅ 服务器连通性测试全部通过!");
|
||||
} else {
|
||||
System.err.println("❌ 服务器连通性测试失败,请查看日志排查问题");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.err.println("❌ 服务器连通性测试异常");
|
||||
LogUtils.e(TAG, "服务器连通性测试执行异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理自定义指令:预留扩展入口,便于后续新增功能
|
||||
@@ -127,7 +167,8 @@ public class ConsoleInputUtils {
|
||||
*/
|
||||
private static void handleCustomCmd(String cmd) {
|
||||
LogUtils.w(TAG, "【指令处理】未识别指令:" + cmd + ",输入help可查看支持的指令");
|
||||
System.out.println("❌ 未识别指令[" + cmd + "],输入help查看帮助,输入exit退出服务,输入selftestmail邮件自测");
|
||||
// 提示语补充 testserver 指令
|
||||
System.out.println("❌ 未识别指令[" + cmd + "],输入help查看帮助,输入exit退出服务,输入selftestmail邮件自测,输入clearverifycode清空验证码记录,输入testserver测试服务器连通性");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,7 +15,7 @@ import javax.mail.internet.MimeMessage;
|
||||
* 适配javax.mail依赖,原生兼容Java7语法与Android API30环境
|
||||
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
|
||||
* @Date 2026-01-15 00:00:00
|
||||
* @LastEditTime 2026-01-17 11:40:00
|
||||
* @LastEditTime 2026-01-17 23:00:00
|
||||
*/
|
||||
public class EmailSendUtils {
|
||||
private static final String TAG = "EmailSendUtils";
|
||||
@@ -23,22 +23,31 @@ public class EmailSendUtils {
|
||||
private static Session mailSession;
|
||||
private static String fromEmail;
|
||||
private static String fromNickname;
|
||||
private static String emailSubjectPrefix;
|
||||
private static String verifyCodeContentTemplate;
|
||||
|
||||
/**
|
||||
* 初始化邮件配置(增强校验,返回初始化结果,便于外部判断)
|
||||
* 初始化邮件配置(增强校验+双键名兼容+修复Java7内部类变量final问题)
|
||||
* @return 配置完整且初始化成功返回true,否则false
|
||||
*/
|
||||
public static boolean initEmailConfig() {
|
||||
LogUtils.d(TAG, "initEmailConfig 函数调用,开始初始化邮件配置");
|
||||
// 读取INI配置,增强日志提示
|
||||
String smtpHost = IniConfigUtils.getConfigValue("EmailConfig", "smtp_host");
|
||||
String smtpPort = IniConfigUtils.getConfigValue("EmailConfig", "smtp_port");
|
||||
fromEmail = IniConfigUtils.getConfigValue("EmailConfig", "from_email");
|
||||
final String smtpAuthCode = IniConfigUtils.getConfigValue("EmailConfig", "smtp_auth_code");
|
||||
fromEmail = IniConfigUtils.getConfigValue("EmailConfig", "send_email_account");
|
||||
// 修复核心:给smtpAuthCode加final,适配Java7内部类访问规则
|
||||
final String smtpAuthCode;
|
||||
String tempAuthCode = IniConfigUtils.getConfigValue("EmailConfig", "send_email_auth_code");
|
||||
if (isEmpty(tempAuthCode)) {
|
||||
tempAuthCode = IniConfigUtils.getConfigValue("EmailConfig", "smtp_auth_code");
|
||||
LogUtils.w(TAG, "未读取到send_email_auth_code,兜底读取smtp_auth_code配置");
|
||||
}
|
||||
smtpAuthCode = tempAuthCode; // 赋值给final变量
|
||||
fromNickname = IniConfigUtils.getConfigValue("EmailConfig", "from_nickname");
|
||||
emailSubjectPrefix = IniConfigUtils.getConfigValue("EmailConfig", "email_subject_prefix");
|
||||
verifyCodeContentTemplate = IniConfigUtils.getConfigValue("EmailConfig", "verify_code_email_content");
|
||||
|
||||
LogUtils.d(TAG, "读取INI邮件配置:smtpHost[" + smtpHost + "] smtpPort[" + smtpPort + "] fromEmail[" + fromEmail + "]");
|
||||
// 增强空值提示,明确缺失项
|
||||
if (isEmpty(smtpHost)) {
|
||||
LogUtils.e(TAG, "邮件核心配置缺失:smtp_host 未配置");
|
||||
return false;
|
||||
@@ -48,15 +57,16 @@ public class EmailSendUtils {
|
||||
return false;
|
||||
}
|
||||
if (isEmpty(fromEmail)) {
|
||||
LogUtils.e(TAG, "邮件核心配置缺失:from_email 未配置");
|
||||
LogUtils.e(TAG, "邮件核心配置缺失:send_email_account 未配置");
|
||||
return false;
|
||||
}
|
||||
if (isEmpty(smtpAuthCode)) {
|
||||
LogUtils.e(TAG, "邮件核心配置缺失:smtp_auth_code 未配置");
|
||||
LogUtils.e(TAG, "邮件核心配置缺失:send_email_auth_code / smtp_auth_code 均未配置");
|
||||
return false;
|
||||
}
|
||||
if (isEmpty(emailSubjectPrefix)) emailSubjectPrefix = "【AuthCenter 认证中心】";
|
||||
if (isEmpty(verifyCodeContentTemplate)) verifyCodeContentTemplate = "您的认证验证码为:{code},有效期5分钟,请及时使用,请勿泄露给他人!";
|
||||
|
||||
// 组装SMTP配置(适配Java7)
|
||||
mailProps.put("mail.smtp.host", smtpHost);
|
||||
mailProps.put("mail.smtp.port", smtpPort);
|
||||
mailProps.put("mail.smtp.auth", "true");
|
||||
@@ -65,7 +75,6 @@ public class EmailSendUtils {
|
||||
mailProps.put("mail.transport.protocol", "smtp");
|
||||
|
||||
try {
|
||||
// 会话创建加异常捕获,防止配置错误导致崩溃
|
||||
mailSession = Session.getInstance(mailProps, new Authenticator() {
|
||||
@Override
|
||||
protected PasswordAuthentication getPasswordAuthentication() {
|
||||
@@ -73,7 +82,7 @@ public class EmailSendUtils {
|
||||
}
|
||||
});
|
||||
mailSession.setDebug(false);
|
||||
LogUtils.i(TAG, "邮件发送配置初始化完成,发送方邮箱:" + fromEmail);
|
||||
LogUtils.i(TAG, "邮件发送配置初始化完成,发送方邮箱:" + fromEmail + " 发送方昵称:" + (fromNickname == null ? "默认昵称" : fromNickname));
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "邮件会话创建失败,检查配置是否正确", e);
|
||||
@@ -82,7 +91,7 @@ public class EmailSendUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送验证码邮件(核心方法,供ServerUtils调用)
|
||||
* 发送验证码邮件(核心方法,适配INI主题/内容模板)
|
||||
* @param toEmail 接收方邮箱
|
||||
* @param verifyCode 验证码
|
||||
* @return 发送成功返回true,失败返回false
|
||||
@@ -100,10 +109,11 @@ public class EmailSendUtils {
|
||||
|
||||
try {
|
||||
MimeMessage message = new MimeMessage(mailSession);
|
||||
message.setFrom(new InternetAddress(fromEmail, fromNickname == null ? "Winboll验证" : fromNickname, "UTF-8"));
|
||||
String finalNickname = isEmpty(fromNickname) ? fromEmail.split("@")[0] : fromNickname;
|
||||
message.setFrom(new InternetAddress(fromEmail, finalNickname, "UTF-8"));
|
||||
message.addRecipient(Message.RecipientType.TO, new InternetAddress(toEmail));
|
||||
message.setSubject("【Winboll验证】您的验证码", "UTF-8");
|
||||
String content = String.format("您好!您的验证代码为:%s\n该验证码5分钟内有效,请及时使用,请勿泄露给他人。", verifyCode);
|
||||
message.setSubject(emailSubjectPrefix + " 验证码通知", "UTF-8");
|
||||
String content = verifyCodeContentTemplate.replace("{code}", verifyCode);
|
||||
message.setText(content, "UTF-8");
|
||||
Transport.send(message);
|
||||
LogUtils.i(TAG, "验证码邮件发送成功,收件人:" + toEmail);
|
||||
@@ -125,7 +135,6 @@ public class EmailSendUtils {
|
||||
LogUtils.w(TAG, "发送方邮箱或测试码为空,自测失败");
|
||||
return false;
|
||||
}
|
||||
// 先判断会话是否就绪,不就绪直接提示
|
||||
if (mailSession == null) {
|
||||
LogUtils.e(TAG, "邮件会话未初始化,自测终止,请先完成INI邮件配置");
|
||||
System.err.println("❌ 邮件会话未初始化!请先检查INI文件的[EmailConfig]配置项是否完整");
|
||||
@@ -134,9 +143,10 @@ public class EmailSendUtils {
|
||||
|
||||
try {
|
||||
MimeMessage message = new MimeMessage(mailSession);
|
||||
message.setFrom(new InternetAddress(fromEmail, fromNickname == null ? "Winboll验证" : fromNickname, "UTF-8"));
|
||||
String finalNickname = isEmpty(fromNickname) ? fromEmail.split("@")[0] : fromNickname;
|
||||
message.setFrom(new InternetAddress(fromEmail, finalNickname, "UTF-8"));
|
||||
message.addRecipient(Message.RecipientType.TO, new InternetAddress(fromEmail));
|
||||
message.setSubject("【Winboll邮件自测】配置连通性测试", "UTF-8");
|
||||
message.setSubject(emailSubjectPrefix + " 配置自测通知", "UTF-8");
|
||||
String content = String.format("邮件发送配置自测成功!\n自测校验码:%s\n当前发送方邮箱:%s\n说明:邮件服务配置正常,可正常发送验证码。", testCode, fromEmail);
|
||||
message.setText(content, "UTF-8");
|
||||
Transport.send(message);
|
||||
|
||||
@@ -1,75 +1,60 @@
|
||||
package cc.winboll.util;
|
||||
|
||||
import cc.winboll.LogUtils;
|
||||
import java.util.Scanner;
|
||||
|
||||
/**
|
||||
* 服务帮助信息工具类,统一封装帮助信息打印逻辑
|
||||
* 适配Java7语言规范,兼容Android API30环境,支持全局复用
|
||||
* 帮助信息工具类,统一管理服务帮助内容,适配控制台展示
|
||||
* 兼容Java7,清晰罗列功能与指令,便于快速查阅
|
||||
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
|
||||
* @Date 2026/01/14 00:00:00
|
||||
* @LastEditTime 2026/01/16 23:10:00
|
||||
* @Date 2026/01/14
|
||||
* @LastEditTime 2026/01/17
|
||||
*/
|
||||
public class HelpInfoUtils {
|
||||
private static final String TAG = "HelpInfoUtils";
|
||||
// 服务核心常量(统一维护,便于全局修改)
|
||||
private static final int HTTP_SERVICE_PORT = 8080;
|
||||
private static final String DEFAULT_SERVER_URL = "http://localhost:8080";
|
||||
private static final String HEALTH_CHECK_API = "GET http://localhost:" + HTTP_SERVICE_PORT + "/authcenter/ping";
|
||||
|
||||
/**
|
||||
* 打印完整服务帮助信息,全局统一调用入口
|
||||
* 打印完整帮助信息(供help指令调用)
|
||||
*/
|
||||
public static void printFullHelpInfo() {
|
||||
LogUtils.d(TAG, "【函数调用】printFullHelpInfo(),开始打印服务帮助信息");
|
||||
System.out.println("\n================================ 服务帮助信息 ================================");
|
||||
printStartArgsInfo();
|
||||
System.out.println("\n=============== Winboll AuthCenter 帮助中心 ===============");
|
||||
printBasicInfo();
|
||||
printConsoleCmdInfo();
|
||||
printServiceCoreInfo();
|
||||
printStopServiceInfo();
|
||||
System.out.println("============================================================================\n");
|
||||
LogUtils.d(TAG, "【函数结束】printFullHelpInfo(),服务帮助信息打印完成");
|
||||
printNoticeInfo();
|
||||
System.out.println("===========================================================\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印启动参数说明
|
||||
* 基础服务信息
|
||||
*/
|
||||
private static void printStartArgsInfo() {
|
||||
System.out.println("1. 启动参数说明");
|
||||
System.out.println(" -detail :启动时输出详细运行环境检测报告(默认输出精简报告)");
|
||||
System.out.println(" 自定义地址 :启动时传入服务器地址,覆盖默认值(示例:java Main http://192.168.1.100:8080)");
|
||||
System.out.println(" 组合使用 :参数顺序无要求(示例:java Main -detail http://192.168.1.100:8080)");
|
||||
private static void printBasicInfo() {
|
||||
System.out.println("1. 服务基础信息");
|
||||
System.out.println(" 服务名称:AuthCenter 认证中心");
|
||||
System.out.println(" 核心能力:邮件验证码发送、校验、过期管理");
|
||||
System.out.println(" 兼容环境:Android Termux / 标准JVM");
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印控制台指令说明
|
||||
* 控制台指令说明(核心:补全所有指令)
|
||||
*/
|
||||
// 找到 printConsoleCmdInfo 方法,新增selftestmail说明
|
||||
private static void printConsoleCmdInfo() {
|
||||
System.out.println("2. 控制台指令说明");
|
||||
System.out.println(" help :调用展示本帮助信息");
|
||||
System.out.println(" exit :执行优雅停机,关闭服务并释放资源(推荐手动停止方式)");
|
||||
System.out.println(" selftestmail :邮件服务自测,发送测试邮件到发送方自身邮箱");
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印核心服务配置信息
|
||||
*/
|
||||
private static void printServiceCoreInfo() {
|
||||
System.out.println("3. 核心服务信息");
|
||||
System.out.println(" HTTP服务端口 :" + HTTP_SERVICE_PORT);
|
||||
System.out.println(" 健康检查接口 :" + HEALTH_CHECK_API);
|
||||
System.out.println(" 默认服务器地址:" + DEFAULT_SERVER_URL);
|
||||
private static void printConsoleCmdInfo() {
|
||||
System.out.println("2. 控制台指令说明(大小写不敏感)");
|
||||
System.out.println(" help :调用展示本帮助信息");
|
||||
System.out.println(" exit :优雅停机,释放资源后退出服务");
|
||||
System.out.println(" selftestmail :邮件服务自测,发送测试邮件到发送方邮箱");
|
||||
System.out.println(" clearverifycode :手动清空所有已存储的验证码记录");
|
||||
System.out.println(" testserver :一键测试服务器基础地址+验证码接口连通性"); // 新增该行
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印服务停止方式说明
|
||||
* 注意事项
|
||||
*/
|
||||
private static void printStopServiceInfo() {
|
||||
System.out.println("4. 停止服务说明");
|
||||
System.out.println(" 方式1:控制台输入 exit 指令(最推荐,优雅停机释放所有资源)");
|
||||
System.out.println(" 方式2:执行 kill 对应Java进程号(推荐,触发优雅停机释放资源)");
|
||||
System.out.println(" 方式3:强制中断(kill -9),可能造成资源未释放,不推荐");
|
||||
private static void printNoticeInfo() {
|
||||
System.out.println("3. 注意事项");
|
||||
System.out.println(" ① 执行selftestmail前,需确保config.ini中[EmailConfig]配置完整");
|
||||
System.out.println(" ② 验证码默认有效期5分钟,超时自动清理,也可手动clearverifycode");
|
||||
System.out.println(" ③ 退出服务优先用exit指令,避免资源泄露");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
150
src/cc/winboll/util/InitCheckUtils.java
Normal file
150
src/cc/winboll/util/InitCheckUtils.java
Normal file
@@ -0,0 +1,150 @@
|
||||
package cc.winboll.util;
|
||||
|
||||
import cc.winboll.LogUtils;
|
||||
|
||||
/**
|
||||
* 启动初始化校验工具类,一键校验邮件+服务器核心配置,保障服务启动基础条件
|
||||
* 适配Java7语法,兼容Android API30环境,校验失败直接提示并终止服务
|
||||
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
|
||||
* @Date 2026/01/17 21:00:00
|
||||
* @LastEditTime 2026/01/18 11:00:00
|
||||
*/
|
||||
public class InitCheckUtils {
|
||||
private static final String TAG = "InitCheckUtils";
|
||||
// 服务器连通性测试超时兜底(和ServerUtils保持一致)
|
||||
private static final int CHECK_TIMEOUT_TIP = 5000;
|
||||
// 优化:本地自服务地址常量,兼容带/不带斜杠场景,彻底解决匹配失败
|
||||
private static final String LOCAL_SERVER_1 = "http://localhost:8080";
|
||||
private static final String LOCAL_SERVER_1_SLASH = "http://localhost:8080/";
|
||||
private static final String LOCAL_SERVER_2 = "http://127.0.0.1:8080";
|
||||
private static final String LOCAL_SERVER_2_SLASH = "http://127.0.0.1:8080/";
|
||||
// 新增:邮件校验开关(true=强制校验,false=跳过,调试时可改false)
|
||||
private static final boolean FORCE_MAIL_CHECK = true;
|
||||
|
||||
/**
|
||||
* 启动核心入口:一键校验 邮件配置完整性 + 服务器配置+连通性,全通过才允许服务启动
|
||||
* @return true=所有校验通过,false=任意一项失败
|
||||
*/
|
||||
public static boolean checkAllInitConfig() {
|
||||
LogUtils.i(TAG, "==================== 启动配置校验开始 ====================");
|
||||
// 优化:支持跳过邮件校验,适配调试场景
|
||||
boolean mailCheck = FORCE_MAIL_CHECK ? checkEmailConfig() : true;
|
||||
boolean serverCheck = checkServerConfig();
|
||||
|
||||
if (mailCheck && serverCheck) {
|
||||
LogUtils.i(TAG, "==================== 所有启动配置校验通过 ====================");
|
||||
System.out.println("\n✅ 初始化校验全部通过,服务可正常启动");
|
||||
return true;
|
||||
} else {
|
||||
LogUtils.e(TAG, "==================== 启动配置校验失败,服务终止 ====================");
|
||||
System.err.println("\n❌ 初始化校验失败,请修复配置后重新启动");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验1:邮件核心配置完整性(必填项非空+配置格式基础校验)
|
||||
* @return true=邮件配置合格,false=不合格
|
||||
*/
|
||||
private static boolean checkEmailConfig() {
|
||||
LogUtils.d(TAG, "开始校验【邮件服务配置】");
|
||||
boolean result = true;
|
||||
// 读取核心必填项,和EmailConfig配置项一一对应
|
||||
String smtpHost = IniConfigUtils.getConfigValue("EmailConfig", "smtp_host");
|
||||
String smtpPort = IniConfigUtils.getConfigValue("EmailConfig", "smtp_port");
|
||||
String sendAccount = IniConfigUtils.getConfigValue("EmailConfig", "send_email_account");
|
||||
String authCode = IniConfigUtils.getConfigValue("EmailConfig", "smtp_auth_code");
|
||||
|
||||
// 1. 非空校验(核心必填项)
|
||||
if (isEmpty(smtpHost)) {
|
||||
LogUtils.e(TAG, "邮件配置缺失:[EmailConfig] smtp_host 未配置");
|
||||
result = false;
|
||||
}
|
||||
if (isEmpty(smtpPort)) {
|
||||
LogUtils.e(TAG, "邮件配置缺失:[EmailConfig] smtp_port 未配置");
|
||||
result = false;
|
||||
}
|
||||
if (isEmpty(sendAccount)) {
|
||||
LogUtils.e(TAG, "邮件配置缺失:[EmailConfig] send_email_account 未配置");
|
||||
result = false;
|
||||
}
|
||||
if (isEmpty(authCode)) {
|
||||
LogUtils.e(TAG, "邮件配置缺失:[EmailConfig] smtp_auth_code 未配置");
|
||||
result = false;
|
||||
}
|
||||
|
||||
// 2. 基础格式校验(提升配置正确性)
|
||||
if (!isEmpty(sendAccount) && !sendAccount.contains("@")) {
|
||||
LogUtils.e(TAG, "邮件配置错误:send_email_account 格式非法,需为完整邮箱地址");
|
||||
result = false;
|
||||
}
|
||||
if (!isEmpty(smtpPort)) {
|
||||
try {
|
||||
Integer.parseInt(smtpPort);
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "邮件配置错误:smtp_port 需为数字端口号");
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (result) {
|
||||
LogUtils.i(TAG, "邮件服务配置校验通过");
|
||||
} else {
|
||||
System.err.println("⚠️ 邮件配置问题指引:1. 检查config.ini[EmailConfig]小节 2. 授权码需开启SMTP后生成 3. 端口填465(SSL)");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验2:服务器配置完整性+连通性(地址非空+一键连通测试)
|
||||
* 优化:兼容本地地址带/不带斜杠,自身服务未启动时跳过连通校验,远程地址正常校验
|
||||
* @return true=服务器配置合格,false=不合格
|
||||
*/
|
||||
private static boolean checkServerConfig() {
|
||||
LogUtils.d(TAG, "开始校验【服务器交互配置】");
|
||||
boolean result = true;
|
||||
String serverUrl = ServerUtils.getServerBaseUrl();
|
||||
|
||||
// 1. 服务器地址配置校验
|
||||
if (isEmpty(serverUrl)) {
|
||||
LogUtils.e(TAG, "服务器配置缺失:未初始化服务器地址,请检查启动参数/INI[ServerConfig]");
|
||||
result = false;
|
||||
return result;
|
||||
}
|
||||
if (!serverUrl.startsWith("http://") && !serverUrl.startsWith("https://")) {
|
||||
LogUtils.e(TAG, "服务器配置错误:地址需带http/https协议头");
|
||||
result = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
// 核心优化:兼容本地地址带/不带斜杠,4种场景都能跳过连通校验
|
||||
if (LOCAL_SERVER_1.equals(serverUrl) || LOCAL_SERVER_1_SLASH.equals(serverUrl)
|
||||
|| LOCAL_SERVER_2.equals(serverUrl) || LOCAL_SERVER_2_SLASH.equals(serverUrl)) {
|
||||
LogUtils.i(TAG, "检测为本地自服务地址,跳过连通性测试(服务启动后自动生效)");
|
||||
result = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
// 2. 非本地自服务,执行连通性测试
|
||||
LogUtils.d(TAG, "开始服务器连通性测试,地址:" + serverUrl + "(超时时间" + CHECK_TIMEOUT_TIP + "ms)");
|
||||
boolean connectable = ServerUtils.testServerConnectivity();
|
||||
if (!connectable) {
|
||||
LogUtils.e(TAG, "服务器连通性测试失败");
|
||||
System.err.println("⚠️ 服务器连通问题指引:1. 检查IP+端口是否正确 2. 服务器是否启动 3. 设备是否在同一局域网");
|
||||
result = false;
|
||||
}
|
||||
|
||||
if (result) {
|
||||
LogUtils.i(TAG, "服务器配置+连通性校验通过");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 空值校验工具,适配多参数判断
|
||||
*/
|
||||
private static boolean isEmpty(String str) {
|
||||
return str == null || str.trim().isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,19 +2,21 @@ package cc.winboll.util;
|
||||
|
||||
import cc.winboll.LogUtils;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 纯服务器交互工具类,仅负责封装HTTP请求、调用远程接口,无监听能力
|
||||
* 适配Java7语法,兼容Android API30环境
|
||||
* 适配Java7语法,兼容Android API30环境,新增服务器连通性一键测试
|
||||
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
|
||||
* @Date 2026/01/16 00:00:00
|
||||
* @LastEditTime 2026/01/16 00:45:00
|
||||
* @LastEditTime 2026/01/17 16:00:00
|
||||
*/
|
||||
public class ServerUtils {
|
||||
// 基础属性
|
||||
@@ -22,25 +24,42 @@ public class ServerUtils {
|
||||
private static final int CONNECT_TIMEOUT = 5000;
|
||||
private static final int READ_TIMEOUT = 5000;
|
||||
private static String serverBaseUrl;
|
||||
|
||||
|
||||
/**
|
||||
* 初始化服务器基础地址
|
||||
*/
|
||||
public static void initServerUrl(String url) {
|
||||
LogUtils.d(TAG, "调用initServerUrl,传入地址:" + url);
|
||||
serverBaseUrl = url;
|
||||
if (url == null || url.trim().isEmpty()) {
|
||||
LogUtils.w(TAG, "服务器地址为空,初始化失败");
|
||||
return;
|
||||
}
|
||||
serverBaseUrl = url.trim().endsWith("/") ? url.trim() : url.trim() + "/";
|
||||
LogUtils.d(TAG, "服务器地址初始化完成:" + serverBaseUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送验证码请求(POST)
|
||||
* 优化版:发送验证码请求(POST),增强校验+兜底提示
|
||||
*/
|
||||
public static String sendVerifyCode(String email) {
|
||||
LogUtils.d(TAG, "调用sendVerifyCode,邮箱参数:" + email);
|
||||
String url = serverBaseUrl + "/api/sendVerifyCode";
|
||||
// 1. 前置校验:服务器地址未初始化
|
||||
if (serverBaseUrl == null || serverBaseUrl.trim().isEmpty()) {
|
||||
LogUtils.e(TAG, "发送验证码失败:服务器地址未初始化,请先调用initServerUrl()");
|
||||
return null;
|
||||
}
|
||||
// 2. 前置校验:邮箱空值/格式基础校验
|
||||
if (email == null || email.trim().isEmpty() || !email.contains("@")) {
|
||||
LogUtils.w(TAG, "发送验证码失败:邮箱地址为空或格式不合法");
|
||||
return null;
|
||||
}
|
||||
String trimEmail = email.trim();
|
||||
String url = serverBaseUrl + "api/sendVerifyCode";
|
||||
Map<String, String> params = new HashMap<String, String>();
|
||||
params.put("email", email);
|
||||
return sendPostRequest(url, params);
|
||||
params.put("email", trimEmail);
|
||||
String result = sendPostRequest(url, params);
|
||||
LogUtils.d(TAG, "验证码发送请求执行完成,邮箱[" + trimEmail + "] 接口响应:" + (result == null ? "null" : result));
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -48,10 +67,18 @@ public class ServerUtils {
|
||||
*/
|
||||
public static String verifyCode(String email, String code) {
|
||||
LogUtils.d(TAG, "调用verifyCode,参数:邮箱[" + email + "] 验证码[" + code + "]");
|
||||
String url = serverBaseUrl + "/api/verifyCode";
|
||||
if (serverBaseUrl == null || serverBaseUrl.trim().isEmpty()) {
|
||||
LogUtils.e(TAG, "校验验证码失败:服务器地址未初始化");
|
||||
return null;
|
||||
}
|
||||
if (email == null || email.trim().isEmpty() || code == null || code.trim().isEmpty()) {
|
||||
LogUtils.w(TAG, "校验验证码失败:邮箱或验证码为空");
|
||||
return null;
|
||||
}
|
||||
String url = serverBaseUrl + "api/verifyCode";
|
||||
Map<String, String> params = new HashMap<String, String>();
|
||||
params.put("email", email);
|
||||
params.put("code", code);
|
||||
params.put("email", email.trim());
|
||||
params.put("code", code.trim());
|
||||
return sendPostRequest(url, params);
|
||||
}
|
||||
|
||||
@@ -60,10 +87,18 @@ public class ServerUtils {
|
||||
*/
|
||||
public static String submitAppPublicKey(String email, String publicKey) {
|
||||
LogUtils.d(TAG, "调用submitAppPublicKey,参数:邮箱[" + email + "] 公钥[" + publicKey + "]");
|
||||
String url = serverBaseUrl + "/api/submitPublicKey";
|
||||
if (serverBaseUrl == null || serverBaseUrl.trim().isEmpty()) {
|
||||
LogUtils.e(TAG, "提交公钥失败:服务器地址未初始化");
|
||||
return null;
|
||||
}
|
||||
if (email == null || email.trim().isEmpty() || publicKey == null || publicKey.trim().isEmpty()) {
|
||||
LogUtils.w(TAG, "提交公钥失败:邮箱或公钥为空");
|
||||
return null;
|
||||
}
|
||||
String url = serverBaseUrl + "api/submitPublicKey";
|
||||
Map<String, String> params = new HashMap<String, String>();
|
||||
params.put("email", email);
|
||||
params.put("appPublicKey", publicKey);
|
||||
params.put("email", email.trim());
|
||||
params.put("appPublicKey", publicKey.trim());
|
||||
return sendPostRequest(url, params);
|
||||
}
|
||||
|
||||
@@ -72,12 +107,89 @@ public class ServerUtils {
|
||||
*/
|
||||
public static String sendPingRequest(String encryptPingData) {
|
||||
LogUtils.d(TAG, "调用sendPingRequest,加密数据:" + encryptPingData);
|
||||
String url = serverBaseUrl + "/api/heartbeat/ping";
|
||||
if (serverBaseUrl == null || serverBaseUrl.trim().isEmpty()) {
|
||||
LogUtils.e(TAG, "发送心跳失败:服务器地址未初始化");
|
||||
return null;
|
||||
}
|
||||
if (encryptPingData == null || encryptPingData.trim().isEmpty()) {
|
||||
LogUtils.w(TAG, "发送心跳失败:加密数据为空");
|
||||
return null;
|
||||
}
|
||||
String url = serverBaseUrl + "api/heartbeat/ping";
|
||||
Map<String, String> params = new HashMap<String, String>();
|
||||
params.put("encryptData", encryptPingData);
|
||||
params.put("encryptData", encryptPingData.trim());
|
||||
return sendPostRequest(url, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增核心:服务器连通性一键测试,快速检测地址是否可达、基础接口是否可用
|
||||
* @return 测试成功返回true,失败返回false,日志输出详细原因
|
||||
*/
|
||||
public static boolean testServerConnectivity() {
|
||||
LogUtils.i(TAG, "开始执行服务器连通性一键测试");
|
||||
// 1. 先校验基础地址
|
||||
if (serverBaseUrl == null || serverBaseUrl.trim().isEmpty()) {
|
||||
LogUtils.e(TAG, "连通性测试失败:服务器地址未初始化,请先调用initServerUrl()");
|
||||
System.err.println("❌ 连通性测试失败:未初始化服务器地址");
|
||||
return false;
|
||||
}
|
||||
// 2. 测试基础地址可达性(优先测根地址,无接口也能判断连通)
|
||||
String testUrl = serverBaseUrl;
|
||||
HttpURLConnection conn = null;
|
||||
try {
|
||||
URL url = new URL(testUrl);
|
||||
conn = (HttpURLConnection) url.openConnection();
|
||||
conn.setRequestMethod("GET");
|
||||
conn.setConnectTimeout(CONNECT_TIMEOUT);
|
||||
conn.setReadTimeout(READ_TIMEOUT);
|
||||
conn.setRequestProperty("Charset", "UTF-8");
|
||||
|
||||
int responseCode = conn.getResponseCode();
|
||||
// 响应码200-399都算连通成功(3xx重定向也代表地址可达)
|
||||
boolean isReachable = responseCode >= 200 && responseCode < 400;
|
||||
if (isReachable) {
|
||||
LogUtils.i(TAG, "✅ 服务器基础地址连通成功,响应码:" + responseCode);
|
||||
System.out.println("✅ 服务器基础地址连通成功:" + testUrl);
|
||||
// 3. 额外测试验证码接口基础可用性(可选,补充提示)
|
||||
String apiTestUrl = serverBaseUrl + "api/sendVerifyCode";
|
||||
LogUtils.d(TAG, "额外测试验证码接口可达性:" + apiTestUrl);
|
||||
HttpURLConnection apiConn = (HttpURLConnection) new URL(apiTestUrl).openConnection();
|
||||
apiConn.setRequestMethod("OPTIONS"); // OPTIONS请求不触发业务,仅测接口是否存在
|
||||
apiConn.setConnectTimeout(CONNECT_TIMEOUT);
|
||||
int apiCode = apiConn.getResponseCode();
|
||||
if (apiCode >= 200 && apiCode < 400) {
|
||||
LogUtils.i(TAG, "✅ 验证码接口可达性测试成功");
|
||||
System.out.println("✅ 验证码接口可达性测试成功");
|
||||
} else {
|
||||
LogUtils.w(TAG, "⚠️ 验证码接口可达性测试提示,响应码:" + apiCode + "(接口可能未部署/未开放OPTIONS)");
|
||||
System.out.println("⚠️ 验证码接口响应码:" + apiCode + ",请确认接口是否部署");
|
||||
}
|
||||
apiConn.disconnect();
|
||||
return true;
|
||||
} else {
|
||||
LogUtils.e(TAG, "❌ 服务器连通失败,响应码:" + responseCode + ",响应信息:" + conn.getResponseMessage());
|
||||
System.err.println("❌ 服务器连通失败,响应码:" + responseCode);
|
||||
return false;
|
||||
}
|
||||
} catch (java.net.ConnectException e) {
|
||||
LogUtils.e(TAG, "❌ 服务器连通失败:无法连接到地址,可能IP/端口错误或网络不通", e);
|
||||
System.err.println("❌ 连通失败:无法连接到 " + testUrl + ",请检查IP、端口和网络");
|
||||
return false;
|
||||
} catch (java.net.SocketTimeoutException e) {
|
||||
LogUtils.e(TAG, "❌ 服务器连通失败:请求超时,网络延迟过高或服务器未响应", e);
|
||||
System.err.println("❌ 连通失败:请求超时(超时时间" + CONNECT_TIMEOUT + "ms)");
|
||||
return false;
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "❌ 服务器连通测试异常", e);
|
||||
System.err.println("❌ 连通测试异常:" + e.getMessage());
|
||||
return false;
|
||||
} finally {
|
||||
if (conn != null) {
|
||||
conn.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前初始化的服务器基础地址
|
||||
*/
|
||||
@@ -87,12 +199,12 @@ public class ServerUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用POST请求封装
|
||||
* 通用POST请求封装(优化参数拼接+URL编码,兼容空参数场景)
|
||||
*/
|
||||
private static String sendPostRequest(String urlStr, Map<String, String> params) {
|
||||
LogUtils.d(TAG, "调用sendPostRequest,请求地址:" + urlStr);
|
||||
if (urlStr == null || params == null) {
|
||||
LogUtils.w(TAG, "POST请求参数为空");
|
||||
if (urlStr == null || params == null || params.isEmpty()) {
|
||||
LogUtils.w(TAG, "POST请求失败:地址为空或无有效参数");
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -105,11 +217,16 @@ public class ServerUtils {
|
||||
conn.setReadTimeout(READ_TIMEOUT);
|
||||
conn.setDoOutput(true);
|
||||
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
|
||||
conn.setRequestProperty("Charset", "UTF-8"); // 新增编码指定,避免乱码
|
||||
|
||||
// 拼接参数
|
||||
// 拼接参数,补充URL编码,过滤空键空值
|
||||
StringBuilder paramStr = new StringBuilder();
|
||||
for (Map.Entry<String, String> entry : params.entrySet()) {
|
||||
paramStr.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
|
||||
String key = entry.getKey();
|
||||
String value = entry.getValue();
|
||||
if (key != null && value != null) {
|
||||
paramStr.append(key).append("=").append(URLEncoder.encode(value, "UTF-8")).append("&");
|
||||
}
|
||||
}
|
||||
if (paramStr.length() > 0) {
|
||||
paramStr.deleteCharAt(paramStr.length() - 1);
|
||||
@@ -120,18 +237,23 @@ public class ServerUtils {
|
||||
os.flush();
|
||||
os.close();
|
||||
|
||||
// 优化:捕获非200响应的内容,便于排查问题
|
||||
InputStream inputStream = conn.getResponseCode() == HttpURLConnection.HTTP_OK ? conn.getInputStream() : conn.getErrorStream();
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
|
||||
StringBuilder response = new StringBuilder();
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
response.append(line);
|
||||
}
|
||||
br.close();
|
||||
inputStream.close();
|
||||
|
||||
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
|
||||
StringBuilder response = new StringBuilder();
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
response.append(line);
|
||||
}
|
||||
br.close();
|
||||
LogUtils.d(TAG, "POST请求成功,响应内容:" + response.toString());
|
||||
return response.toString();
|
||||
} else {
|
||||
LogUtils.w(TAG, "POST请求失败,响应码:" + conn.getResponseCode());
|
||||
LogUtils.w(TAG, "POST请求失败,响应码:" + conn.getResponseCode() + " 响应内容:" + response.toString());
|
||||
return response.toString(); // 返回错误响应,便于上层排查
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "POST请求异常", e);
|
||||
|
||||
Reference in New Issue
Block a user