成都网站开发技术珠海网站开发定制

news/2025/9/27 12:26:21/文章来源:
成都网站开发技术,珠海网站开发定制,城乡住房建设厅网站,利用国外网站文章图片做书营利前言 目前网页的主流登录方式是通过手机扫码二维码登录。我看了网上很多关于扫码登录博客后#xff0c;发现基本思路大致是#xff1a;打开网页#xff0c;生成uuid#xff0c;然后长连接请求后端并等待登录认证相应结果#xff0c;而后端每个几百毫秒会循环查询数据库或r…前言     目前网页的主流登录方式是通过手机扫码二维码登录。我看了网上很多关于扫码登录博客后发现基本思路大致是打开网页生成uuid然后长连接请求后端并等待登录认证相应结果而后端每个几百毫秒会循环查询数据库或redis当查询到登录信息后则响应长连接的请求。 然而如果是小型应用则没问题如果用户量并发大则会出现非常严重的性能瓶颈。而问题的关键是使用了循环查询数据库或redis的方案。假设要优化这个方案可以使用java多线程的同步集合CountDownLatch来解决。   一、环境   1.java 8(jdk1.8) 2.maven 3.3.9 3.spring boot 2.0   二、知识点   1.同步集合使用 2.CountDownLatch使用 3.http ajax 4.zxing二维码生成   三、流程及实现原理   1.打开网页通过ajax请求获取二维码图片地址 2.页面渲染二维码图片并通过长连接请求获取后端的登录认证信息 3.事先登录过APP的手机扫码二维码然后APP请求服务器端的API接口把用户认证信息传递到服务器中。 4.后端收到APP的请求后唤醒长连接的等待线程并把用户认证信息写入session。 5.页面得到长连接的响应并跳转到首页。 整个流程图下图所示      四、代码编写     pom.xml文件如下 ?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersiongroupIdcom.demo/groupIdartifactIdauth/artifactIdversion0.0.1-SNAPSHOT/versionpackagingjar/packagingnameauth/namedescription二维码登录/descriptionparentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion2.0.0.RELEASE/versionrelativePath / !-- lookup parent from repository --/parentpropertiesproject.build.sourceEncodingUTF-8/project.build.sourceEncodingproject.reporting.outputEncodingUTF-8/project.reporting.outputEncodingjava.version1.8/java.version/propertiesdependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-thymeleaf/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-devtools/artifactIdscoperuntime/scope/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependency!-- zxing --dependencygroupIdcom.google.zxing/groupIdartifactIdcore/artifactIdversion3.3.0/version/dependencydependencygroupIdcom.google.zxing/groupIdartifactIdjavase/artifactIdversion3.3.0/version/dependencydependencygroupIdcommons-codec/groupIdartifactIdcommons-codec/artifactId/dependency/dependenciesbuildpluginsplugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactId/plugin/plugins/build/project pom.xml     首先参照《玩转spring boot——简单登录认证》完成简单登录认证。在浏览器中输入http://localhost:8080页面时由于未登录认证则重定向到http://localhost:8080/login页面 代码如下 package com.demo.auth;import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession;import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;/*** 登录配置 博客出处http://www.cnblogs.com/GoodHelper/**/ Configuration public class WebSecurityConfig implements WebMvcConfigurer {/*** 登录session key*/public final static String SESSION_KEY user;Beanpublic SecurityInterceptor getSecurityInterceptor() {return new SecurityInterceptor();}public void addInterceptors(InterceptorRegistry registry) {InterceptorRegistration addInterceptor registry.addInterceptor(getSecurityInterceptor());// 排除配置addInterceptor.excludePathPatterns(/error);addInterceptor.excludePathPatterns(/login);addInterceptor.excludePathPatterns(/login/**);// 拦截配置addInterceptor.addPathPatterns(/**);}private class SecurityInterceptor extends HandlerInterceptorAdapter {Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {HttpSession session request.getSession();if (session.getAttribute(SESSION_KEY) ! null)return true;// 跳转登录String url /login;response.sendRedirect(url);return false;}} }     其次新建控制器类MainController /*** 控制器* * author 刘冬博客http://www.cnblogs.com/GoodHelper**/ Controller public class MainController {GetMapping({ /, index })public String index(Model model, SessionAttribute(WebSecurityConfig.SESSION_KEY) String user) {model.addAttribute(user, user);return index;}GetMapping(login)public String login() {return login;} }   新建两个html页面index.html和login.html !DOCTYPE html html xmlns:thhttp://www.thymeleaf.org head meta charsetUTF-8 title二维码登录/title /head bodyh1二维码登录/h1h4a target_blank hrefhttp://www.cnblogs.com/GoodHelper/from刘冬的博客/a/h4h3 th:text登录用户 ${user}/h3 /body /html   !DOCTYPE html html xmlns:thhttp://www.thymeleaf.org head meta charsetUTF-8 title二维码登录/title script src//cdn.bootcss.com/angular.js/1.5.6/angular.min.js/script script typetext/javascript/*![CDATA[*/var app angular.module(app, []);app.controller(MainController, function($rootScope, $scope, $http) {//二维码图片src$scope.src null;//获取二维码$scope.getQrCode function() {$http.get(/login/getQrCode).success(function(data) {if (!data || !data.loginId || !data.image)return;$scope.src data:image/png;base64, data.image$scope.getResponse(data.loginId)});}//获取登录响应$scope.getResponse function(loginId) {$http.get(/login/getResponse/ loginId).success(function(data) {//一秒后重新获取登录二维码if (!data || !data.success) {setTimeout($scope.getQrCode(), 1000);return;}//登录成功进去首页location.href /}).error(function(data, status) {console.log(data)console.log(status)//一秒后重新获取登录二维码setTimeout($scope.getQrCode(), 1000);})}$scope.getQrCode();});/*]]*/ /script /head body ng-appapp ng-controllerMainControllerh1扫码登录/h1h4a target_blank hrefhttp://www.cnblogs.com/GoodHelper/from刘冬的博客/a/h4img ng-showsrc ng-src{{src}} / /body /html   login.html页面先请求后端服务器获取登录uuid然后获取到服务器的二维码后在页面渲染二维码。接着使用长连接请求并等待服务器的相应。   然后新建一个承载登录信息的类LoginResponse package com.demo.auth;import java.util.concurrent.CountDownLatch;/*** 登录信息承载类* * author 刘冬博客http://www.cnblogs.com/GoodHelper**/ public class LoginResponse {public CountDownLatch latch;public String user;// 省略 get set }     最后修改MainController类最终的代码如下 package com.demo.auth;import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.util.HashMap; import java.util.Hashtable; import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit;import javax.imageio.ImageIO; import javax.servlet.http.HttpSession;import org.apache.commons.codec.binary.Base64; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.SessionAttribute;import com.google.zxing.BarcodeFormat; import com.google.zxing.EncodeHintType; import com.google.zxing.MultiFormatWriter; import com.google.zxing.common.BitMatrix; import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;/*** 控制器* * author 刘冬博客http://www.cnblogs.com/GoodHelper**/ Controller public class MainController {/*** 存储登录状态*/private MapString, LoginResponse loginMap new ConcurrentHashMap();GetMapping({ /, index })public String index(Model model, SessionAttribute(WebSecurityConfig.SESSION_KEY) String user) {model.addAttribute(user, user);return index;}GetMapping(login)public String login() {return login;}/*** 获取二维码* * return*/GetMapping(login/getQrCode)public ResponseBody MapString, Object getQrCode() throws Exception {MapString, Object result new HashMap();result.put(loginId, UUID.randomUUID());// app端登录地址String loginUrl http://localhost:8080/login/setUser/loginId/;result.put(loginUrl, loginUrl);result.put(image, createQrCode(loginUrl));return result;}/*** app二维码登录地址这里为了测试才传{user},实际项目中user是通过其他方式传值* * param loginId* param user* return*/GetMapping(login/setUser/{loginId}/{user})public ResponseBody MapString, Object setUser(PathVariable String loginId, PathVariable String user) {if (loginMap.containsKey(loginId)) {LoginResponse loginResponse loginMap.get(loginId);// 赋值登录用户loginResponse.user user;// 唤醒登录等待线程loginResponse.latch.countDown();}MapString, Object result new HashMap();result.put(loginId, loginId);result.put(user, user);return result;}/*** 等待二维码扫码结果的长连接* * param loginId* param session* return*/GetMapping(login/getResponse/{loginId})public ResponseBody MapString, Object getResponse(PathVariable String loginId, HttpSession session) {MapString, Object result new HashMap();result.put(loginId, loginId);try {LoginResponse loginResponse null;if (!loginMap.containsKey(loginId)) {loginResponse new LoginResponse();loginMap.put(loginId, loginResponse);} elseloginResponse loginMap.get(loginId);// 第一次判断// 判断是否登录,如果已登录则写入sessionif (loginResponse.user ! null) {session.setAttribute(WebSecurityConfig.SESSION_KEY, loginResponse.user);result.put(success, true);return result;}if (loginResponse.latch null) {loginResponse.latch new CountDownLatch(1);}try {// 线程等待loginResponse.latch.await(5, TimeUnit.MINUTES);} catch (Exception e) {e.printStackTrace();}// 再次判断// 判断是否登录,如果已登录则写入sessionif (loginResponse.user ! null) {session.setAttribute(WebSecurityConfig.SESSION_KEY, loginResponse.user);result.put(success, true);return result;}result.put(success, false);return result;} finally {// 移除登录请求if (loginMap.containsKey(loginId))loginMap.remove(loginId);}}/*** 生成base64二维码* * param content* return* throws Exception*/private String createQrCode(String content) throws Exception {try (ByteArrayOutputStream out new ByteArrayOutputStream()) {HashtableEncodeHintType, Object hints new HashtableEncodeHintType, Object();hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);hints.put(EncodeHintType.CHARACTER_SET, utf-8);hints.put(EncodeHintType.MARGIN, 1);BitMatrix bitMatrix new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, 400, 400, hints);int width bitMatrix.getWidth();int height bitMatrix.getHeight();BufferedImage image new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);for (int x 0; x width; x) {for (int y 0; y height; y) {image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);}}ImageIO.write(image, JPG, out);return Base64.encodeBase64String(out.toByteArray());}}}   其中使用  MapString, LoginResponse loginMap类存储登录请求信息 createQrCode方法是用于生成二维码 getQrCode方法是给页面返回登录uuid和二维码前端页面拿到登录uuid后请求长连接等待二维码的扫码登录结果。 setUser方法是提供给APP端调用的在此过程中通过uuid找到对应的CountDownLatch并唤醒长连接的线程。而这里是为了做演示才把这个方法放到这个类里在实际项目中此方法不一定在这个类里或未必在同一个后端中。另外我把用户信息的传递也写在这个方法中了而实际项目是通过其他的方式来传递用户信息这里仅仅是为了演示方便。 getResponse方法是处理ajax的长连接并使用CountDownLatch等待APP端来唤醒这个线程然后把用户信息写入session。    入口类App.java package com.demo.auth;import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;SpringBootApplication public class App {public static void main(String[] args) {SpringApplication.run(App.class, args);} }    项目结构如下图所示    五、总结   打开浏览器输入http://localhost:8080。运行效果如下图所以     使用CountDownLatch则避免了每隔500毫秒读一次数据库或redis的频繁查询性能问题。因为操作的是内存数据所以性能非常高。 而CountDownLatch是java多线程中非常实用的类二维码扫码登录就是一个具有代表意义的应用场景。当然如果你不嫌代码量大也可以用waitnotify来实现。另在java.util.concurrent包下也有很多的多线程类能到达同样的目的我这里就不一一例举了。   根据园友的建议我发现本篇文章里的线程阻塞是设计缺陷所以不循环查询数据库或redis里但一台服务器的线程数是有限的。在下篇我会改进这个设计   代码下载   如果你觉得我的博客对你有帮助可以给我点儿打赏左侧微信右侧支付宝。 有可能就是你的一点打赏会让我的博客写的更好:)   返回玩转spring boot系列目录   作者刘冬.NET 博客地址http://www.cnblogs.com/GoodHelper/ 欢迎转载但须保留版权 转载于:https://www.cnblogs.com/GoodHelper/p/8641905.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/916608.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

dw做的网站有什么缺陷河南网站优化排名

10月16日,企业科技盛会HPE Discover More AI 2024在香港瑰丽酒店举行。本次大会Hewlett Packard Enterprise (HPE) 联同全球14个科技合作伙伴,聚焦于AI未来走势、混合云创新与边缘安全等领域,以主题演讲、技术展示、研讨会等形式进行&#xf…

做mla的网站安康平台

【(精华版)最新国家开放大学电大本科《计算机应用基础》网络课网考形考作业一及三试题答案】(精华版)最新国家开放大学电大本科《计算机应用基础》网络课网考形考作业一及三试题答案 盗传必究 形考作业一 一、单选题 1当前的计算机一般被认为是第四代计算机,它所采用…

读人形机器人22工作的意义

读人形机器人22工作的意义1. 工作的意义 1.1. 工作的本质正在被重新定义 1.2. 当机器人和AI接管曾被认为是独属于人类的任务时,社会必须面对关于身份、目标和成就感的深刻问题 2. 工作是身份认同的源泉 2.1. 几个世纪…

.NET 何以成为制造业数字化转型的基石:效率、生态与跨平台的制胜之道

在制造业,特别是半导体设备通信领域,.NET因其开发效率、跨平台能力和成熟的生态系统,已成为主流技术之一。这篇文章做个具体分析制造业为什么钟爱.NET 技术。一、.NET在制造业的应用半导体设备通信的核心技术:SECS…

宁陵县网站seo公众号授权网站

工厂模式(Factory Pattern) 定义: 工厂模式是一种创建型设计模式,它提供了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法使一个类的实例化延迟到其子类。 主要类型: 简单工厂模式&…

jquery网站开发教程漳州最便宜的网站建设价格

作者 | BoCong-Deng来源 | CSDN 博客,责编 | 夕颜头图 | CSDN 下载自东方 IC出品 | CSDN(ID:CSDNnews)写在前面开发Web应用,对页面的安全控制通常是必须的。比如:对于没有访问权限的用户需要转到登录表单页面。要实现访…

怎样加入装修接单网站网上做设计的网站

Android早已超过Windows,坐拥全球用户量最大的操作系统宝座。这么高的人气,当然会有很多可玩性,比如Android -x86项目,即在x86处理器平台上运行Android。据悉,底层升级为Android 9 Pie(android-9.0.0_r50)的x86项目已经…

深度互联:金兰契协议下的领域知识与元智慧共生

深度互联:金兰契协议下的领域知识与元智慧共生 在信息爆炸的时代,知识正以前所未有的速度分化与沉淀,形成一座座精深的“领域孤岛”。我们精通了如何在各自的岛屿上深耕,却常常忘记了如何与隔海相望的邻居对话。岐…

如何用api方式做网站建设博客网站制作

mac如何投屏手机1.首先,解iPhone,然后用手指从下往上,打开控心,在其中就可以找到AirPlay了屏幕镜像。2.接来下就来教大家如何使用AirPlay吧,首先将手机和电脑连接在同一WiFi网络之下,这是投屏成功的前提条件…

以营销为导向的网站建设小程序登录注册

RestFul风格或者是web阶段接触过的异步请求,都需要把数据转换成Json放入响应体中。 ResponseBody的作用其实是将java对象转为json格式的相应内容 使用 RequestMapping注解时,Spring会将返回值解析为视图路径,然后跳转路径返回对应的视图页面…

做网站多少钱西宁君博专注番禺网站建设制作

已经找到工作,但希望再试试春招,距离春招还剩两个月,加油。 这两道题都刷过很多遍了,没什么好说的直接过。 704 本以为刷了很多次没想到还是做错了,有些小细节要注意。 这里是迭代式的,函数式的也不难。 …

阿里巴巴网站建设代理查询类网站用什么做

经常要使用VMWare Workstation来在本地测试不同的操作系统&#xff0c;以前也搞不清楚网络连接三种模式&#xff0c;最近看了几篇文章才算明白。现总结如下&#xff1a; 1. VMware Workstation的虚拟网络组件 虚拟<网卡/网络适配器>&#xff1a;见下图。安装一个虚拟PC…

河口建设局网站深圳设计公司最新招聘

Python的pymysql模块与MySQL数据库的互动&#xff1a;基础与实例 一、连接数据库二、创建游标三、执行SQL命令四、关闭连接 在Python的世界里&#xff0c;操作MySQL数据库最常用的库就是pymysql。 pymysql是一个灵活且易于使用的库&#xff0c;它允许我们以Python的方式操作MyS…

Winform无边框窗体拖动功能实现

1. 设置无边框模式 选中要去除边框的窗体,按F4调出其属性面板,在属性面板中找到 FormBorderStyle ,并选择 ​None,即可将窗体设置成无边框模式;默认是无法随意拖动的,也没有最大化最小化关闭按钮。 2. 通过Pan…

淘宝联盟交钱建设网站手机网站qq代码

以下配置为我自己的需求&#xff0c;因人而异&#xff0c;如果只是单纯的前端非交互页面&#xff0c;可以不用修改配置。 代码及注释&#xff0c;如下&#xff1a; #解决vue-router设置mode为history&#xff0c;去掉路由地址上的/#/后nginx显示404的问题location / {proxy_htt…

厦门电脑网站建设张家界做网站的

随着社会经济的发展和数字技术的进步&#xff0c;互联网行业发展迅速。为了适应新时代社会发展的需要&#xff0c;大数据在这个社会经济发展过程中随着技术的进步而显得尤为重要。同时&#xff0c;大数据技术的快速发展进程也推动了可视化技术的飞速发展&#xff0c;国内外各类…

夺宝网站建设深圳网站导航

1、安装ntpdate&#xff0c;同步标准时间 2、修改时区 3、在.profile文件中写入上面提示的信息&#xff0c;保存退出、更新配置文件或者重启生效 3.1、或者配合上面的cp那条命令&#xff0c;用下面的命令保存到底层 $ hwclock --systohc 4、重启之后&#xff0c;查看日期时间已…

免费网站免费进入在线蓬莱网站建设价格

[react] 在react中页面重新加载时怎样保留数据&#xff1f; 使用浏览器localstorage来保存应用程序的状态 个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起通关前端面试题

net做公司网站网站建设所需要软件

GItlab概述 GitLab概述&#xff1a; 是一个利用 Ruby on Rails 开发的开源应用程序&#xff0c;实现一个自托管的Git项目仓库&#xff0c;可通过Web界面进行访问公开的或者私人项目。 Ruby on Rails 是一个可以使你开发、部署、维护 web 应用程序变得简单的框架。 GitLab拥有与…

网站的注册上一步下一步怎么做西昌市做网站的公司

文章目录 0. 引言1. 回顾2. PrioritizeNodes3. 有哪些优选算法4. selectHost5. 总结6. 参考 0. 引言 欢迎关注本专栏&#xff0c;本专栏主要从 K8s 源码出发&#xff0c;深入理解 K8s 一些组件底层的代码逻辑&#xff0c;同时借助 debug Minikube 来进一步了解 K8s 底层的代码…