├── 滑块验证码.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 |
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 |
--------------------------------------------------------------------------------