SpringBoot实战项目(十三)--登录功能之页面构建及验证码实现

最终实现效果---

 

 

 杂七杂八做了不少小项目,感觉过段时间就忘,这直接就记录下来吧!

前端什么的也只能基本看懂,注重后端开发就行

(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=&#39;&#39;" onblur="this.placeholder=&#39;请输入您的用户名&#39;">
 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=&#39;&#39;" onblur="this.placeholder=&#39;请输入您的密码&#39;">
 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=&#39;&#39;" onblur="this.placeholder=&#39;请输入验证码&#39;">
 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>
login.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 }
LoginControlle

 

配置没问题就实现验证码功能了

 

 

posted on 2020-04-29 21:43  北林日记  阅读(1325)  评论(0编辑  收藏  举报

导航