├── 滑块验证码.zip ├── silder_code.jar ├── web ├── sourceYzmImg │ ├── 1.png │ ├── 12.png │ ├── 13.png │ ├── 4.png │ └── 5.png ├── login │ ├── img │ │ ├── erricon.png │ │ ├── loading.png │ │ └── refresh.png │ ├── js │ │ └── drag.js │ └── css │ │ └── login.css └── login1.jsp ├── README.en.md ├── redme.txt ├── README.md └── com └── power └── yzm ├── servlet └── YzmServlet.java └── util └── DragYzm.java /滑块验证码.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/refetch/slider_verification_code/master/滑块验证码.zip -------------------------------------------------------------------------------- /silder_code.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/refetch/slider_verification_code/master/silder_code.jar -------------------------------------------------------------------------------- /web/sourceYzmImg/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/refetch/slider_verification_code/master/web/sourceYzmImg/1.png -------------------------------------------------------------------------------- /web/sourceYzmImg/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/refetch/slider_verification_code/master/web/sourceYzmImg/12.png -------------------------------------------------------------------------------- /web/sourceYzmImg/13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/refetch/slider_verification_code/master/web/sourceYzmImg/13.png -------------------------------------------------------------------------------- /web/sourceYzmImg/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/refetch/slider_verification_code/master/web/sourceYzmImg/4.png -------------------------------------------------------------------------------- /web/sourceYzmImg/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/refetch/slider_verification_code/master/web/sourceYzmImg/5.png -------------------------------------------------------------------------------- /web/login/img/erricon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/refetch/slider_verification_code/master/web/login/img/erricon.png -------------------------------------------------------------------------------- /web/login/img/loading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/refetch/slider_verification_code/master/web/login/img/loading.png -------------------------------------------------------------------------------- /web/login/img/refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/refetch/slider_verification_code/master/web/login/img/refresh.png -------------------------------------------------------------------------------- /README.en.md: -------------------------------------------------------------------------------- 1 | # 滑块验证码 2 | 3 | #### Description 4 | 简单滑块验证码 5 | 6 | #### Software Architecture 7 | Software architecture description 8 | 9 | #### Installation 10 | 11 | 1. xxxx 12 | 2. xxxx 13 | 3. xxxx 14 | 15 | #### Instructions 16 | 17 | 1. xxxx 18 | 2. xxxx 19 | 3. xxxx 20 | 21 | #### Contribution 22 | 23 | 1. Fork the repository 24 | 2. Create Feat_xxx branch 25 | 3. Commit your code 26 | 4. Create Pull Request 27 | 28 | 29 | #### Gitee Feature 30 | 31 | 1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md 32 | 2. Gitee blog [blog.gitee.com](https://blog.gitee.com) 33 | 3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore) 34 | 4. The most valuable open source project [GVP](https://gitee.com/gvp) 35 | 5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help) 36 | 6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) 37 | -------------------------------------------------------------------------------- /redme.txt: -------------------------------------------------------------------------------- 1 | 1、引入silder_code.jar。 2 | 2、配置web.xml文件 3 | 4 | yzmServlet 5 | com.power.yzm.servlet.YzmServlet 6 | 7 | 8 | yzmServlet 9 | /yzmServlet 10 | 11 | 12 | 13 | 14 | 3、将web文件拷贝进入项目。 15 | 4、验证码验证 16 | String yzm = request.getParameter("yzm"); 17 | Integer location_x = (Integer) request.getSession().getAttribute("location_x"); 18 | if ((Integer.valueOf(yzm) < location_x + 4) && (Integer.valueOf(yzm) > location_x - 4)) { 19 | request.setAttribute("msg", "登录成功"); 20 | request.getRequestDispatcher("/result.jsp").forward(request, response); 21 | } else { 22 | request.setAttribute("msg", "图形验证失败"); 23 | request.getRequestDispatcher("/result.jsp").forward(request, response); 24 | } 25 | 5、sourceYzmImg 这个文件夹下面就是验证码图片 26 | 也可以自己拷贝进去 想要图片 27 | 260 * 116 28 | 图片大小 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 滑块验证码 2 | 3 | #### 介绍 4 | 简单滑块验证码 5 | 6 | #### 软件架构 7 | servlet 8 | 9 | 10 | #### 安装教程 11 | 12 | 1、引入silder_code.jar。 13 | 2、配置web.xml文件 14 | 15 | yzmServlet 16 | com.power.yzm.servlet.YzmServlet 17 | 18 | 19 | yzmServlet 20 | /yzmServlet 21 | 22 | 23 | 24 | 25 | 3、将web文件拷贝进入项目。 26 | 4、验证码验证 27 | String yzm = request.getParameter("yzm"); 28 | Integer location_x = (Integer) request.getSession().getAttribute("location_x"); 29 | if ((Integer.valueOf(yzm) < location_x + 4) && (Integer.valueOf(yzm) > location_x - 4)) { 30 | request.setAttribute("msg", "登录成功"); 31 | request.getRequestDispatcher("/result.jsp").forward(request, response); 32 | } else { 33 | request.setAttribute("msg", "图形验证失败"); 34 | request.getRequestDispatcher("/result.jsp").forward(request, response); 35 | } 36 | 5、sourceYzmImg 这个文件夹下面就是验证码图片 37 | 也可以自己拷贝进去 想要图片 38 | 260 * 116 39 | 图片大小 -------------------------------------------------------------------------------- /com/power/yzm/servlet/YzmServlet.java: -------------------------------------------------------------------------------- 1 | package com.power.yzm.servlet; 2 | 3 | 4 | import com.power.yzm.util.DragYzm; 5 | import net.sf.json.JSONObject; 6 | import org.apache.commons.lang.StringUtils; 7 | 8 | import javax.servlet.ServletConfig; 9 | import javax.servlet.ServletException; 10 | import javax.servlet.http.HttpServlet; 11 | import javax.servlet.http.HttpServletRequest; 12 | import javax.servlet.http.HttpServletResponse; 13 | import java.io.IOException; 14 | import java.io.PrintWriter; 15 | import java.util.HashMap; 16 | import java.util.Map; 17 | 18 | 19 | public class YzmServlet extends HttpServlet { 20 | 21 | @Override 22 | public void init(ServletConfig config) throws ServletException { 23 | super.init(config); 24 | DragYzm.init(config.getServletContext()); 25 | } 26 | 27 | protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 28 | String imgname = request.getParameter("imgname"); 29 | String point = request.getParameter("point"); 30 | PrintWriter out = null; 31 | try { 32 | Map result = new HashMap(); 33 | out = response.getWriter(); 34 | response.setContentType("application/json-rpc;charset=UTF-8"); 35 | if (StringUtils.isEmpty(point)) { //生成图形验证码 36 | if(StringUtils.isEmpty(imgname)) { 37 | imgname = "5.png"; 38 | } 39 | DragYzm resourImg = new DragYzm(); 40 | result = resourImg.create(request, imgname); 41 | } else { //验证验证码 42 | Integer location_x = (Integer) request.getSession().getAttribute("location_x"); 43 | if ((Integer.valueOf(point) < location_x + 4) && (Integer.valueOf(point) > location_x - 4)) { 44 | //说明验证通过, 45 | result.put("data", "success"); 46 | } else { 47 | result.put("data", "error"); 48 | } 49 | } 50 | JSONObject jsonObject = JSONObject.fromObject(result); 51 | out.println(jsonObject.toString()); 52 | } catch (Exception e) { 53 | e.printStackTrace(); 54 | } finally { 55 | if (out != null) { 56 | out.close(); 57 | } 58 | } 59 | } 60 | 61 | protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 62 | 63 | 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /web/login/js/drag.js: -------------------------------------------------------------------------------- 1 | (function($){ 2 | $.fn.drag = function(options, sucfun, errfun){ 3 | var isvalid = false; 4 | var x, drag = this, isMove = false, defaults = { 5 | }; 6 | var options = $.extend(defaults, options); 7 | //添加背景,文字,滑块 8 | var html = '
'+ 9 | '
拖动图片验证登录
'+ 10 | '
'; 11 | this.append(html); 12 | 13 | var handler = drag.find('.handler'); 14 | var drag_bg = drag.find('.drag_bg'); 15 | var text = drag.find('.drag_text'); 16 | var maxWidth = drag.width() - handler.width(); //能滑动的最大间距 17 | 18 | //鼠标按下时候的x轴的位置 19 | handler.mousedown(function(e){ 20 | if(isvalid) { 21 | return false; 22 | } 23 | $gt_cut.css("display", "none"); 24 | $gt_cut_hidden.show(); 25 | $xy_img.show(); 26 | isMove = true; 27 | x = e.pageX - parseInt(handler.css('left'), 10); 28 | }); 29 | var $xy_img = $("#xy_img"); 30 | var $gt_cut = $("#yzm_image_source"); 31 | var $gt_cut_hidden = $("#yzm_image_cut_big"); 32 | //鼠标指针在上下文移动时,移动距离大于0小于最大间距,滑块x轴位置等于鼠标移动距离 33 | $("#drag").mousemove(function(e){ 34 | if(isvalid) { 35 | return false; 36 | } 37 | var _x = e.pageX - x; 38 | if(isMove){ 39 | if(_x > 0 && _x <= maxWidth){ 40 | $xy_img.css({'left': _x}); 41 | handler.css({'left': _x}); 42 | drag_bg.css({'width': _x}); 43 | }else if(_x > maxWidth){ //鼠标指针移动距离达到最大时清空事件 44 | // dragOk(); 45 | } 46 | } 47 | }).mouseup(function(e){ 48 | if(isvalid) { 49 | return false; 50 | } 51 | isMove = false; 52 | var _x = e.pageX - x; 53 | // console.log("X",_x); 54 | $.ajax({ 55 | type:"POST", 56 | url:"yzmServlet", 57 | dataType:"JSON", 58 | async: false, 59 | data:{point:_x}, 60 | success:function(result){ 61 | // console.log(result) 62 | if(result.data == "success") { 63 | dragOk(_x); 64 | }else{ 65 | dragErr(); 66 | } 67 | }, 68 | error: function(err) { 69 | // console.log(err) 70 | // $(".drag_bg").css("background-color", "#C22A0E"); 71 | text.text('请滑动滑块进行验证!'); 72 | } 73 | }); 74 | }); 75 | 76 | var errcount = 0; 77 | function dragErr() { 78 | errcount = errcount + 1; 79 | isvalid = false; 80 | $(".drag_bg").css("background-color", "#C22A0E"); 81 | text.text("验证失败"); 82 | handler.removeClass('handler_bg').addClass('handler_err_bg'); 83 | setTimeout(function(){ 84 | //还原 85 | text.text("拖动图片验证登录"); 86 | $(".drag_bg").css("background-color", "#7ac23c"); 87 | handler.removeClass("handler_err_bg").addClass("handler_bg"); 88 | // $xy_img.css("display", "none"); 89 | $xy_img.css({'left': 0}); 90 | handler.css({'left': 0}); 91 | drag_bg.css({'width': 0}); 92 | //验证失败, 拖动错误数大于3次,那么就重置 93 | if(errcount >= 3) { 94 | errfun(); 95 | errcount = 0; 96 | $xy_img.css("display", "none"); 97 | $gt_cut.show(); 98 | $gt_cut_hidden.css("display", "none"); 99 | } 100 | }, 1000); 101 | } 102 | //清空事件 103 | function dragOk(_x){ 104 | isvalid = true; 105 | handler.removeClass('handler_bg').addClass('handler_ok_bg'); 106 | text.text('验证通过'); 107 | drag.css({'color': '#fff'}); 108 | handler.unbind('mousedown'); 109 | $(document).unbind('mousemove'); 110 | $(document).unbind('mouseup'); 111 | //验证通过,隐藏刷新 112 | $("#refreshyzm").css("display", "none"); 113 | $("#passcheck").val("1"); 114 | $("#yzm").val(_x); 115 | 116 | //显示原始图片,并做光线闪过 117 | $xy_img.css("display", "none"); 118 | $gt_cut_hidden.css("display", "none"); 119 | $gt_cut.show(); 120 | $gt_cut.addClass("run"); 121 | } 122 | }; 123 | })(jQuery); 124 | 125 | 126 | -------------------------------------------------------------------------------- /web/login/css/login.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 0px; 3 | margin: 0px; 4 | } 5 | 6 | .yzm { 7 | width: 260px; 8 | height: 120px; 9 | position: relative; 10 | margin-left: 80px; 11 | } 12 | 13 | #drag { 14 | position: relative; 15 | background-color: #e8e8e8; 16 | width: 300px; 17 | height: 34px; 18 | line-height: 34px; 19 | margin-left: 80px; 20 | text-align: center; 21 | } 22 | 23 | #drag .handler { 24 | position: absolute; 25 | top: 0px; 26 | left: 0px; 27 | width: 40px; 28 | height: 32px; 29 | border: 1px solid #ccc; 30 | cursor: move; 31 | } 32 | 33 | .handler_bg { 34 | background: #fff url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NTc3MiwgMjAxNC8wMS8xMy0xOTo0NDowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo0ZDhlNWY5My05NmI0LTRlNWQtOGFjYi03ZTY4OGYyMTU2ZTYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NTEyNTVEMURGMkVFMTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NTEyNTVEMUNGMkVFMTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo2MTc5NzNmZS02OTQxLTQyOTYtYTIwNi02NDI2YTNkOWU5YmUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NGQ4ZTVmOTMtOTZiNC00ZTVkLThhY2ItN2U2ODhmMjE1NmU2Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+YiRG4AAAALFJREFUeNpi/P//PwMlgImBQkA9A+bOnfsIiBOxKcInh+yCaCDuByoswaIOpxwjciACFegBqZ1AvBSIS5OTk/8TkmNEjwWgQiUgtQuIjwAxUF3yX3xyGIEIFLwHpKyAWB+I1xGSwxULIGf9A7mQkBwTlhBXAFLHgPgqEAcTkmNCU6AL9d8WII4HOvk3ITkWJAXWUMlOoGQHmsE45ViQ2KuBuASoYC4Wf+OUYxz6mQkgwAAN9mIrUReCXgAAAABJRU5ErkJggg==") no-repeat center; 35 | } 36 | 37 | .handler_ok_bg { 38 | background: #fff url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NTc3MiwgMjAxNC8wMS8xMy0xOTo0NDowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo0ZDhlNWY5My05NmI0LTRlNWQtOGFjYi03ZTY4OGYyMTU2ZTYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NDlBRDI3NjVGMkQ2MTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NDlBRDI3NjRGMkQ2MTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDphNWEzMWNhMC1hYmViLTQxNWEtYTEwZS04Y2U5NzRlN2Q4YTEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NGQ4ZTVmOTMtOTZiNC00ZTVkLThhY2ItN2U2ODhmMjE1NmU2Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+k+sHwwAAASZJREFUeNpi/P//PwMyKD8uZw+kUoDYEYgloMIvgHg/EM/ptHx0EFk9I8wAoEZ+IDUPiIMY8IN1QJwENOgj3ACo5gNAbMBAHLgAxA4gQ5igAnNJ0MwAVTsX7IKyY7L2UNuJAf+AmAmJ78AEDTBiwGYg5gbifCSxFCZoaBMCy4A4GOjnH0D6DpK4IxNSVIHAfSDOAeLraJrjgJp/AwPbHMhejiQnwYRmUzNQ4VQgDQqXK0ia/0I17wJiPmQNTNBEAgMlQIWiQA2vgWw7QppBekGxsAjIiEUSBNnsBDWEAY9mEFgMMgBk00E0iZtA7AHEctDQ58MRuA6wlLgGFMoMpIG1QFeGwAIxGZo8GUhIysmwQGSAZgwHaEZhICIzOaBkJkqyM0CAAQDGx279Jf50AAAAAABJRU5ErkJggg==") no-repeat center; 39 | } 40 | 41 | .handler_err_bg { 42 | background: #fff url("../img/erricon.png"); 43 | } 44 | 45 | #drag .drag_bg { 46 | background-color: #7ac23c; 47 | height: 34px; 48 | width: 0px; 49 | } 50 | 51 | #drag .drag_err { 52 | background-color: darkred; 53 | height: 34px; 54 | width: 0px; 55 | } 56 | 57 | #drag .drag_text { 58 | position: absolute; 59 | top: 0px; 60 | width: 300px; 61 | -moz-user-select: none; 62 | -webkit-user-select: none; 63 | user-select: none; 64 | -o-user-select: none; 65 | -ms-user-select: none; 66 | } 67 | 68 | .yzm_image_source { 69 | float: left; 70 | width: 260px; 71 | height: 113px; 72 | margin: 0 !important; 73 | border: 0px; 74 | padding: 0 !important; 75 | background-image: url("../../sourceYzmImg/5.png"); 76 | } 77 | 78 | .yzm_image_source:before { 79 | content: ""; 80 | position: absolute; 81 | width: 100px; 82 | height: 100%; 83 | top: 0; 84 | left: -150px; 85 | overflow: hidden; 86 | background: -moz-linear-gradient(left, rgba(255, 255, 255, 0) 0, rgba(255, 255, 255, .2) 50%, rgba(255, 255, 255, 0) 100%); 87 | background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 0)), 88 | color-stop(50%, rgba(255, 255, 255, .2)), color-stop(100%, rgba(255, 255, 255, 0))); 89 | background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0, rgba(255, 255, 255, .2) 50%, rgba(255, 255, 255, 0) 100%); 90 | background: -o-linear-gradient(left, rgba(255, 255, 255, 0) 0, rgba(255, 255, 255, .2) 50%, rgba(255, 255, 0, 0) 100%); 91 | -webkit-transform: skewX(-25deg); 92 | -moz-transform: skewX(-25deg) 93 | } 94 | 95 | .run:before { 96 | left: 70%; 97 | transition: left 2s ease 0s; 98 | } 99 | 100 | .yzm_image_cut_big { 101 | float: left; 102 | width: 260px; 103 | height: 113px; 104 | margin: 0 !important; 105 | border: 0px; 106 | padding: 0 !important; 107 | } 108 | 109 | .yzm_image_cut_loading { 110 | float: left; 111 | width: 260px; 112 | height: 113px; 113 | margin: 0 !important; 114 | border: 1px solid red; 115 | padding: 0 !important; 116 | background-image: url("../img/loading.png"); 117 | } 118 | 119 | #xy_img { 120 | z-index: 999; 121 | width: 60px; 122 | height: 60px; 123 | position: relative; 124 | } -------------------------------------------------------------------------------- /web/login1.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 | 3 | 4 | 江苏省学生健康监测系统 5 | 6 | 7 | 8 | 9 | 56 | 57 | 58 | 59 |
60 |
61 | 62 | 63 | 64 |
65 |

用户登录

66 |
67 |
68 | 69 | 70 |
71 |
72 | 73 | 74 |
75 |
76 | <%----%> 77 |
78 | 79 |
80 | 81 |
82 | 83 |
84 | 85 |
86 | 88 | 91 |
92 |
93 |
94 | 95 |
96 | 97 |
98 | 99 | 100 | 101 | 102 |
103 |
104 | 105 | 181 | 182 | 183 | -------------------------------------------------------------------------------- /com/power/yzm/util/DragYzm.java: -------------------------------------------------------------------------------- 1 | package com.power.yzm.util; 2 | 3 | 4 | 5 | 6 | import org.apache.commons.lang.StringUtils; 7 | import org.apache.commons.lang.math.RandomUtils; 8 | import sun.misc.BASE64Encoder; 9 | 10 | import javax.imageio.ImageIO; 11 | import javax.imageio.ImageReadParam; 12 | import javax.imageio.ImageReader; 13 | import javax.imageio.stream.ImageInputStream; 14 | import javax.servlet.ServletContext; 15 | import javax.servlet.http.HttpServletRequest; 16 | import java.awt.*; 17 | import java.awt.geom.Arc2D; 18 | import java.awt.geom.Area; 19 | import java.awt.geom.Rectangle2D; 20 | import java.awt.image.BufferedImage; 21 | import java.io.ByteArrayOutputStream; 22 | import java.io.File; 23 | import java.io.FileInputStream; 24 | import java.io.IOException; 25 | import java.net.URL; 26 | import java.util.*; 27 | import java.util.List; 28 | 29 | 30 | public class DragYzm { 31 | 32 | private int tailoring_w = 50; //小图的宽 33 | private int tailoring_h = 50; //小图的高 34 | 35 | private int location_x = 0; //随机X位置 36 | private int location_y = 0; //随机Y位置 37 | 38 | //生成图片名称 39 | // private String picSuffix = ".png"; 40 | 41 | //指定web下的目录, 42 | // private static String imgPath = ""; 43 | private static String sourceImgPath = ""; 44 | 45 | // private static final String tempYzmImg = "tempYzmImg"; 46 | //private static final String tempYzmImg = "tempYzmImg"; 47 | private static final String sourceYzmImg = "sourceYzmImg"; 48 | 49 | private static final int shadowWidth = 4; //阴影宽度 50 | private static final int lightHeightWidth = 5; //图片边缘亮色(黄色)宽度。 51 | 52 | private static final int arc = 10; //圆弧直径 53 | 54 | /** 55 | * 制定源图片位置及其生成的临时图位置 56 | * 57 | * @param context 58 | */ 59 | public static void init(ServletContext context) { 60 | // imgPath = context.getRealPath("/") + tempYzmImg; 61 | sourceImgPath = context.getRealPath("/") + sourceYzmImg; 62 | } 63 | 64 | public DragYzm() { 65 | } 66 | 67 | /** 68 | * 创建图片到临时目录, 并返回图片的文件名称 69 | * 70 | * @param request 71 | * @param havingfilename 72 | * @return 73 | * @throws IOException 74 | */ 75 | public Map create(HttpServletRequest request, String havingfilename) throws IOException { 76 | //本地原始图片路径, 77 | File file = new File(sourceImgPath); 78 | String[] list = file.list(); 79 | String filename; 80 | //获取随机图片, 每次获取到的图片与已有的图片要不同。 81 | while (true) { 82 | int randowval = RandomUtils.nextInt(list.length); 83 | filename = list[randowval]; 84 | if (!filename.equals(havingfilename)) { 85 | break; 86 | } 87 | } 88 | 89 | if (StringUtils.isEmpty(filename)){ 90 | filename = " 5.png"; 91 | } 92 | // BufferedImage originalImage = getBufferedImage(sourceImgPath + File.separator + filename); 93 | File sourceFile = new File(sourceImgPath + File.separator + filename); 94 | //从原始图片中随机截取小图,同时处理背景大图 95 | Map result = createImg(sourceFile, filename); 96 | //将x 轴位置作为验证码 97 | request.getSession().setAttribute("location_x", location_x); 98 | return result; 99 | } 100 | 101 | 102 | /** 103 | * 对图片进行裁剪 104 | * 105 | * @param file 图片 106 | * @param x 裁剪图左上方X位置 107 | * @param y 裁剪图左上方Y位置 108 | * @param w 裁剪的宽 109 | * @param h 裁剪的宽 110 | * @return 裁剪之后的图片Buffered 111 | * @throws IOException 112 | */ 113 | private static BufferedImage cutImg(File file, int x, int y, int w, int h) throws IOException { 114 | Iterator iterator = ImageIO.getImageReadersByFormatName("png"); 115 | ImageReader render = (ImageReader) iterator.next(); 116 | ImageInputStream in = ImageIO.createImageInputStream(new FileInputStream(file)); 117 | render.setInput(in, true); 118 | BufferedImage bufferedImage; 119 | try { 120 | ImageReadParam param = render.getDefaultReadParam(); 121 | Rectangle rect = new Rectangle(x, y, w, h); 122 | param.setSourceRegion(rect); 123 | bufferedImage = render.read(0, param); 124 | } finally { 125 | if(in != null) { 126 | in.close(); 127 | } 128 | } 129 | return bufferedImage; 130 | } 131 | 132 | // private String createBigImg(BufferedImage smllImage, File file, String filename) throws IOException { 133 | // //创建一个灰度化图层, 将生成的小图,覆盖到该图层,使其灰度化,用于作为一个水印图 134 | // String bigImgName = randomImgName("big_" + filename.replaceAll(".png", "") + "_"); 135 | // //如果大图不存在,那么就创建 136 | //// File bigfile = new File(imgPath + File.separator + bigImgName); 137 | //// if (!bigfile.exists()) { 138 | //// //将灰度化之后的图片,整合到原有图片上 139 | //// BufferedImage bigImg = addWatermark(file, smllImage, 0.6F); 140 | //// ImageIO.write(bigImg, "png", bigfile); 141 | //// } 142 | // 143 | // return bigImgName; 144 | // } 145 | 146 | /** 147 | * 添加水印 148 | * @param file 149 | * @param smallImage 150 | */ 151 | private BufferedImage addWatermark(File file, BufferedImage smallImage, float alpha) throws IOException { 152 | BufferedImage source = ImageIO.read(file); 153 | Graphics2D graphics2D = source.createGraphics(); 154 | graphics2D.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP,alpha)); 155 | graphics2D.drawImage(smallImage, location_x, location_y, null); 156 | graphics2D.dispose(); //释放 157 | return source; 158 | } 159 | 160 | // private String randomImgName(String suf) { 161 | // //按照坐标位生成图片 162 | // return suf + location_y + "_" + DigestUtils.md5Hex(String.valueOf(location_x)).substring(0, 16) + picSuffix; 163 | //// return RandomStringUtils.random(8, "abcdefg1234567890") + picSuffix; 164 | // } 165 | 166 | private Map createImg(File file, String filename) throws IOException { 167 | BufferedImage sourceBuff = ImageIO.read(file); 168 | int width = sourceBuff.getWidth(); 169 | int height = sourceBuff.getHeight(); 170 | //生成随机x,y 171 | Random random = new Random(); 172 | //X轴距离右端tailoring_w 以上) Y轴距离底部tailoring_y以上 173 | this.location_x = random.nextInt(width - tailoring_w * 2) + tailoring_w; 174 | this.location_y = random.nextInt(height - tailoring_h); 175 | //裁剪小图 176 | BufferedImage sourceSmall = cutImg(file, location_x, location_y, tailoring_w, tailoring_h); 177 | //创建shape区域 178 | List shapes = createSmallShape(); 179 | Shape area = shapes.get(0); 180 | Shape bigarea = shapes.get(1); 181 | //创建图层用于处理小图的阴影 182 | BufferedImage bfm1 = new BufferedImage(tailoring_w, tailoring_h, BufferedImage.TYPE_INT_ARGB); 183 | //创建图层用于处理大图的凹槽 184 | BufferedImage bfm2 = new BufferedImage(tailoring_w, tailoring_h, BufferedImage.TYPE_INT_ARGB); 185 | for (int i = 0; i < tailoring_w; i++) { 186 | for (int j = 0; j < tailoring_h; j++) { 187 | if (area.contains(i, j)) { 188 | bfm1.setRGB(i, j, sourceSmall.getRGB(i, j)); 189 | } 190 | if (bigarea.contains(i, j)) { 191 | bfm2.setRGB(i, j, Color.black.getRGB()); 192 | } 193 | } 194 | } 195 | //处理图片的边缘高亮及其阴影效果 196 | BufferedImage resultImgBuff = dealLightAndShadow(bfm1, area); 197 | //生成随机名称 198 | // String smallFileName = randomImgName("small_" + filename.replaceAll(".png", "") + "_"); 199 | // File smallfile = new File(imgPath + File.separator + smallFileName); 200 | // if (!smallfile.exists()) { //因为根据坐标点生成小图,如果已经存在,那么就不需要重复创建,直接使用 201 | // ImageIO.write(resultImgBuff, "png", smallfile); 202 | // } 203 | 204 | // ByteArrayOutputStream os = new ByteArrayOutputStream();//新建流。 205 | // ImageIO.write(resultImgBuff, "png", os);//利用ImageIO类提供的write方法,将bi以png图片的数据模式写入流。 206 | // byte[] jigsawImages = os.toByteArray(); 207 | // BASE64Encoder encoder = new sun.misc.BASE64Encoder(); 208 | 209 | Map result = new HashMap(); 210 | result.put("smallImgName",getImageToBase64Str(resultImgBuff)); 211 | //将灰色图当做水印印到原图上 212 | BufferedImage bigImg = addWatermark(file, bfm2, 0.6F); 213 | result.put("bigImgName", getImageToBase64Str(bigImg)); 214 | result.put("location_y", String.valueOf(location_y)); 215 | result.put("sourceImgName", filename); 216 | return result; 217 | } 218 | 219 | private String getImageToBase64Str (BufferedImage templateImage){ 220 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 221 | try { 222 | ImageIO.write(templateImage, "png", baos); 223 | } catch (IOException e) { 224 | e.printStackTrace(); 225 | } 226 | byte[] bytes = baos.toByteArray(); 227 | BASE64Encoder encoder = new sun.misc.BASE64Encoder(); 228 | return encoder.encodeBuffer(bytes).trim(); 229 | } 230 | 231 | private List createSmallShape() { 232 | //处理小图,在4个方向上 随机找到2个方向添加凸出 233 | int face1 = RandomUtils.nextInt(3); //凸出1 234 | int face2; //凸出2 235 | //使凸出1 与 凸出2不在同一个方向 236 | while (true) { 237 | face2 = RandomUtils.nextInt(3); 238 | if (face1 != face2) { 239 | break; 240 | } 241 | } 242 | //生成随机区域值, (10-20)之间 243 | int position1 = RandomUtils.nextInt((tailoring_h - arc * 2) / 2) + (tailoring_h - arc * 2)/2; 244 | Shape shape1 = createShape(face1, 0, position1); 245 | Shape bigshape1 = createShape(face1, 2, position1); 246 | 247 | //生成中间正方体Shape, (具体边界+弧半径 = x坐标位) 248 | Shape centre = new Rectangle2D.Float(arc, arc, tailoring_w - 2 * 10, tailoring_h - 2 * 10); 249 | int position2 = RandomUtils.nextInt((tailoring_h - arc * 2) / 2) + (tailoring_h - arc * 2)/2; 250 | Shape shape2 = createShape(face2, 0, position2); 251 | 252 | //因为后边图形需要生成阴影, 所以生成的小图shape + 阴影宽度 = 灰度化的背景小图shape(即大图上的凹槽) 253 | Shape bigshape2 = createShape(face2, shadowWidth / 2, position2); 254 | Shape bigcentre = new Rectangle2D.Float(10 - shadowWidth / 2, 10 - shadowWidth / 2, 30 + shadowWidth, 30 + shadowWidth); 255 | 256 | //合并Shape 257 | Area area = new Area(centre); 258 | area.add(new Area(shape1)); 259 | area.add(new Area(shape2)); 260 | //合并大Shape 261 | Area bigarea = new Area(bigcentre); 262 | bigarea.add(new Area(bigshape1)); 263 | bigarea.add(new Area(bigshape2)); 264 | List list = new ArrayList(); 265 | list.add(area); 266 | list.add(bigarea); 267 | return list; 268 | } 269 | 270 | 271 | //处理小图的边缘灯光及其阴影效果 272 | private BufferedImage dealLightAndShadow(BufferedImage bfm, Shape shape) throws IOException { 273 | //创建新的透明图层,该图层用于边缘化阴影, 将生成的小图合并到该图上 274 | BufferedImage buffimg = ((Graphics2D) bfm.getGraphics()).getDeviceConfiguration().createCompatibleImage(50, 50, Transparency.TRANSLUCENT); 275 | Graphics2D graphics2D = buffimg.createGraphics(); 276 | Graphics2D g2 = (Graphics2D) bfm.getGraphics(); 277 | //原有小图,边缘亮色处理 278 | paintBorderGlow(g2, lightHeightWidth, shape); 279 | //新图层添加阴影 280 | paintBorderShadow(graphics2D, shadowWidth, shape); 281 | graphics2D.drawImage(bfm, 0, 0, null); 282 | return buffimg; 283 | } 284 | 285 | /** 286 | * 处理阴影 287 | * @param g2 288 | * @param shadowWidth 289 | * @param clipShape 290 | */ 291 | private void paintBorderShadow(Graphics2D g2, int shadowWidth, Shape clipShape) { 292 | g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 293 | int sw = shadowWidth * 2; 294 | for (int i = sw; i >= 2; i -= 2) { 295 | float pct = (float) (sw - i) / (sw - 1); 296 | //pct<03. 用于去掉阴影边缘白边, pct>0.8用于去掉过深的色彩, 如果使用Color.lightGray. 可去掉pct>0.8 297 | if (pct < 0.3 || pct > 0.8) { 298 | continue; 299 | } 300 | g2.setColor(getMixedColor(new Color(54, 54, 54), pct, Color.WHITE, 1.0f - pct)); 301 | g2.setStroke(new BasicStroke(i)); 302 | g2.draw(clipShape); 303 | } 304 | } 305 | 306 | private static final Color clrGlowInnerHi = new Color(253, 239, 175, 148); 307 | private static final Color clrGlowInnerLo = new Color(255, 209, 0); 308 | private static final Color clrGlowOuterHi = new Color(253, 239, 175, 124); 309 | private static final Color clrGlowOuterLo = new Color(255, 179, 0); 310 | 311 | /** 312 | * 处理边缘亮色 313 | * @param g2 314 | * @param glowWidth 315 | * @param clipShape 316 | */ 317 | public void paintBorderGlow(Graphics2D g2, int glowWidth, Shape clipShape) { 318 | int gw = glowWidth * 2; 319 | for (int i = gw; i >= 2; i -= 2) { 320 | float pct = (float) (gw - i) / (gw - 1); 321 | Color mixHi = getMixedColor(clrGlowInnerHi, pct, clrGlowOuterHi, 1.0f - pct); 322 | Color mixLo = getMixedColor(clrGlowInnerLo, pct, clrGlowOuterLo, 1.0f - pct); 323 | g2.setPaint(new GradientPaint(0.0f, 35 * 0.25f, mixHi, 0.0f, 35, mixLo)); 324 | g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, pct)); 325 | g2.setStroke(new BasicStroke(i)); 326 | g2.draw(clipShape); 327 | } 328 | } 329 | 330 | private static Color getMixedColor(Color c1, float pct1, Color c2, float pct2) { 331 | float[] clr1 = c1.getComponents(null); 332 | float[] clr2 = c2.getComponents(null); 333 | for (int i = 0; i < clr1.length; i++) { 334 | clr1[i] = (clr1[i] * pct1) + (clr2[i] * pct2); 335 | } 336 | return new Color(clr1[0], clr1[1], clr1[2], clr1[3]); 337 | } 338 | 339 | //创建圆形区域, 半径为5 type , 0:上方,1:右方 2:下方,3:左方 340 | private Shape createShape(int type, int size, int position) { 341 | Arc2D.Float d; 342 | if (type == 0) { 343 | //上 344 | d = new Arc2D.Float(position, 5, 10 + size, 10 + size, 0, 190, Arc2D.CHORD); 345 | } else if (type == 1) { 346 | //右 347 | d = new Arc2D.Float(35, position, 10 + size, 10 + size, 270, 190, Arc2D.CHORD); 348 | } else if (type == 2) { 349 | //下 350 | d = new Arc2D.Float(position, 35, 10 + size, 10 + size, 180, 190, Arc2D.CHORD); 351 | } else if (type == 3) { 352 | //左 353 | d = new Arc2D.Float(5, position, 10 + size, 10 + size, 90, 190, Arc2D.CHORD); 354 | } else { 355 | d = new Arc2D.Float(5, position, 10 + size, 10 + size, 90, 190, Arc2D.CHORD); 356 | } 357 | return d; 358 | } 359 | 360 | } 361 | --------------------------------------------------------------------------------