| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929 |
- <!DOCTYPE html>
- <html lang="zh-CN">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Java后台手机验证码处理</title>
- <style>
- * {
- margin: 0;
- padding: 0;
- box-sizing: border-box;
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
- }
- body {
- background: linear-gradient(135deg, #1e3c72, #2a5298);
- color: #333;
- line-height: 1.6;
- padding: 20px;
- min-height: 100vh;
- }
- .container {
- max-width: 1200px;
- margin: 0 auto;
- }
- header {
- text-align: center;
- margin-bottom: 40px;
- color: white;
- padding: 30px;
- background: rgba(255, 255, 255, 0.1);
- border-radius: 15px;
- box-shadow: 0 8px 25px rgba(0, 0, 0, 0.2);
- backdrop-filter: blur(10px);
- }
- h1 {
- font-size: 2.8rem;
- margin-bottom: 15px;
- text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
- }
- .subtitle {
- font-size: 1.2rem;
- opacity: 0.9;
- max-width: 800px;
- margin: 0 auto;
- }
- .content {
- display: grid;
- grid-template-columns: 1fr 1fr;
- gap: 30px;
- margin-bottom: 40px;
- }
- @media (max-width: 768px) {
- .content {
- grid-template-columns: 1fr;
- }
- }
- .card {
- background: white;
- border-radius: 12px;
- padding: 25px;
- box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
- transition: transform 0.3s, box-shadow 0.3s;
- }
- .card:hover {
- transform: translateY(-5px);
- box-shadow: 0 15px 30px rgba(0, 0, 0, 0.2);
- }
- .card h2 {
- color: #1e3c72;
- margin-bottom: 20px;
- padding-bottom: 10px;
- border-bottom: 2px solid #4a90e2;
- display: flex;
- align-items: center;
- }
- .card h2 i {
- margin-right: 10px;
- font-size: 1.5rem;
- }
- .input-group {
- margin-bottom: 20px;
- }
- label {
- display: block;
- margin-bottom: 8px;
- font-weight: 600;
- color: #444;
- }
- input, textarea, select {
- width: 100%;
- padding: 12px;
- border: 1px solid #ddd;
- border-radius: 6px;
- font-size: 16px;
- transition: all 0.3s;
- }
- textarea {
- min-height: 120px;
- resize: vertical;
- font-family: 'Courier New', monospace;
- }
- input:focus, textarea:focus, select:focus {
- border-color: #4a90e2;
- outline: none;
- box-shadow: 0 0 0 2px rgba(74, 144, 226, 0.2);
- }
- .btn-group {
- display: flex;
- gap: 10px;
- margin-top: 20px;
- }
- button {
- padding: 12px 20px;
- border: none;
- border-radius: 6px;
- font-size: 16px;
- font-weight: 600;
- cursor: pointer;
- transition: all 0.3s;
- flex: 1;
- display: flex;
- align-items: center;
- justify-content: center;
- }
- button i {
- margin-right: 8px;
- }
- .send-btn {
- background: #4a90e2;
- color: white;
- }
- .send-btn:hover {
- background: #3a7bc8;
- transform: translateY(-2px);
- }
- .verify-btn {
- background: #2ecc71;
- color: white;
- }
- .verify-btn:hover {
- background: #27ae60;
- transform: translateY(-2px);
- }
- .reset-btn {
- background: #95a5a6;
- color: white;
- }
- .reset-btn:hover {
- background: #7f8c8d;
- transform: translateY(-2px);
- }
- .code-block {
- background: #2d3748;
- color: #e2e8f0;
- padding: 25px;
- border-radius: 10px;
- font-family: 'Consolas', 'Courier New', monospace;
- overflow-x: auto;
- margin-top: 20px;
- box-shadow: inset 0 2px 10px rgba(0, 0, 0, 0.3);
- line-height: 1.5;
- }
- .code-block h3 {
- color: #4a90e2;
- margin-bottom: 15px;
- font-size: 1.3rem;
- }
- .code-comment {
- color: #a0aec0;
- font-style: italic;
- }
- .code-keyword {
- color: #63b3ed;
- }
- .code-string {
- color: #68d391;
- }
- .code-method {
- color: #fbb6ce;
- }
- .code-class {
- color: #f6ad55;
- }
- .code-number {
- color: #f6e05e;
- }
- .explanation {
- margin-top: 40px;
- background: white;
- border-radius: 12px;
- padding: 30px;
- box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
- }
- .explanation h2 {
- color: #1e3c72;
- margin-bottom: 20px;
- padding-bottom: 10px;
- border-bottom: 2px solid #4a90e2;
- }
- .info-box {
- background: #e8f4fd;
- border-left: 4px solid #4a90e2;
- padding: 20px;
- margin: 20px 0;
- border-radius: 0 10px 10px 0;
- }
- .warning-box {
- background: #fff5f5;
- border-left: 4px solid #e74c3c;
- padding: 20px;
- margin: 20px 0;
- border-radius: 0 10px 10px 0;
- }
- footer {
- text-align: center;
- margin-top: 40px;
- color: white;
- padding: 20px;
- opacity: 0.9;
- }
- .result {
- margin-top: 20px;
- padding: 15px;
- border-radius: 8px;
- display: none;
- }
- .success {
- border-left: 4px solid #2ecc71;
- background: #f0fff4;
- }
- .error {
- border-left: 4px solid #e74c3c;
- background: #fff5f5;
- }
- .response-area {
- margin-top: 20px;
- }
- .response-area h3 {
- margin-bottom: 10px;
- color: #444;
- }
- .response-content {
- background: #f8f9fa;
- border: 1px solid #e9ecef;
- border-radius: 6px;
- padding: 15px;
- min-height: 150px;
- font-family: 'Courier New', monospace;
- white-space: pre-wrap;
- overflow-x: auto;
- }
- .verification-form {
- display: flex;
- flex-direction: column;
- gap: 15px;
- }
- .code-input-group {
- display: flex;
- gap: 10px;
- align-items: center;
- }
- .code-input {
- flex: 1;
- }
- .countdown {
- color: #e74c3c;
- font-weight: bold;
- min-width: 100px;
- text-align: center;
- }
- .step {
- display: flex;
- margin-bottom: 30px;
- background: white;
- border-radius: 10px;
- overflow: hidden;
- box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
- }
- .step-number {
- background: #4a90e2;
- color: white;
- font-size: 2rem;
- font-weight: bold;
- padding: 20px;
- display: flex;
- align-items: center;
- justify-content: center;
- min-width: 80px;
- }
- .step-content {
- padding: 20px;
- flex: 1;
- }
- .flow-diagram {
- display: flex;
- flex-direction: column;
- align-items: center;
- margin: 30px 0;
- }
- .flow-step {
- background: white;
- border-radius: 8px;
- padding: 15px;
- margin: 10px 0;
- width: 80%;
- text-align: center;
- box-shadow: 0 3px 10px rgba(0, 0, 0, 0.1);
- position: relative;
- }
- .flow-step:not(:last-child):after {
- content: "↓";
- position: absolute;
- bottom: -25px;
- left: 50%;
- transform: translateX(-50%);
- font-size: 20px;
- color: #4a90e2;
- }
- .method-comparison {
- display: grid;
- grid-template-columns: 1fr 1fr;
- gap: 20px;
- margin-top: 20px;
- }
- @media (max-width: 768px) {
- .method-comparison {
- grid-template-columns: 1fr;
- }
- }
- .method-card {
- background: #f8f9fa;
- border-radius: 8px;
- padding: 20px;
- border: 1px solid #e9ecef;
- }
- .method-card h4 {
- color: #4a90e2;
- margin-bottom: 10px;
- }
- </style>
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
- </head>
- <body>
- <div class="container">
- <header>
- <h1>Java后台手机验证码处理</h1>
- <p class="subtitle">演示Java后台处理手机验证码的完整流程,包括生成、发送、验证和安全性考虑</p>
- </header>
- <div class="content">
- <div class="card">
- <h2><i class="fas fa-mobile-alt"></i> 验证码测试</h2>
- <div class="verification-form">
- <div class="input-group">
- <label for="phone">手机号码:</label>
- <input type="tel" id="phone" placeholder="请输入11位手机号码" maxlength="11" value="13800138000">
- </div>
- <div class="input-group">
- <label for="code">验证码:</label>
- <div class="code-input-group">
- <input type="text" id="code" class="code-input" placeholder="请输入6位验证码" maxlength="6">
- <button class="send-btn" id="send-btn">发送验证码</button>
- </div>
- <div class="countdown" id="countdown"></div>
- </div>
- <div class="btn-group">
- <button class="verify-btn" onclick="verifyCode()"><i class="fas fa-check-circle"></i> 验证验证码</button>
- <button class="reset-btn" onclick="resetForm()"><i class="fas fa-redo"></i> 重置</button>
- </div>
- </div>
- <div class="response-area">
- <h3>验证结果:</h3>
- <div class="response-content" id="verify-result">
- 验证结果将显示在这里...
- </div>
- </div>
- <div id="verify-status" class="result"></div>
- </div>
- <div class="card">
- <h2><i class="fas fa-code"></i> Java 核心代码</h2>
- <div class="code-block">
- <h3>验证码服务类</h3>
- <pre><code><span class="code-keyword">import</span> org.springframework.stereotype.Service;
- <span class="code-keyword">import</span> java.util.Random;
- <span class="code-keyword">import</span> java.util.concurrent.ConcurrentHashMap;
- <span class="code-keyword">import</span> java.util.concurrent.TimeUnit;
- <span class="code-comment">/**
- * 手机验证码服务
- */</span>
- @Service
- <span class="code-keyword">public class</span> <span class="code-class">SmsCodeService</span> {
- <span class="code-comment">// 存储验证码,key: 手机号, value: 验证码和过期时间</span>
- <span class="code-keyword">private final</span> ConcurrentHashMap<String, CodeInfo> codeCache =
- <span class="code-keyword">new</span> ConcurrentHashMap<>();
- <span class="code-comment">// 验证码有效期(分钟)</span>
- <span class="code-keyword">private static final int</span> CODE_EXPIRE_MINUTES = <span class="code-number">5</span>;
- <span class="code-comment">// 验证码长度</span>
- <span class="code-keyword">private static final int</span> CODE_LENGTH = <span class="code-number">6</span>;
- <span class="code-comment">// 发送间隔(秒)</span>
- <span class="code-keyword">private static final int</span> SEND_INTERVAL_SECONDS = <span
- class="code-number">60</span>;
- <span class="code-comment">/**
- * 生成验证码
- */</span>
- <span class="code-keyword">public</span> String <span class="code-method">generateCode</span>() {
- Random random = <span class="code-keyword">new</span> Random();
- StringBuilder sb = <span class="code-keyword">new</span> StringBuilder();
- <span class="code-keyword">for</span> (<span class="code-keyword">int</span> i = <span
- class="code-number">0</span>; i < CODE_LENGTH; i++) {
- sb.append(random.nextInt(<span class="code-number">10</span>));
- }
- <span class="code-keyword">return</span> sb.toString();
- }
- <span class="code-comment">/**
- * 发送验证码
- */</span>
- <span class="code-keyword">public</span> boolean <span class="code-method">sendCode</span>(String phone) {
- <span class="code-comment">// 检查发送频率</span>
- <span class="code-keyword">if</span> (isTooFrequent(phone)) {
- <span class="code-keyword">return false</span>;
- }
- <span class="code-comment">// 生成验证码</span>
- String code = generateCode();
- <span class="code-comment">// 存储验证码信息</span>
- CodeInfo codeInfo = <span class="code-keyword">new</span> CodeInfo(code,
- System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(CODE_EXPIRE_MINUTES));
- codeCache.put(phone, codeInfo);
- <span class="code-comment">// 记录发送时间</span>
- recordSendTime(phone);
- <span class="code-comment">// 调用短信服务发送验证码(这里模拟发送)</span>
- <span class="code-keyword">return</span> sendSms(phone, code);
- }
- <span class="code-comment">/**
- * 验证验证码
- */</span>
- <span class="code-keyword">public</span> boolean <span class="code-method">verifyCode</span>(String phone, String inputCode) {
- CodeInfo codeInfo = codeCache.get(phone);
- <span class="code-keyword">if</span> (codeInfo == <span class="code-keyword">null</span>) {
- <span class="code-keyword">return false</span>; <span class="code-comment">// 验证码不存在</span>
- }
- <span class="code-comment">// 检查是否过期</span>
- <span class="code-keyword">if</span> (System.currentTimeMillis() > codeInfo.getExpireTime()) {
- codeCache.remove(phone); <span class="code-comment">// 移除过期验证码</span>
- <span class="code-keyword">return false</span>;
- }
- <span class="code-comment">// 验证码是否正确</span>
- <span class="code-keyword">if</span> (codeInfo.getCode().equals(inputCode)) {
- codeCache.remove(phone); <span class="code-comment">// 验证成功后移除验证码</span>
- <span class="code-keyword">return true</span>;
- }
- <span class="code-keyword">return false</span>;
- }
- <span class="code-comment">/**
- * 检查发送频率
- */</span>
- <span class="code-keyword">private</span> boolean <span class="code-method">isTooFrequent</span>(String phone) {
- <span class="code-comment">// 实现发送频率检查逻辑</span>
- <span class="code-comment">// 这里简化实现,实际应该存储发送时间并检查</span>
- <span class="code-keyword">return false</span>;
- }
- <span class="code-comment">/**
- * 记录发送时间
- */</span>
- <span class="code-keyword">private void</span> <span class="code-method">recordSendTime</span>(String phone) {
- <span class="code-comment">// 记录发送时间,用于频率控制</span>
- }
- <span class="code-comment">/**
- * 发送短信(模拟实现)
- */</span>
- <span class="code-keyword">private</span> boolean <span class="code-method">sendSms</span>(String phone, String code) {
- <span class="code-comment">// 这里模拟发送短信</span>
- System.out.println(<span class="code-string">"发送短信到 "</span> + phone + <span
- class="code-string">": 验证码是 "</span> + code);
- <span class="code-comment">// 实际项目中这里会调用短信服务商的API</span>
- <span class="code-comment">// 例如阿里云短信服务、腾讯云短信服务等</span>
- <span class="code-keyword">return true</span>;
- }
- <span class="code-comment">/**
- * 验证码信息类
- */</span>
- <span class="code-keyword">private static class</span> <span class="code-class">CodeInfo</span> {
- <span class="code-keyword">private final</span> String code;
- <span class="code-keyword">private final long</span> expireTime;
- <span class="code-keyword">public</span> <span class="code-class">CodeInfo</span>(String code, long expireTime) {
- <span class="code-keyword">this</span>.code = code;
- <span class="code-keyword">this</span>.expireTime = expireTime;
- }
- <span class="code-keyword">public</span> String <span class="code-method">getCode</span>() {
- <span class="code-keyword">return</span> code;
- }
- <span class="code-keyword">public long</span> <span class="code-method">getExpireTime</span>() {
- <span class="code-keyword">return</span> expireTime;
- }
- }
- }</code></pre>
- </div>
- </div>
- </div>
- <div class="step">
- <div class="step-number">1</div>
- <div class="step-content">
- <h3>验证码生成与发送</h3>
- <p>Java后台生成6位数字验证码,并通过短信服务发送给用户。</p>
- <div class="code-block">
- <pre><code><span class="code-comment">// 生成6位数字验证码</span>
- <span class="code-keyword">public</span> String <span class="code-method">generateCode</span>() {
- Random random = <span class="code-keyword">new</span> Random();
- StringBuilder sb = <span class="code-keyword">new</span> StringBuilder();
- <span class="code-keyword">for</span> (<span class="code-keyword">int</span> i = <span class="code-number">0</span>; i < <span
- class="code-number">6</span>; i++) {
- sb.append(random.nextInt(<span class="code-number">10</span>));
- }
- <span class="code-keyword">return</span> sb.toString();
- }
- <span class="code-comment">// 发送验证码</span>
- <span class="code-keyword">public</span> boolean <span class="code-method">sendCode</span>(String phone) {
- String code = generateCode();
- <span class="code-comment">// 存储验证码(设置5分钟过期)</span>
- codeCache.put(phone, <span class="code-keyword">new</span> CodeInfo(code,
- System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(<span class="code-number">5</span>)));
- <span class="code-comment">// 调用短信服务发送</span>
- <span class="code-keyword">return</span> sendSms(phone, code);
- }</code></pre>
- </div>
- </div>
- </div>
- <div class="step">
- <div class="step-number">2</div>
- <div class="step-content">
- <h3>验证码验证</h3>
- <p>用户提交验证码后,后台进行验证,包括检查是否存在、是否过期、是否正确。</p>
- <div class="code-block">
- <pre><code><span class="code-comment">// 验证验证码</span>
- <span class="code-keyword">public</span> boolean <span class="code-method">verifyCode</span>(String phone, String inputCode) {
- CodeInfo codeInfo = codeCache.get(phone);
- <span class="code-comment">// 检查验证码是否存在</span>
- <span class="code-keyword">if</span> (codeInfo == <span class="code-keyword">null</span>) {
- <span class="code-keyword">return false</span>;
- }
- <span class="code-comment">// 检查是否过期</span>
- <span class="code-keyword">if</span> (System.currentTimeMillis() > codeInfo.getExpireTime()) {
- codeCache.remove(phone);
- <span class="code-keyword">return false</span>;
- }
- <span class="code-comment">// 检查验证码是否正确</span>
- <span class="code-keyword">if</span> (codeInfo.getCode().equals(inputCode)) {
- codeCache.remove(phone); <span class="code-comment">// 验证成功后移除</span>
- <span class="code-keyword">return true</span>;
- }
- <span class="code-keyword">return false</span>;
- }</code></pre>
- </div>
- </div>
- </div>
- <div class="flow-diagram">
- <div class="flow-step">用户请求发送验证码</div>
- <div class="flow-step">后端生成验证码并存储</div>
- <div class="flow-step">调用短信服务发送验证码</div>
- <div class="flow-step">用户输入验证码提交</div>
- <div class="flow-step">后端验证验证码</div>
- <div class="flow-step">返回验证结果</div>
- </div>
- <div class="explanation">
- <h2><i class="fas fa-info-circle"></i> Java验证码处理详解</h2>
- <div class="method-comparison">
- <div class="method-card">
- <h4>存储方案选择</h4>
- <ul>
- <li><strong>内存存储</strong>:简单快速,适合单机应用</li>
- <li><strong>Redis</strong>:分布式支持,自动过期,性能优秀</li>
- <li><strong>数据库</strong>:持久化存储,适合重要业务场景</li>
- <li><strong>Ehcache</strong>:本地缓存,性能较好</li>
- </ul>
- </div>
- <div class="method-card">
- <h4>安全性考虑</h4>
- <ul>
- <li><strong>频率限制</strong>:防止恶意发送验证码</li>
- <li><strong>IP限制</strong>:限制同一IP的发送次数</li>
- <li><strong>验证码复杂度</strong>:适当长度的数字或字母数字组合</li>
- <li><strong>时效性</strong>:设置合理的过期时间</li>
- </ul>
- </div>
- </div>
- <div class="info-box">
- <h3><i class="fas fa-lightbulb"></i> 最佳实践</h3>
- <ul>
- <li>使用线程安全的ConcurrentHashMap或Redis存储验证码</li>
- <li>设置合理的验证码有效期(通常5-10分钟)</li>
- <li>实现发送频率限制,防止短信轰炸</li>
- <li>验证成功后立即删除验证码,防止重复使用</li>
- <li>记录发送日志,便于排查问题</li>
- <li>使用专业的短信服务商,确保送达率</li>
- </ul>
- </div>
- <div class="warning-box">
- <h3><i class="fas fa-exclamation-triangle"></i> 注意事项</h3>
- <ul>
- <li>不要在前端生成验证码,必须在后端生成</li>
- <li>验证码不能过于简单,避免被暴力破解</li>
- <li>生产环境不要使用System.out打印验证码</li>
- <li>考虑短信服务商调用失败的重试机制</li>
- <li>注意验证码存储的内存泄漏问题</li>
- </ul>
- </div>
- <h3><i class="fas fa-cogs"></i> 完整Controller示例</h3>
- <div class="code-block">
- <pre><code><span class="code-keyword">import</span> org.springframework.beans.factory.annotation.Autowired;
- <span class="code-keyword">import</span> org.springframework.web.bind.annotation.*;
- @RestController
- @RequestMapping(<span class="code-string">"/api/sms"</span>)
- <span class="code-keyword">public class</span> <span class="code-class">SmsController</span> {
- @Autowired
- <span class="code-keyword">private</span> SmsCodeService smsCodeService;
- <span class="code-comment">/**
- * 发送验证码
- */</span>
- @PostMapping(<span class="code-string">"/send"</span>)
- <span class="code-keyword">public</span> ApiResult<String> <span class="code-method">sendCode</span>(@RequestBody SendCodeRequest request) {
- <span class="code-comment">// 验证手机号格式</span>
- <span class="code-keyword">if</span> (!isValidPhone(request.getPhone())) {
- <span class="code-keyword">return</span> ApiResult.error(<span class="code-string">"手机号格式不正确"</span>);
- }
- <span class="code-comment">// 发送验证码</span>
- boolean success = smsCodeService.sendCode(request.getPhone());
- <span class="code-keyword">if</span> (success) {
- <span class="code-keyword">return</span> ApiResult.success(<span class="code-string">"验证码发送成功"</span>);
- } <span class="code-keyword">else</span> {
- <span class="code-keyword">return</span> ApiResult.error(<span class="code-string">"验证码发送失败,请稍后重试"</span>);
- }
- }
- <span class="code-comment">/**
- * 验证验证码
- */</span>
- @PostMapping(<span class="code-string">"/verify"</span>)
- <span class="code-keyword">public</span> ApiResult<String> <span class="code-method">verifyCode</span>(@RequestBody VerifyCodeRequest request) {
- boolean isValid = smsCodeService.verifyCode(request.getPhone(), request.getCode());
- <span class="code-keyword">if</span> (isValid) {
- <span class="code-keyword">return</span> ApiResult.success(<span class="code-string">"验证码正确"</span>);
- } <span class="code-keyword">else</span> {
- <span class="code-keyword">return</span> ApiResult.error(<span class="code-string">"验证码错误或已过期"</span>);
- }
- }
- <span class="code-comment">/**
- * 验证手机号格式
- */</span>
- <span class="code-keyword">private</span> boolean <span class="code-method">isValidPhone</span>(String phone) {
- <span class="code-comment">// 简单的手机号格式验证</span>
- <span class="code-keyword">return</span> phone != <span class="code-keyword">null</span> && phone.matches(<span
- class="code-string">"^1[3-9]\\d{9}$"</span>);
- }
- <span class="code-comment">/**
- * 发送验证码请求参数
- */</span>
- <span class="code-keyword">public static class</span> <span class="code-class">SendCodeRequest</span> {
- <span class="code-keyword">private</span> String phone;
- <span class="code-comment">// getter和setter</span>
- <span class="code-keyword">public</span> String <span class="code-method">getPhone</span>() { <span
- class="code-keyword">return</span> phone; }
- <span class="code-keyword">public void</span> <span class="code-method">setPhone</span>(String phone) { <span
- class="code-keyword">this</span>.phone = phone; }
- }
- <span class="code-comment">/**
- * 验证验证码请求参数
- */</span>
- <span class="code-keyword">public static class</span> <span class="code-class">VerifyCodeRequest</span> {
- <span class="code-keyword">private</span> String phone;
- <span class="code-keyword">private</span> String code;
- <span class="code-comment">// getter和setter</span>
- <span class="code-keyword">public</span> String <span class="code-method">getPhone</span>() { <span
- class="code-keyword">return</span> phone; }
- <span class="code-keyword">public void</span> <span class="code-method">setPhone</span>(String phone) { <span
- class="code-keyword">this</span>.phone = phone; }
- <span class="code-keyword">public</span> String <span class="code-method">getCode</span>() { <span
- class="code-keyword">return</span> code; }
- <span class="code-keyword">public void</span> <span class="code-method">setCode</span>(String code) { <span
- class="code-keyword">this</span>.code = code; }
- }
- }</code></pre>
- </div>
- </div>
- <footer>
- <p>© 2023 Java后台手机验证码处理 | 注意:生产环境需要考虑安全性和性能优化</p>
- </footer>
- </div>
- <script>
- // 验证码相关变量
- let countdown = 0;
- let countdownInterval;
- let generatedCode = '';
- // 发送验证码
- document.getElementById('send-btn').addEventListener('click', function () {
- const phone = document.getElementById('phone').value.trim();
- const statusDiv = document.getElementById('verify-status');
- if (!phone) {
- showResult(statusDiv, '请输入手机号码', 'error');
- return;
- }
- if (!/^1[3-9]\d{9}$/.test(phone)) {
- showResult(statusDiv, '手机号格式不正确', 'error');
- return;
- }
- // 生成验证码
- generatedCode = generateCode();
- // 开始倒计时
- startCountdown();
- // 模拟发送验证码
- setTimeout(() => {
- showResult(statusDiv, `验证码已发送到 ${phone},验证码:${generatedCode}(控制台查看)`, 'success');
- console.log(`模拟发送验证码到 ${phone}: ${generatedCode}`);
- }, 1000);
- });
- // 验证验证码
- function verifyCode() {
- const phone = document.getElementById('phone').value.trim();
- const inputCode = document.getElementById('code').value.trim();
- const resultDiv = document.getElementById('verify-result');
- const statusDiv = document.getElementById('verify-status');
- if (!phone || !inputCode) {
- showResult(statusDiv, '请输入手机号和验证码', 'error');
- return;
- }
- if (inputCode === generatedCode) {
- resultDiv.textContent = '验证成功!验证码正确。';
- resultDiv.style.color = '#2ecc71';
- showResult(statusDiv, '验证码正确', 'success');
- // 验证成功后清除验证码
- generatedCode = '';
- } else {
- resultDiv.textContent = '验证失败!验证码错误。';
- resultDiv.style.color = '#e74c3c';
- showResult(statusDiv, '验证码错误', 'error');
- }
- }
- // 生成6位数字验证码
- function generateCode() {
- let code = '';
- for (let i = 0; i < 6; i++) {
- code += Math.floor(Math.random() * 10);
- }
- return code;
- }
- // 开始倒计时
- function startCountdown() {
- const sendBtn = document.getElementById('send-btn');
- const countdownDiv = document.getElementById('countdown');
- countdown = 60;
- sendBtn.disabled = true;
- sendBtn.textContent = '发送中...';
- countdownInterval = setInterval(() => {
- countdown--;
- countdownDiv.textContent = `${countdown}s`;
- if (countdown <= 0) {
- clearInterval(countdownInterval);
- sendBtn.disabled = false;
- sendBtn.textContent = '发送验证码';
- countdownDiv.textContent = '';
- }
- }, 1000);
- }
- // 显示结果消息
- function showResult(element, message, type) {
- element.textContent = message;
- element.className = 'result ' + type;
- element.style.display = 'block';
- // 3秒后自动隐藏消息
- setTimeout(() => {
- element.style.display = 'none';
- }, 3000);
- }
- // 重置表单
- function resetForm() {
- document.getElementById('phone').value = '13800138000';
- document.getElementById('code').value = '';
- document.getElementById('verify-result').textContent = '验证结果将显示在这里...';
- document.getElementById('verify-result').style.color = '#333';
- document.getElementById('verify-status').style.display = 'none';
- // 清除倒计时
- if (countdownInterval) {
- clearInterval(countdownInterval);
- }
- const sendBtn = document.getElementById('send-btn');
- sendBtn.disabled = false;
- sendBtn.textContent = '发送验证码';
- document.getElementById('countdown').textContent = '';
- generatedCode = '';
- }
- </script>
- </body>
- </html>
|