最終實現效果---
雜七雜八做了不少小項目,感覺過段時間就忘,這直接就記錄下來吧!
前端什么的也只能基本看懂,注重后端開發就行
(css,js靜態資源放網盤了)
鏈接:https://pan.baidu.com/s/1mOKQ9mKKJEkZn9dvmZ0GCQ
提取碼:urhv
首先頁面構建

1 <!DOCTYPE html> 2 <html lang="en" xmlns:th="http://www.thymeleaf.org"> 3 <head> 4 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 5 <title>SSM框架后台管理員登錄</title> 6 <meta name="description" content="particles.js is a lightweight JavaScript library for creating particles."> 7 <meta name="author" content="Vincent Garreau"> 8 <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"> 9 <link rel="stylesheet" media="screen" th:href="@{/xadmin/login/css/style.css}"> 10 <link rel="stylesheet" type="text/css" th:href="@{/xadmin/login/css/reset.css}"> 11 <body> 12 13 <div id="particles-js"> 14 <div class="login" style="display: block;"> 15 <div class="login-top"> 16 登錄 17 </div> 18 <div class="login-center clearfix"> 19 <div class="login-center-img"><img th:src="@{/xadmin/login/images/name.png}"></div> 20 <div class="login-center-input"> 21 <input type="text" name="userName" id="username" value="" placeholder="請輸入您的用戶名" onfocus="this.placeholder=''" onblur="this.placeholder='請輸入您的用戶名'"> 22 <div class="login-center-input-text">用戶名</div> 23 </div> 24 </div> 25 <div class="login-center clearfix"> 26 <div class="login-center-img"><img th:src="@{/xadmin/login/images/password.png}"></div> 27 <div class="login-center-input"> 28 <input type="password" name="passWord" id="password" value="" placeholder="請輸入您的密碼" onfocus="this.placeholder=''" onblur="this.placeholder='請輸入您的密碼'"> 29 <div class="login-center-input-text">密碼</div> 30 </div> 31 </div> 32 <div class="login-center clearfix"> 33 <div class="login-center-img"><img th:src="@{/xadmin/login/images/cpacha.png}"></div> 34 <div class="login-center-input"> 35 <input style="width:50%;" type="text" name="cpacha" id="cpacha" value="" placeholder="請輸入驗證碼" onfocus="this.placeholder=''" onblur="this.placeholder='請輸入驗證碼'"> 36 <div class="login-center-input-text">驗證碼</div> 37 <img id="cpacha-img" title="點擊切換驗證碼" style="cursor:pointer;" src="get_cpacha?vl=4&w=150&h=40&type=loginCpacha" width="110px" height="30px" onclick="changeCpacha()"> 38 </div> 39 </div> 40 <div class="login-button"> 41 登錄 42 </div> 43 </div> 44 <div class="sk-rotating-plane"></div> 45 <canvas class="particles-js-canvas-el" width="1147" height="952" style="width: 100%; height: 100%;"></canvas></div> 46 47 <!-- scripts --> 48 <script th:src="@{/xadmin/login/js/particles.min.js}"></script> 49 <script th:src="@{/xadmin/login/js/app.js}"></script> 50 <script th:src="@{/xadmin/login/js/jquery-1.8.0.min.js}"></script> 51 <script type="text/javascript"> 52 function hasClass(elem, cls) { 53 cls = cls || ''; 54 if (cls.replace(/\s/g, '').length == 0) return false; //當cls沒有參數時,返回false 55 return new RegExp(' ' + cls + ' ').test(' ' + elem.className + ' '); 56 } 57 58 function addClass(ele, cls) { 59 if (!hasClass(ele, cls)) { 60 ele.className = ele.className == '' ? cls : ele.className + ' ' + cls; 61 } 62 } 63 64 function removeClass(ele, cls) { 65 if (hasClass(ele, cls)) { 66 var newClass = ' ' + ele.className.replace(/[\t\r\n]/g, '') + ' '; 67 while (newClass.indexOf(' ' + cls + ' ') >= 0) { 68 newClass = newClass.replace(' ' + cls + ' ', ' '); 69 } 70 ele.className = newClass.replace(/^\s+|\s+$/g, ''); 71 } 72 } 73 74 function changeCpacha(){ 75 $("#cpacha-img").attr("src",'get_cpacha?vl=4&w=150&h=40&type=loginCpacha&t=' + new Date().getTime()); 76 } 77 document.querySelector(".login-button").onclick = function(){ 78 var userName = $("#username").val(); 79 var passWord = $("#password").val(); 80 var cpacha = $("#cpacha").val(); 81 if(userName == '' || userName == 'undefined'){ 82 alert("請填寫用戶名!"); 83 return; 84 } 85 if(passWord == '' || passWord == 'undefined'){ 86 alert("請填寫密碼!"); 87 return; 88 } 89 if(cpacha == '' || cpacha == 'undefined'){ 90 alert("請填寫驗證碼!"); 91 return; 92 } 93 addClass(document.querySelector(".login"), "active") 94 addClass(document.querySelector(".sk-rotating-plane"), "active") 95 document.querySelector(".login").style.display = "none" 96 $.ajax({ 97 url:'/login', 98 data:{userName:userName,passWord:passWord,cpacha:cpacha}, 99 type:'post', 100 dataType:'json', 101 success:function(results){ 102 if(results.code == 200){ 103 window.parent.location = '/index'; 104 //alert("登錄成功!"); 105 }else{ 106 removeClass(document.querySelector(".login"), "active"); 107 removeClass(document.querySelector(".sk-rotating-plane"), "active"); 108 document.querySelector(".login").style.display = "block"; 109 alert(results.msg); 110 changeCpacha(); 111 } 112 } 113 }); 114 115 } 116 </script> 117 </body></html>
驗證碼--隨機數字輸入驗證,原理:向服務端請求,生成隨機的字符,寫入會話請求,同時將隨機字符生成對應圖片,響應給前端;前端輸入對應字符的驗證碼,向后台發起校驗。
這種沒必要死記,網上這種一搜大把,只要理解其實現原理就行,不會就直接復制粘貼

1 package com.beilin.util; 2 3 import java.awt.Color; 4 import java.awt.Font; 5 import java.awt.Graphics; 6 import java.awt.Graphics2D; 7 import java.awt.image.BufferedImage; 8 import java.util.Random; 9 10 /** 11 * 驗證碼生成器 12 * 13 * @author llq 14 */ 15 public class CpachaUtil { 16 17 /** 18 * 驗證碼來源 19 */ 20 final private char[] code = { 21 '2', '3', '4', '5', '6', '7', '8', '9', 22 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 23 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 24 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 25 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 26 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' 27 }; 28 /** 29 * 字體 30 */ 31 final private String[] fontNames = new String[]{ 32 "黑體", "宋體", "Courier", "Arial", 33 "Verdana", "Times", "Tahoma", "Georgia"}; 34 /** 35 * 字體樣式 36 */ 37 final private int[] fontStyles = new int[]{ 38 Font.BOLD, Font.ITALIC|Font.BOLD 39 }; 40 41 /** 42 * 驗證碼長度 43 * 默認4個字符 44 */ 45 private int vcodeLen = 4; 46 /** 47 * 驗證碼圖片字體大小 48 * 默認17 49 */ 50 private int fontsize = 25; 51 /** 52 * 驗證碼圖片寬度 53 */ 54 private int width = (fontsize+1)*vcodeLen+10; 55 /** 56 * 驗證碼圖片高度 57 */ 58 private int height = fontsize+12; 59 /** 60 * 干擾線條數 61 * 默認3條 62 */ 63 private int disturbline = 3; 64 65 66 public CpachaUtil(){} 67 68 /** 69 * 指定驗證碼長度 70 * @param vcodeLen 驗證碼長度 71 */ 72 public CpachaUtil(int vcodeLen) { 73 this.vcodeLen = vcodeLen; 74 this.width = (fontsize+1)*vcodeLen+10; 75 } 76 77 /** 78 * 指定驗證碼長度、圖片寬度、高度 79 * @param vcodeLen 80 * @param width 81 * @param height 82 */ 83 public CpachaUtil(int vcodeLen,int width,int height) { 84 this.vcodeLen = vcodeLen; 85 this.width = width; 86 this.height = height; 87 } 88 89 /** 90 * 生成驗證碼圖片 91 * @param vcode 要畫的驗證碼 92 * @param drawline 是否畫干擾線 93 * @return 94 */ 95 public BufferedImage generatorVCodeImage(String vcode, boolean drawline){ 96 //創建驗證碼圖片 97 BufferedImage vcodeImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); 98 Graphics g = vcodeImage.getGraphics(); 99 //填充背景色 100 g.setColor(new Color(246, 240, 250)); 101 g.fillRect(0, 0, width, height); 102 if(drawline){ 103 drawDisturbLine(g); 104 } 105 //用於生成偽隨機數 106 Random ran = new Random(); 107 //在圖片上畫驗證碼 108 for(int i = 0;i < vcode.length();i++){ 109 //設置字體 110 g.setFont(new Font(fontNames[ran.nextInt(fontNames.length)], fontStyles[ran.nextInt(fontStyles.length)], fontsize)); 111 //隨機生成顏色 112 g.setColor(getRandomColor()); 113 //畫驗證碼 114 g.drawString(vcode.charAt(i)+"", i*fontsize+10, fontsize+5); 115 } 116 //釋放此圖形的上下文以及它使用的所有系統資源 117 g.dispose(); 118 119 return vcodeImage; 120 } 121 /** 122 * 獲得旋轉字體的驗證碼圖片 123 * @param vcode 124 * @param drawline 是否畫干擾線 125 * @return 126 */ 127 public BufferedImage generatorRotateVCodeImage(String vcode, boolean drawline){ 128 //創建驗證碼圖片 129 BufferedImage rotateVcodeImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); 130 Graphics2D g2d = rotateVcodeImage.createGraphics(); 131 //填充背景色 132 g2d.setColor(new Color(246, 240, 250)); 133 g2d.fillRect(0, 0, width, height); 134 if(drawline){ 135 drawDisturbLine(g2d); 136 } 137 //在圖片上畫驗證碼 138 for(int i = 0;i < vcode.length();i++){ 139 BufferedImage rotateImage = getRotateImage(vcode.charAt(i)); 140 g2d.drawImage(rotateImage, null, (int) (this.height * 0.7) * i, 0); 141 } 142 g2d.dispose(); 143 return rotateVcodeImage; 144 } 145 /** 146 * 生成驗證碼 147 * @return 驗證碼 148 */ 149 public String generatorVCode(){ 150 int len = code.length; 151 Random ran = new Random(); 152 StringBuffer sb = new StringBuffer(); 153 for(int i = 0;i < vcodeLen;i++){ 154 int index = ran.nextInt(len); 155 sb.append(code[index]); 156 } 157 return sb.toString(); 158 } 159 /** 160 * 為驗證碼圖片畫一些干擾線 161 * @param g 162 */ 163 private void drawDisturbLine(Graphics g){ 164 Random ran = new Random(); 165 for(int i = 0;i < disturbline;i++){ 166 int x1 = ran.nextInt(width); 167 int y1 = ran.nextInt(height); 168 int x2 = ran.nextInt(width); 169 int y2 = ran.nextInt(height); 170 g.setColor(getRandomColor()); 171 //畫干擾線 172 g.drawLine(x1, y1, x2, y2); 173 } 174 } 175 /** 176 * 獲取一張旋轉的圖片 177 * @param c 要畫的字符 178 * @return 179 */ 180 private BufferedImage getRotateImage(char c){ 181 BufferedImage rotateImage = new BufferedImage(height, height, BufferedImage.TYPE_INT_ARGB); 182 Graphics2D g2d = rotateImage.createGraphics(); 183 //設置透明度為0 184 g2d.setColor(new Color(255, 255, 255, 0)); 185 g2d.fillRect(0, 0, height, height); 186 Random ran = new Random(); 187 g2d.setFont(new Font(fontNames[ran.nextInt(fontNames.length)], fontStyles[ran.nextInt(fontStyles.length)], fontsize)); 188 g2d.setColor(getRandomColor()); 189 double theta = getTheta(); 190 //旋轉圖片 191 g2d.rotate(theta, height/2, height/2); 192 g2d.drawString(Character.toString(c), (height-fontsize)/2, fontsize+5); 193 g2d.dispose(); 194 195 return rotateImage; 196 } 197 /** 198 * @return 返回一個隨機顏色 199 */ 200 private Color getRandomColor(){ 201 Random ran = new Random(); 202 return new Color(ran.nextInt(220), ran.nextInt(220), ran.nextInt(220)); 203 } 204 /** 205 * @return 角度 206 */ 207 private double getTheta(){ 208 return ((int) (Math.random()*1000) % 2 == 0 ? -1 : 1)*Math.random(); 209 } 210 211 /** 212 * @return 驗證碼字符個數 213 */ 214 public int getVcodeLen() { 215 return vcodeLen; 216 } 217 /** 218 * 設置驗證碼字符個數 219 * @param vcodeLen 220 */ 221 public void setVcodeLen(int vcodeLen) { 222 this.width = (fontsize+3)*vcodeLen+10; 223 this.vcodeLen = vcodeLen; 224 } 225 /** 226 * @return 字體大小 227 */ 228 public int getFontsize() { 229 return fontsize; 230 } 231 /** 232 * 設置字體大小 233 * @param fontsize 234 */ 235 public void setFontsize(int fontsize) { 236 this.width = (fontsize+3)*vcodeLen+10; 237 this.height = fontsize+15; 238 this.fontsize = fontsize; 239 } 240 /** 241 * @return 圖片寬度 242 */ 243 public int getWidth() { 244 return width; 245 } 246 /** 247 * 設置圖片寬度 248 * @param width 249 */ 250 public void setWidth(int width) { 251 this.width = width; 252 } 253 /** 254 * @return 圖片高度 255 */ 256 public int getHeight() { 257 return height; 258 } 259 /** 260 * 設置圖片高度 261 * @param height 262 */ 263 public void setHeight(int height) { 264 this.height = height; 265 } 266 /** 267 * @return 干擾線條數 268 */ 269 public int getDisturbline() { 270 return disturbline; 271 } 272 /** 273 * 設置干擾線條數 274 * @param disturbline 275 */ 276 public void setDisturbline(int disturbline) { 277 this.disturbline = disturbline; 278 } 279 280 }
(與登錄相關的操作都放在LoginController,里面都有中文注解,很多東西只可意會不可言傳)

1 package com.beilin.controller; 2 3 4 import com.beilin.Service.UserService; 5 import com.beilin.entity.SysUser; 6 import com.beilin.result.ResponseCode; 7 import com.beilin.result.Results; 8 import com.beilin.util.CpachaUtil; 9 import com.beilin.util.Md5Cipher; 10 import org.springframework.beans.factory.annotation.Autowired; 11 import org.springframework.stereotype.Controller; 12 import org.springframework.web.bind.annotation.*; 13 import org.springframework.web.servlet.ModelAndView; 14 15 import javax.imageio.ImageIO; 16 import javax.servlet.http.HttpServletRequest; 17 import javax.servlet.http.HttpServletResponse; 18 import java.awt.image.BufferedImage; 19 import java.io.IOException; 20 21 /** 22 * 系統登錄控制器相關 23 */ 24 @Controller 25 public class LoginController { 26 @Autowired 27 private UserService userService; 28 29 30 /** 31 * 登錄成功后的主頁 32 * @param model 33 * @return 34 */ 35 @GetMapping("/index") 36 public ModelAndView index(ModelAndView model) { 37 model.setViewName("index"); 38 return model; 39 } 40 41 /** 42 * 打開登錄頁面 43 * @param model 44 * @return 45 */ 46 @GetMapping("/login") 47 public ModelAndView login(ModelAndView model) { 48 model.setViewName("login"); 49 return model; 50 } 51 52 53 /** 54 * 本系統所有的驗證碼均采用此方法 55 * @param vcodeLen 56 * @param width 57 * @param height 58 * @param cpachaType:用來區別驗證碼的類型,傳入字符串 59 * @param request 60 * @param response 61 */ 62 @GetMapping (value="/get_cpacha") 63 public void generateCpacha( 64 @RequestParam(name="vl",required=false,defaultValue="4") Integer vcodeLen, 65 @RequestParam(name="w",required=false,defaultValue="100") Integer width, 66 @RequestParam(name="h",required=false,defaultValue="30") Integer height, 67 @RequestParam(name="type",required=true,defaultValue="loginCpacha") String cpachaType, 68 HttpServletRequest request, 69 HttpServletResponse response){ 70 //調用CpachaUtil中的構造方法指定驗證碼的長度,寬度,高度 71 CpachaUtil cpachaUtil = new CpachaUtil(vcodeLen, width, height); 72 //生成驗證碼 73 String generatorVCode = cpachaUtil.generatorVCode(); 74 request.getSession().setAttribute(cpachaType, generatorVCode); 75 //把隨機取到的驗證碼傳入圖片 true--需要干擾線 76 BufferedImage generatorRotateVCodeImage = cpachaUtil.generatorRotateVCodeImage(generatorVCode, true); 77 try { 78 ImageIO.write(generatorRotateVCodeImage, "gif", response.getOutputStream()); 79 } catch (IOException e) { 80 // TODO Auto-generated catch block 81 e.printStackTrace(); 82 } 83 } 84 85 86 }
配置沒問題就實現驗證碼功能了