下面我举的例子是,前端通过ajax+bootstrap的模态框,向服务器获取验证码图片。
效果:
如何实现呢?
1、第一种:
一般向服务器请求图片时,都是将图片保存在服务器上,再将网络地址URL返回,前端通过URL获取图片。
前端代码:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ include file="/resources/base/taglib.jsp"%> <html> <head> <title>Title</title> <script src="<c:url value='/resources/YQQ/js/jquery-3.1.0.min.js'/>"></script> <script src="<c:url value='/resources/YQQ/js/bootstrap.min.js'/>"></script> <link href="<c:url value='/resources/YQQ/css/bootstrap.min.css'/>" rel="stylesheet"> </head> <body> <button class="btn btn-primary btn-lg" data-toggle="modal" data-target="#myModal" onclick="getCode()"> 获取验证码 </button> <!-- 模态框(Modal) --> <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">× </button> <h4 class="modal-title" id="myModalLabel"> 请输入验证码: </h4> </div> <div class="modal-body"> <img src="" id="code"> <input type="text" id="codeText"> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">关闭 </button> <button type="button" class="btn btn-primary" onclick="mnLogin()"> 提交 </button> </div> </div><!-- /.modal-content --> </div><!-- /.modal-dialog --> </div><!-- /.modal --> </body> <script> function getCode() { $("#code").attr("src", ""); $.ajax({ url: '${base}/bbm/getCode', type: "post", success: function (data) { setTimeout(function(){}, 500); $("#code").attr("src", data); } }) }</script> </html>
后端代码
@ResponseBody @RequestMapping("getCode") public String getCode(HttpServletRequest request){ System.out.println("===="); try { String imgURLPath = TestLogin.getCode(request); return imgURLPath; } catch (IOException e) { e.printStackTrace(); } return ""; }
// 将验证码图片保存到服务器,并返回url访问地址 public static String getCode(HttpServletRequest request) throws IOException { /*这一段是请求接口,获取验证码的图片*/ HttpGet get = new HttpGet("xxxx"); // 创建一个http客户端 CloseableHttpClient httpClient = HttpClientBuilder.create().setDefaultCookieStore(COOKIE).build(); // 发送get请求 HttpResponse response = httpClient.execute(get); byte[] bytes = EntityUtils.toByteArray(response.getEntity()); /*这一段是请求接口,获取验证码的图片*/ // 文件存放路径 String realPath = request.getServletContext().getRealPath("/resources"); // 文件名称 code.jpg String fileName = "code.jpg"; // 文件输出 File file = new File(realPath, fileName); FileOutputStream fileOutputStream = new FileOutputStream(file); fileOutputStream.write(bytes); fileOutputStream.close(); String urlPath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath() + "/resources/" + fileName; return urlPath; }
第一种方式,存在的问题:
1)第一次访问验证码没有问题,但是关闭模态框后,再次点开发现验证码并没有发生改变,而服务器上保存的图片却改变了。
解决方法:
只需要在请求验证码图片的url后面加入不同的参数,保证浏览器不会因为请求地址url相同,而直接从缓存中读取。
$("#code").attr("src", data + "?datetime=" + new Date().getTime() + Math.round(Math.random()*100));
2)但是修改之后,又出现新的问题:请求过快导致图片无法正常显示,并且不能够保证浏览器还是会从缓存中读取图片。
2、第二种:
因为将图片保存到服务器时,由于网络的原因有时候会慢,所以前端访问的时候,可能图片还没有保存到服务器,而导致图片无法正常显示。
解决方式:先将图片转为byte字节数组,再转为base64编码的字符串,传递给前端,前端显示显示出来即可。
为什么要使用base64编码的图片?
可以减少http请求,一个请求相当于一个网络开销。第一种方式,还需要再次发起http请求。
后端代码
@ResponseBody @RequestMapping("getCode") public String getCode(HttpServletRequest request){ try { byte[] codeBytes = TestLogin.getCodeBytes(); //定义一个BASE64Encoder BASE64Encoder encode = new BASE64Encoder(); //将byte[]转换为base64 String base64 = encode.encode(codeBytes); return base64; } catch (IOException e) { e.printStackTrace(); } return null; }
前端代码
function getCode() { $("#code").attr("src", ""); $.ajax({ url: '${base}/bbm/getCode', type: "post", success: function (data) { if (data!=null){ str = 'data:image/png;base64,' + data; $("#code").attr("src", str); }else{ alert("错误"); } } }) }
这样的话,无论关闭模态框 / 显示模态框,点击多快,都不会出现验证码图片显示不正常的请求,也保证每次的验证码都是不同的。