最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

js+java實(shí)現(xiàn)登錄滑動(dòng)圖片驗(yàn)證

 更新時(shí)間:2020年09月29日 15:53:23   作者:YongHon  
這篇文章主要為大家詳細(xì)介紹了js+java實(shí)現(xiàn)登錄滑動(dòng)圖片驗(yàn)證,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

最新需要公司要求在不改變?cè)瓉?lái)的登錄邏輯的情況下,將原來(lái)的驗(yàn)證碼登錄的形式改成滑動(dòng)圖片的形式!下面是做出來(lái)的效果:

實(shí)現(xiàn)思路:所有的圖片數(shù)據(jù),驗(yàn)證全部由后端來(lái)做。前端調(diào)用接口,后端會(huì)返回兩張經(jīng)過(guò)base64加密的圖片信息,分別是背景圖片和滑塊圖片,前端滑動(dòng)滑塊以后將X方向的滑動(dòng)距離傳回后端做驗(yàn)證,驗(yàn)證成功以后再做后續(xù)的登錄邏輯驗(yàn)證,以下是完整的過(guò)程:

獲取背景圖,我這邊是在FTP上放了10張圖片,隨機(jī)獲取一張。

@LogAnnotation(description = "web獲取滑動(dòng)圖片信息")
 @ApiOperation(value = "web獲取滑動(dòng)圖片信息", httpMethod = "POST", response = Result.class, notes = "")
 @RequiresPermissions(value = "code/picture/msg")
 @RequestMapping(value = "code/picture/msg", method = RequestMethod.POST)
 @ResponseBody
 public Response getPictureCode(HttpServletRequest request) {
 Map<String, Object> pictureMap = new HashMap<>();
 try {
 //隨機(jī)獲取需要切成的圖片形狀
 Integer templateNum = new Random().nextInt(10) + 1;
 String randomStr = String.valueOf(templateNum);
 if(templateNum < 10){
 randomStr = "0"+randomStr;
 }
 InputStream tempInputStream = FileUtils.downloadFtpFile(Constant.POCTURE_CHECK_PATH,randomStr+".jpg");
 //根據(jù)源圖片和摳圖形狀生成新的圖片信息以流的形式返回到前端
 pictureMap = VerifyImageUtil.getVerifyImage(tempInputStream);
 //將剪裁好了以后的圖片信息以當(dāng)前時(shí)間戳為key,存入redis(這一步是為了對(duì)圖片信息做過(guò)期處理,根據(jù)自己需求做)
 String tempTime = String.valueOf(System.currentTimeMillis());
 redisUtils.hset(Constant.REDIS_LOGIN_PICTURE_CODE, tempTime,pictureMap.get("locationX").toString(),60);
 pictureMap.put("tempTime",tempTime);
 //移出隨機(jī)生成的摳圖位置坐標(biāo),不返回給前端
 pictureMap.remove("locationX");
 return new ObjectResponse<Map<String, Object>>(pictureMap);
 }catch(Exception e){
 logger.error("code/picture/msg", e);
 return new FailedResponse();
 }
 }

FTP下載方法代碼

public static FTPClient ftpLogin(){
 String ip = p.getProperty("ftp的ip");
 String username = p.getProperty("ftp的user");
 String password = p.getProperty("ftp的pwd");
 int ftpPort = Integer.parseInt(p.getProperty("ftp的port"));
 FTPClient ftpClient = new FTPClient();
 try { 
  ftpClient.connect(ip , ftpPort );// 連接FTP服務(wù)器 
  ftpClient.login(username , password );// 登陸FTP服務(wù)器 
  if (!FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) { 
  ftpClient.disconnect(); 
  }
 } catch (SocketException e) { 
  e.printStackTrace(); 
 } catch (IOException e) { 
  e.printStackTrace(); 
 } 
 return ftpClient;
 }
 
public static InputStream downloadFtpFile(String ftpPath, String fileName) { 
 FTPClient ftpClient = ftpLogin();
 try {
  ftpClient.setControlEncoding("UTF-8"); // 中文支持 
  ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE); 
  ftpClient.enterLocalPassiveMode(); 
  ftpClient.changeWorkingDirectory(ftpPath); 
  InputStream inputStream = ftpClient.retrieveFileStream(new String(fileName.getBytes("UTF-8"), "ISO-8859-1"));
  //ftpClient.completePendingCommand();
  return inputStream;
 } catch (Exception e) { 
  e.printStackTrace(); 
 }finally {
  try {
 ftpClient.logout();
 } catch (IOException e) {
 e.printStackTrace();
 } 
 }
 return null;
 } 

摳圖工具類VerifyImageUtil

public class VerifyImageUtil {
 
 /**
 * 源文件寬度
 */
 private static int ORI_WIDTH = 296;
 /**
 * 源文件高度
 */
 private static int ORI_HEIGHT = 182;
 /**
 * 模板圖寬度
 */
 private static int CUT_WIDTH = 50;
 /**
 * 模板圖高度
 */
 private static int CUT_HEIGHT = 50;
 /**
 * 摳圖凸起圓心
 */
 private static int circleR = 6;
 /**
 * 摳圖內(nèi)部矩形填充大小
 */
 private static int RECTANGLE_PADDING = 6;
 /**
 * 摳圖的邊框?qū)挾?
 */
 private static int SLIDER_IMG_OUT_PADDING = 1;
 
 
 /**
 * 根據(jù)傳入的路徑生成指定驗(yàn)證碼圖片
 *
 * @param filePath
 * @return
 * @throws IOException
 */
 public static Map<String, Object> getVerifyImage(InputStream filePath) throws IOException {
 BufferedImage srcImage = ImageIO.read(filePath);
 int locationX = CUT_WIDTH + new Random().nextInt(srcImage.getWidth() - CUT_WIDTH * 2);
 int locationY = CUT_HEIGHT + new Random().nextInt(srcImage.getHeight() - CUT_HEIGHT) / 2;
 BufferedImage markImage = new BufferedImage(CUT_WIDTH,CUT_HEIGHT,BufferedImage.TYPE_4BYTE_ABGR);
 int[][] data = getBlockData();
 cutImgByTemplate(srcImage, markImage, data, locationX, locationY);
 Map<String, Object> resultMap = new HashMap<>();
 //放入背景圖的加密信息
 resultMap.put("srcImage",getImageBASE64(srcImage));
 //放入滑塊圖的加密信息
 resultMap.put("markImage",getImageBASE64(markImage));
 //放入摳圖位置的X方向的信息,用于驗(yàn)證滑塊位置是否正確
 resultMap.put("locationX",locationX);
 //放入摳圖位置的Y方向的信息,用于前端控制定位信息
 resultMap.put("locationY",locationY);
 return resultMap;
 }
 
 
 /**
 * 生成隨機(jī)滑塊形狀
 * <p>
 * 0 透明像素
 * 1 滑塊像素
 * 2 陰影像素
 * @return int[][]
 */
 private static int[][] getBlockData() {
 int[][] data = new int[CUT_WIDTH][CUT_HEIGHT];
 Random random = new Random();
 //(x-a)²+(y-b)²=r²
 //x中心位置左右5像素隨機(jī)
 double x1 = RECTANGLE_PADDING + (CUT_WIDTH - 2 * RECTANGLE_PADDING) / 2.0 - 5 + random.nextInt(10);
 //y 矩形上邊界半徑-1像素移動(dòng)
 double y1_top = RECTANGLE_PADDING - random.nextInt(3);
 double y1_bottom = CUT_HEIGHT - RECTANGLE_PADDING + random.nextInt(3);
 double y1 = random.nextInt(2) == 1 ? y1_top : y1_bottom;
 
 
 double x2_right = CUT_WIDTH - RECTANGLE_PADDING - circleR + random.nextInt(2 * circleR - 4);
 double x2_left = RECTANGLE_PADDING + circleR - 2 - random.nextInt(2 * circleR - 4);
 double x2 = random.nextInt(2) == 1 ? x2_right : x2_left;
 double y2 = RECTANGLE_PADDING + (CUT_HEIGHT - 2 * RECTANGLE_PADDING) / 2.0 - 4 + random.nextInt(10);
 
 double po = Math.pow(circleR, 2);
 for (int i = 0; i < CUT_WIDTH; i++) {
 for (int j = 0; j < CUT_HEIGHT; j++) {
 //矩形區(qū)域
 boolean fill;
 if ((i >= RECTANGLE_PADDING && i < CUT_WIDTH - RECTANGLE_PADDING)
 && (j >= RECTANGLE_PADDING && j < CUT_HEIGHT - RECTANGLE_PADDING)) {
 data[i][j] = 1;
 fill = true;
 } else {
 data[i][j] = 0;
 fill = false;
 }
 //凸出區(qū)域
 double d3 = Math.pow(i - x1, 2) + Math.pow(j - y1, 2);
 if (d3 < po) {
 data[i][j] = 1;
 } else {
 if (!fill) {
 data[i][j] = 0;
 }
 }
 //凹進(jìn)區(qū)域
 double d4 = Math.pow(i - x2, 2) + Math.pow(j - y2, 2);
 if (d4 < po) {
 data[i][j] = 0;
 }
 }
 }
 //邊界陰影
 for (int i = 0; i < CUT_WIDTH; i++) {
 for (int j = 0; j < CUT_HEIGHT; j++) {
 //四個(gè)正方形邊角處理
 for (int k = 1; k <= SLIDER_IMG_OUT_PADDING; k++) {
 //左上、右上
 if (i >= RECTANGLE_PADDING - k && i < RECTANGLE_PADDING
 && ((j >= RECTANGLE_PADDING - k && j < RECTANGLE_PADDING)
 || (j >= CUT_HEIGHT - RECTANGLE_PADDING - k && j < CUT_HEIGHT - RECTANGLE_PADDING +1))) {
 data[i][j] = 2;
 }
 
 //左下、右下
 if (i >= CUT_WIDTH - RECTANGLE_PADDING + k - 1 && i < CUT_WIDTH - RECTANGLE_PADDING + 1) {
 for (int n = 1; n <= SLIDER_IMG_OUT_PADDING; n++) {
 if (((j >= RECTANGLE_PADDING - n && j < RECTANGLE_PADDING)
  || (j >= CUT_HEIGHT - RECTANGLE_PADDING - n && j <= CUT_HEIGHT - RECTANGLE_PADDING ))) {
 data[i][j] = 2;
 }
 }
 }
 }
 
 if (data[i][j] == 1 && j - SLIDER_IMG_OUT_PADDING > 0 && data[i][j - SLIDER_IMG_OUT_PADDING] == 0) {
 data[i][j - SLIDER_IMG_OUT_PADDING] = 2;
 }
 if (data[i][j] == 1 && j + SLIDER_IMG_OUT_PADDING > 0 && j + SLIDER_IMG_OUT_PADDING < CUT_HEIGHT && data[i][j + SLIDER_IMG_OUT_PADDING] == 0) {
 data[i][j + SLIDER_IMG_OUT_PADDING] = 2;
 }
 if (data[i][j] == 1 && i - SLIDER_IMG_OUT_PADDING > 0 && data[i - SLIDER_IMG_OUT_PADDING][j] == 0) {
 data[i - SLIDER_IMG_OUT_PADDING][j] = 2;
 }
 if (data[i][j] == 1 && i + SLIDER_IMG_OUT_PADDING > 0 && i + SLIDER_IMG_OUT_PADDING < CUT_WIDTH && data[i + SLIDER_IMG_OUT_PADDING][j] == 0) {
 data[i + SLIDER_IMG_OUT_PADDING][j] = 2;
 }
 }
 }
 return data;
 }
 
 /**
 * 裁剪區(qū)塊
 * 根據(jù)生成的滑塊形狀,對(duì)原圖和裁剪塊進(jìn)行變色處理
 * @param oriImage 原圖
 * @param targetImage 裁剪圖
 * @param blockImage 滑塊
 * @param x  裁剪點(diǎn)x
 * @param y  裁剪點(diǎn)y
 */
 private static void cutImgByTemplate(BufferedImage oriImage, BufferedImage targetImage, int[][] blockImage, int x, int y) {
 for (int i = 0; i < CUT_WIDTH; i++) {
 for (int j = 0; j < CUT_HEIGHT; j++) {
 int _x = x + i;
 int _y = y + j;
 int rgbFlg = blockImage[i][j];
 int rgb_ori = oriImage.getRGB(_x, _y);
 // 原圖中對(duì)應(yīng)位置變色處理
 if (rgbFlg == 1) {
 //摳圖上復(fù)制對(duì)應(yīng)顏色值
 targetImage.setRGB(i,j, rgb_ori);
 //原圖對(duì)應(yīng)位置顏色變化
 oriImage.setRGB(_x, _y, rgb_ori & 0x363636);
 } else if (rgbFlg == 2) {
 targetImage.setRGB(i, j, Color.WHITE.getRGB());
 oriImage.setRGB(_x, _y, Color.GRAY.getRGB());
 }else if(rgbFlg == 0){
 //int alpha = 0;
 targetImage.setRGB(i, j, rgb_ori & 0x00ffffff);
 }
 }
 
 }
 }
 
 
 /**
 * 隨機(jī)獲取一張圖片對(duì)象
 * @param path
 * @return
 * @throws IOException
 */
 public static BufferedImage getRandomImage(String path) throws IOException {
 File files = new File(path);
 File[] fileList = files.listFiles();
 List<String> fileNameList = new ArrayList<>();
 if (fileList!=null && fileList.length!=0){
 for (File tempFile:fileList){
 if (tempFile.isFile() && tempFile.getName().endsWith(".jpg")){
 fileNameList.add(tempFile.getAbsolutePath().trim());
 }
 }
 }
 Random random = new Random();
 File imageFile = new File(fileNameList.get(random.nextInt(fileNameList.size())));
 return ImageIO.read(imageFile);
 }
 
 /**
 * 將IMG輸出為文件
 * @param image
 * @param file
 * @throws Exception
 */
 public static void writeImg(BufferedImage image, String file) throws Exception {
 byte[] imagedata = null;
 ByteArrayOutputStream bao=new ByteArrayOutputStream();
 ImageIO.write(image,"png",bao);
 imagedata = bao.toByteArray();
 FileOutputStream out = new FileOutputStream(new File(file));
 out.write(imagedata);
 out.close();
 }
 
 /**
 * 將圖片轉(zhuǎn)換為BASE64
 * @param image
 * @return
 * @throws IOException
 */
 public static String getImageBASE64(BufferedImage image) throws IOException {
 ByteArrayOutputStream out = new ByteArrayOutputStream();
 ImageIO.write(image,"png",out);
 //轉(zhuǎn)成byte數(shù)組
 byte[] bytes = out.toByteArray();
 BASE64Encoder encoder = new BASE64Encoder();
 //生成BASE64編碼
 return encoder.encode(bytes);
 }
 
 /**
 * 將BASE64字符串轉(zhuǎn)換為圖片
 * @param base64String
 * @return
 */
 public static BufferedImage base64StringToImage(String base64String) {
 try {
 BASE64Decoder decoder=new BASE64Decoder();
 byte[] bytes1 = decoder.decodeBuffer(base64String);
 ByteArrayInputStream bais = new ByteArrayInputStream(bytes1);
 return ImageIO.read(bais);
 } catch (IOException e) {
 e.printStackTrace();
 }
 return null;
 }
}

前端收到請(qǐng)求成功返回信息以后,對(duì)數(shù)據(jù)做解析

// 設(shè)置圖片的src屬性
 $("#背景圖的ID").attr("src", "data:image/png;base64," + result.datas.srcImage);
 $("#滑塊圖的ID").attr("src", "data:image/png;base64," + result.datas.markImage);
 $("#滑塊圖的ID").css("top", result.datas.locationY);
 /* 初始化按鈕拖動(dòng)事件 */
 // 鼠標(biāo)點(diǎn)擊事件
 $("#滑塊拖動(dòng)條").mousedown(function(e) {
 e = e || window.event;
 // 鼠標(biāo)在滑塊按下切換滑塊背景
 var left = e.pageX;//記錄鼠標(biāo)按下時(shí)的坐標(biāo) X軸值
 var num = 0;
 // 鼠標(biāo)移動(dòng)事件
 document.onmousemove = function(e) {
 var nowLeft = e.pageX;
 num = nowLeft-left;
 if(num <= 0){
 num = 0;
 }else if(num >= 251){
 num= 251;
 }
 $("#滑塊拖動(dòng)條").css("width", (42+num) + "px");
 $("#滑塊拖動(dòng)條圖片").css("left", (num) + "px");
 $("#滑塊拖動(dòng)條").css("background-color", "#3c55ff");
 };
 // 鼠標(biāo)松開(kāi)事件
 document.onmouseup = function(e) {
 left = 0;
 document.onmousemove = null;
 document.onmouseup = null;
   //松開(kāi)以后進(jìn)行后續(xù)的驗(yàn)證......
 
 };
 });

以上就是完整的過(guò)程了.

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • SpringBoot項(xiàng)目如何將Bean注入到普通類中

    SpringBoot項(xiàng)目如何將Bean注入到普通類中

    這篇文章主要介紹了SpringBoot項(xiàng)目如何將Bean注入到普通類中,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • Java實(shí)現(xiàn)監(jiān)聽(tīng)文件變化的三種方案詳解

    Java實(shí)現(xiàn)監(jiān)聽(tīng)文件變化的三種方案詳解

    這篇文章主要介紹了Java實(shí)現(xiàn)監(jiān)聽(tīng)文件變化的三種方法,每種方案給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-05-05
  • 詳解SpringBoot和SpringBatch 使用

    詳解SpringBoot和SpringBatch 使用

    Spring Batch 是一個(gè)輕量級(jí)的、完善的批處理框架,旨在幫助企業(yè)建立健壯、高效的批處理應(yīng)用。這篇文章主要介紹了詳解SpringBoot和SpringBatch 使用,需要的朋友可以參考下
    2018-07-07
  • Mybatis如何使用@Mapper和@MapperScan注解實(shí)現(xiàn)映射關(guān)系

    Mybatis如何使用@Mapper和@MapperScan注解實(shí)現(xiàn)映射關(guān)系

    這篇文章主要介紹了Mybatis使用@Mapper和@MapperScan注解實(shí)現(xiàn)映射關(guān)系,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • Spring Security基于散列加密方案實(shí)現(xiàn)自動(dòng)登錄功能

    Spring Security基于散列加密方案實(shí)現(xiàn)自動(dòng)登錄功能

    為了提高項(xiàng)目的用戶體驗(yàn),我們可以在項(xiàng)目中添加自動(dòng)登錄功能,當(dāng)然也要給用戶提供退出登錄的功能。接下來(lái)學(xué)習(xí)下Spring Security基于散列加密方案實(shí)現(xiàn)自動(dòng)登錄功能,一起看看吧
    2021-09-09
  • SpringBoot集成shiro,MyRealm中無(wú)法@Autowired注入Service的問(wèn)題

    SpringBoot集成shiro,MyRealm中無(wú)法@Autowired注入Service的問(wèn)題

    今天小編就為大家分享一篇關(guān)于SpringBoot集成shiro,MyRealm中無(wú)法@Autowired注入Service的問(wèn)題,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2019-03-03
  • Springboot+TCP監(jiān)聽(tīng)服務(wù)器搭建過(guò)程圖解

    Springboot+TCP監(jiān)聽(tīng)服務(wù)器搭建過(guò)程圖解

    這篇文章主要介紹了Springboot+TCP監(jiān)聽(tīng)服務(wù)器搭建過(guò)程,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-10-10
  • SpringCloud組件性能優(yōu)化的技巧

    SpringCloud組件性能優(yōu)化的技巧

    這篇文章主要介紹了SpringCloud組件性能優(yōu)化的技巧,Springcloud?原始的配置,性能是很低的,大家可以使用?Jmeter?測(cè)試一下,QPS?不會(huì)到?50,要做到高并發(fā),需要做不少的配置優(yōu)化,需要的朋友可以參考下
    2023-09-09
  • Java多線程中的原子類屬性說(shuō)明

    Java多線程中的原子類屬性說(shuō)明

    這篇文章主要介紹了Java多線程中的原子類屬性說(shuō)明,對(duì)多線程訪問(wèn)同一個(gè)變量,我們需要加鎖,而鎖是比較消耗性能的,JDk1.5之后,新增的原子操作類提供了一種用法簡(jiǎn)單、性能高效、線程安全地更新一個(gè)變量的方式,需要的朋友可以參考下
    2023-10-10
  • Java從入門到起飛之?dāng)?shù)組使用詳解

    Java從入門到起飛之?dāng)?shù)組使用詳解

    這篇文章主要介紹了Java從入門到起飛之?dāng)?shù)組使用的相關(guān)資料,包括數(shù)組的聲明、初始化、長(zhǎng)度、索引、遍歷和默認(rèn)值等內(nèi)容,還介紹了Arrays工具類中常用的方法,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2025-03-03

最新評(píng)論

阳江市| 福贡县| 含山县| 靖安县| 兴文县| 汕尾市| 崇义县| 江西省| 光山县| 清水河县| 扬中市| 武安市| 惠州市| 惠州市| 同仁县| 南澳县| 崇文区| 沂源县| 贡嘎县| 苏尼特右旗| 中超| 德庆县| 白朗县| 女性| 专栏| 淳化县| 茶陵县| 湄潭县| 通江县| 武清区| 永和县| 桐梓县| 镇雄县| 满洲里市| 宝山区| 昌图县| 英超| 龙泉市| 白河县| 民县| 峨边|