SpringBoot学习之单点登录

2023-11-13

单点登录

  • 概念

    单点登录全称Single Sign On(以下简称SSO),是指在多系统应用群中登录一个系统,便可在其他所有系统中得到授权而无需再次登录,包括单点登录与单点注销两部分

登录

  • 实现原理

    sso需要一个独立的认证中心(CAS),只有认证中心能接受用户的用户名密码等安全信息,其他系统不提供登录入口,只接受认证中心的间接授权。

    间接授权通过令牌实现,sso认证中心验证用户的用户名密码没问题,创建授权令牌,在接下来的跳转过程中,授权令牌作为参数发送给各个子系统,子系统拿到令牌,即得到了授权,可以借此创建局部会话,局部会话登录方式与单系统的登录方式相同。

  • 登录流程图
    SSO单点登录流程

  • 登录流程详解

    1. 用户访问系统1的受保护资源,系统1发现用户未登录,跳转至sso认证中心,并将自己的地址作为参数

    2. sso认证中心发现用户未登录,将用户引导至登录页面

    3. 用户输入用户名密码提交登录申请

    4. sso认证中心校验用户信息,创建用户与sso认证中心之间的会话,称为全局会话,同时创建授权令牌

    5. sso认证中心带着令牌跳转会最初的请求地址(系统1)

    6. 系统1拿到令牌,去sso认证中心校验令牌是否有效

    7. sso认证中心校验令牌,返回有效,注册系统1

    8. 系统1使用该令牌创建与用户的会话,称为局部会话,返回受保护资源

    9. 用户访问系统2的受保护资源

    10. 系统2发现用户未登录,跳转至sso认证中心,并将自己的地址作为参数

    11. sso认证中心发现用户已登录,跳转回系统2的地址,并附上令牌

    12. 系统2拿到令牌,去sso认证中心校验令牌是否有效

    13. sso认证中心校验令牌,返回有效,注册系统2

    14. 系统2使用该令牌创建与用户的局部会话,返回受保护资源

  • 全局会话与局部会话

    用户登录成功之后,会与sso认证中心及各个子系统建立会话,用户与sso认证中心建立的会话称为全局会话,用户与各个子系统建立的会话称为局部会话,局部会话建立之后,用户访问子系统受保护资源将不再通过sso认证中心。

    全局会话与局部会话有如下约束关系:

    1. 局部会话存在,全局会话一定存在

    2. 全局会话存在,局部会话不一定存在

    3. 全局会话销毁,局部会话必须销毁

注销

  • 实现原理

    在一个子系统中注销,所有子系统的会话都将被销毁

  • 注销流程图
    注销流程图

  • 注销流程详解

    sso认证中心一直监听全局会话的状态,一旦全局会话销毁,监听器将通知所有注册系统执行注销操作

    1. 用户向系统1发起注销请求

    2. 系统1根据用户与系统1建立的会话id拿到令牌,向sso认证中心发起注销请求

    3. sso认证中心校验令牌有效,销毁全局会话,同时取出所有用此令牌注册的系统地址

    4. sso认证中心向所有注册系统发起注销请求

    5. 各注册系统接收sso认证中心的注销请求,销毁局部会话

    6. sso认证中心引导用户至登录页面

部署

  • 实现原理

    单点登录涉及sso认证中心与众子系统,子系统与sso认证中心需要通信以交换令牌、校验令牌及发起注销请求,因而子系统必须集成sso的客户端,sso认证中心则是sso服务端,整个单点登录过程实质是sso客户端与服务端通信的过程

  • 部署流程图
    部署流程图

  • 注意事项

    sso认证中心与sso客户端通信方式有多种,这里以简单好用的httpClient为例,web service、rpc、restful api都可以

实现

主要功能

  • sso-client

    1. 拦截子系统未登录用户请求,跳转至sso认证中心

    2. 接收并存储sso认证中心发送的令牌

    3. 与sso-server通信,校验令牌的有效性

    4. 建立局部会话

    5. 拦截用户注销请求,向sso认证中心发送注销请求

    6. 接收sso认证中心发出的注销请求,销毁局部会话

  • sso-server

    1. 验证用户的登录信息

    2. 创建全局会话

    3. 创建授权令牌

    4. 与sso-client通信发送令牌

    5. 校验sso-client令牌有效性

    6. 系统注册

    7. 接收sso-client注销请求,注销所有会话

重要步骤

sso-client拦截未登录请求
  • 拦截请求方式

    servlet、filter、listener三种方式

  • 实现思路

    在sso-client中创建LoginFilter.java类并实现Filter接口,在doFilter()方法中加入对未登录用户的拦截

    
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    
            HttpServletRequest req = (HttpServletRequest) request;
    
            HttpServletResponse res = (HttpServletResponse) response;
    
            HttpSession session = req.getSession();
    
            if (session.getAttribute("isLogin")) {
    
                chain.doFilter(request, response);
    
                return;
    
            }
    
            //跳转至sso认证中心
    
            res.sendRedirect("sso-server-url-with-system-url");
    
        }
    
    
    
sso-server拦截未登录请求
  • 实现思路

    拦截从sso-client跳转至sso认证中心的未登录请求,跳转至登录页面,这个过程与sso-client完全一样

sso-server验证用户登录信息
  • 实现思路

    用户在登录页面输入用户名密码,请求登录,sso认证中心校验用户信息,校验成功,将会话状态标记为"已登录"

    
        @RequestMapping("/login")
        public String login(String username, String password, HttpServletRequest req) {
    
            this.checkLoginInfo(username, password);
    
            req.getSession().setAttribute("isLogin", true);
    
            return "success";
    
        }
    
    
    
sso-server创建授权令牌
  • 实现思路

    授权令牌是一串随机字符,只要不重复,不易伪造即可,建议使用JWT工具类

    
        package util;
    
        import io.jsonwebtoken.Claims;
        import io.jsonwebtoken.JwtBuilder;
        import io.jsonwebtoken.Jwts;
        import io.jsonwebtoken.SignatureAlgorithm;
        import org.springframework.boot.context.properties.ConfigurationProperties;
        import org.springframework.stereotype.Component;
    
        import java.util.Date;
    
        /**
        * Created by Administrator on 2018/4/11.
        */
        @ConfigurationProperties("jwt.config")
        public class JwtUtil {
    
            private String key ;
    
            private long ttl ;//一个小时
    
            public String getKey() {
                return key;
            }
    
            public void setKey(String key) {
                this.key = key;
            }
    
            public long getTtl() {
                return ttl;
            }
    
            public void setTtl(long ttl) {
                this.ttl = ttl;
            }
    
            /**
            * 生成JWT
            *
            * @param id
            * @param subject
            * @return
            */
            public String createJWT(String id, String subject, String roles) {
                long nowMillis = System.currentTimeMillis();
                Date now = new Date(nowMillis);
                JwtBuilder builder = Jwts.builder().setId(id)
                        .setSubject(subject)
                        .setIssuedAt(now)
                        .signWith(SignatureAlgorithm.HS256, key).claim("roles", roles);
                if (ttl > 0) {
                    builder.setExpiration( new Date( nowMillis + ttl));
                }
                return builder.compact();
            }
    
            /**
            * 解析JWT
            * @param jwtStr
            * @return
            */
            public Claims parseJWT(String jwtStr){
                return  Jwts.parser()
                        .setSigningKey(key)
                        .parseClaimsJws(jwtStr)
                        .getBody();
            }
    
        }
    
    
    
    
sso-client取得令牌并校验
  • 实现思路

    sso认证中心登录后,跳转回子系统并附上令牌,子系统(sso-client)取得令牌,然后去sso认证中心校验,在LoginFilter.java的doFilter()中添加几行

    
        // 请求附带token参数
    
        String token = req.getParameter("token");
        if (token != null) {
            // 去sso认证中心校验token
            boolean verifyResult = this.verify("sso-server-verify-url", token);
            if (!verifyResult) {
                res.sendRedirect("sso-server-url");
                return;
            }
            chain.doFilter(request, response);
        }
    
    

    verify()方法使用httpClient实现,这里仅简略介绍,httpClient详细使用方法请参考官方文档

sso-server接收并处理校验令牌请求
  • 实现思路

    用户在sso认证中心登录成功后,sso-server创建授权令牌并存储该令牌,所以,sso-server对令牌的校验就是去查找这个令牌是否存在以及是否过期,令牌校验成功后sso-server将发送校验请求的系统注册到sso认证中心(就是存储起来的意思)

  • 存储方式

    令牌与注册系统地址通常存储在key-value数据库(如redis)中,redis可以为key设置有效时间也就是令牌的有效期。

  • 存储原因

    当用户向sso认证中心提交注销请求,sso认证中心注销全局会话,若未存储注册系统地址,将无法确定哪些系统用此全局会话建立了自己的局部会话,也不知道要向哪些子系统发送注销请求注销局部会话
    redis中存储令牌数据类型选择

sso-client校验令牌成功创建局部会话
  • 实现思路

    令牌校验成功后,sso-client将当前局部会话标记为“已登录”,修改LoginFilter.java

    
        if (verifyResult) {
    
            session.setAttribute("isLogin", true);
    
        }
    
    
    
  • 注意事项
    sso-client还需将当前会话id与令牌绑定,表示这个会话的登录状态与令牌相关,此关系可以用java的hashmap保存,保存的数据用来处理sso认证中心发来的注销请求

注销过程
  • 实现思路

    1. 用户向子系统发送带有"logout"参数的请求(注销请求),sso-client拦截器拦截该请求,向sso认证中心发起注销请求
    
        String logout = req.getParameter("logout");
        if (logout != null) {
    
            this.ssoServer.logout(token);
    
        }
    
    
    1. sso认证中心也用同样的方式识别出sso-client的请求是注销请求(带有“logout”参数),sso认证中心注销全局会话
    
        @RequestMapping("/logout")
    
        public String logout(HttpServletRequest req) {
    
            HttpSession session = req.getSession();
    
            if (session != null) {
    
                session.invalidate();//触发LogoutListener
    
            }
    
            return "redirect:/";
    
        }
    
    
    
    1. sso认证中心有一个全局会话的监听器,一旦全局会话注销,将通知所有注册系统注销
    
    
        public class LogoutListener implements HttpSessionListener {
    
            @Override
    
            public void sessionCreated(HttpSessionEvent event) {}
    
            @Override
    
            public void sessionDestroyed(HttpSessionEvent event) {
    
                //通过httpClient向所有注册系统发送注销请求
    
            }
    
        }
    
    
    

用户注册

业务流程

在用户微服务编写API,生成手机验证码,存入Redis并发送到RocketMQ

用户登录

常见认证机制

HTTP Basic Auth

  • 概念

    说明就是每次请求API时都提供用户的username和password。但由于有把用户名密码暴露给第三方客户端的风险,在生产环境下被使用的越来越少

Cookie Auth

  • 概念

    Cookie认证机制就是为一次请求认证在服务端创建一个Session对象,同时在客户端的浏览器端创建了一个Cookie对象;通过客户端带上来Cookie对象来与服务器端的session对象匹配来实现状态管理

  • 登录流程
    CookieAuth登录流程

适用场景
  • 多服务器部署单体web项目
  1. 方案一

    使用nginx对ip进行hash取模,使得每次该用户登录系统时,都访问到同一台服务器

    存在问题

    存在单点故障问题,若该服务器系统宕机,将会丢失该服务器中存储的用户信息,可以考虑搭建数据库集群,数据库和应用分别部署在不同的服务器

  2. 方案二

    使用tomcat服务器进行session同步

    存在问题

    只能用于同一集群下的项目,不能在不同服务进行session同步,例如淘宝登录后,天猫还得进行登录;而且session复制会导致单个tomcat中存储压力过大

  3. 方案三

    借助redis等第三方存储引擎存储session

    存在问题

    以Map<String,Object>形式存储登录信息(不同服务器(域名)之间SessionID不一致),但需要保证key唯一,可以采用UUID类似工具类生成,但是跨服务后,另外的服务也无法直接获取key,需要在登录的服务将key传给客户端,由客户端保存在本地缓存(cookie)中,再访问其他域服务时,如果没有设置跨域访问,将不会接收cookie信息

OAuth

  • 概念

    OAuth(开放授权)是一个开放的授权标准,允许用户让第三方应用访问该用户在某一web服务上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用。OAuth让用户可以授权第三方网站访问他们存储在另外服务提供者的某些特定信息,而非所有内容。

  • 登录流程
    oauth2.0协议登录流程

  • 适用场景

    基于OAuth的认证机制适用于个人消费者类的互联网产品,如社交类APP等应用,但是不太适合拥有自有认证权限管理的企业应用。

Token Auth

  • 概念

    使用基于 Token 的身份验证方法,在服务端不需要存储用户的登录记录。

  • 验证流程

  1. 客户端使用用户名跟密码请求登录
  2. 服务端收到请求,去验证用户名与密码
  3. 验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端
  4. 客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里
  5. 客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
  6. 服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据
  • Token Auth相对于Cookie机制的优点
  1. 支持跨域访问: Cookie是不允许垮域访问的,这一点对Token机制是不存在的,前提是传输的用户认证信息通过HTTP头传输.
  2. 无状态(也称:服务端可扩展行):Token机制在服务端不需要存储session信息,因为Token 自身包含了所有登录用户的信息,只需要在客户端的cookie或本地介质存储状态信息.
  3. 更适用CDN: 可以通过内容分发网络请求你服务端的所有资料(如:javascript,HTML,图片等),而你的服务端只要提供API即可.
  4. 去耦: 不需要绑定到一个特定的身份验证方案。Token可以在任何地方生成,只要在你的API被调用的时候,你可以进行Token生成调用即可.
  5. 更适用于移动应用: 当你的客户端是一个原生平台(iOS, Android,Windows 8等)时,Cookie是不被支持的(你需要通过Cookie容器进行处理),这时采用Token认证机制就会简单得多。
  6. CSRF:因为不再依赖于Cookie,所以你就不需要考虑对CSRF(跨站请求伪造)的防范。
  7. 性能: 一次网络往返时间(通过数据库查询session信息)总比做一次HMACSHA256计算 的Token验证和解析要费时得多.
  8. 不需要为登录页面做特殊处理: 如果你使用Protractor 做功能测试的时候,不再需要为登录页面做特殊处理.
  9. 基于标准化:你的API可以采用标准化的 JSON Web Token (JWT). 这个标准已经存在多个后端库(.NET, Ruby, Java,Python, PHP)和多家公司的支持(如:Firebase,Google, Microsoft).

BCrypt密码加密

  • Spring Security提供方法

    Spring Security提供了BCryptPasswordEncoder类,实现Spring的PasswordEncoder接口使用BCrypt强哈希方法来加密密码,BCrypt强哈希方法 每次加密的结果都不一样。
    
  • 实操步骤

  1. 引入坐标依赖

        <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring‐boot‐starter‐security</artifactId>
        </dependency>
    
  2. 添加配置类

    添加了spring security依赖后,所有的地址都被spring security所控制了,我们目前只是需要用到BCrypt密码加密的部分,所以我们要添加一个配置类,配置为所有地址都可以匿名访问

基于JWT的Token认证机制实现

JWT概念

JSON Web Token(JWT)是一个非常轻巧的规范。这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息。

JWT组成

一个JWT实际上就是一个字符串,它由三部分组成,头部、载荷与签名。
  • 头部

    头部用于描述关于该JWT的最基本的信息,例如其类型以及签名所用的算法等
    在头部指明了签名算法是HS256算法。 我们进行BASE64编码

  • 载荷

    (1)标准中注册的声明(建议但不强制使用)
    iss: jwt签发者
    sub: jwt所面向的用户
    aud: 接收jwt的一方
    exp: jwt的过期时间,这个过期时间必须要大于签发时间
    nbf: 定义在什么时间之前,该jwt都是不可用的.
    iat: jwt的签发时间
    jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。

    (2)公共的声明(公共的claim,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息)

    (3)私有的声明(自定义的claim)
    claim跟JWT标准规定的claim区别在于:JWT规定的claim,JWT的接收方在拿到JWT之后,都知道怎么对这些标准的claim进行验证(还不知道是否能够验证);而private claims不会验证,除非明确告诉接收方要对这些claim进行验证以及规则才行。

  • 签证(signature)

    header (base64后的)
    payload (base64后的)
    secret
    需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分

    将这三部分用"."连接成一个完整的字符串,构成了最终的jwt

  • 注意

    secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。

token的创建

  • 创建类用于生成token(自定义claims保存角色)

        public class CreateJwtTest {
                public static void main(String[] args) {
                        //为了方便测试,我们将过期时间设置为1分钟
                        long now = System.currentTimeMillis();//当前时间
                        long exp = now + 1000*60;//过期时间为1分钟
    
                        JwtBuilder builder= Jwts.builder().setId("888")
                        .setSubject("小白")
                        .setIssuedAt(new Date())
                        .signWith(SignatureAlgorithm.HS256,"itcast")
                        .setExpiration(new Date(exp))
                        .claim("roles","admin")
                        .claim("logo","logo.png");
                        System.out.println( builder.compact() );
                }
        }
    
  • 常用API介绍

    setIssuedAt 用于设置签发时间
    signWith 用于设置签名秘钥
    setExpiration 方法用于设置过期时间

token的解析

  • 创建类用于解析token

    
        public class ParseJwtTest {
                public static void main(String[] args) {
                        String compactJws="eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4ODgiLCJzdWIiOiLlsI_nmb0iLCJpYXQiOjE1MjM0MTM0NTh9.
                        gq0J‐cOM_qCNqU_s‐d_IrRytaNenesPmqAIhQpYXHZk";
                        Claims claims =Jwts.parser().setSigningKey("itcast").parseClaimsJws(compactJws).getBody();
                        System.out.println("id:"+claims.getId());
                        System.out.println("subject:"+claims.getSubject());
                        System.out.println("IssuedAt:"+claims.getIssuedAt());
                        System.out.println("roles:"+claims.get("roles"));
                        System.out.println("logo:"+claims.get("logo"));
    
                        SimpleDateFormat sdf=new SimpleDateFormat("yyyy‐MM‐dd hh:mm:ss");
                        System.out.println("签发时间:"+sdf.format(claims.getIssuedAt()));
                        System.out.println("过期时间:"+sdf.format(claims.getExpiration()));
                        System.out.println("当前时间:"+sdf.format(new Date()) );
                }
        }
    
  • 测试运行

    当未过期时可以正常读取,当过期时会引发io.jsonwebtoken.ExpiredJwtException异常。

        eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsImlhdCI6MTU2NjYyODcxNiwiZXhwIjoxNTY2NjMyMzE2LCJyb2xlcyI6ImFkbWluIn0.59_d07aSZQZU1DTZuvoVKhzaoNPMfaHiSNO8jnMkGZs
    
        JWT expired at 2019-08-23T17:50:48+0800. Current time: 2019-08-24T14:52:19+0800
    

JWT工具类

  • 配置私有属性取值

    
        @ConfigurationProperties()
    
    
  • Spring提供的拦截器

    Spring为我们提供了org.springframework.web.servlet.handler.HandlerInterceptorAdapter这个适配器,继承此类,可以非常方便的实现自己的拦截器。他有三个方法:
    
    分别实现预处理、后处理(调用了Service并返回ModelAndView,但未进行页面渲染)、返回处理(已经渲染了页面)
    1. 在preHandle中,可以进行编码、安全控制等处理;
    2. 在postHandle中,有机会修改ModelAndView;
    3. 在afterCompletion中,可以根据ex是否为null判断是否发生了异常,进行日志记录。
    
  • 拦截器配置类继承类

        org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport
    
    

其他

  • 参考链接

    https://blog.csdn.net/xiaoguan_liu/article/details/91492110

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SpringBoot学习之单点登录 的相关文章

  • 清理码头 - 删除“不必要”的东西

    我习惯用Jetty http jetty codehaus org jetty 作为我的网络容器 我对我做了什么安装步骤得到原始的焦油球并且清理一些目录和文件从中 我在这里想提出的是 您通常从 Jetty 中删除什么以在生产 登台环境中使用
  • 将 jar 作为 Linux 服务运行 - init.d 脚本在启动应用程序时卡住

    我目前正在致力于在 Linux VM 上实现一个可运行的 jar 作为后台服务 我已经使用了找到的例子here https gist github com shirish4you 5089019作为工作的基础 并将 start 方法修改为
  • Android 2.2 SDK - Droid X 相机活动无法正常完成

    我注意到我在 Droid X 上调用的默认相机活动与我的 Droid 和 Nexus One 上的默认相机活动看起来不同 在 Droid 和 Nexus One 上选择 确定 后 活动将完成 Droid X 有一个 完成 按钮 它将带您返回
  • Grails 2.3.0 自动重新加载不起作用

    我最近将我们的项目升级到 grails 2 3 0 一切工作正常 除了每当我更改代码时自动重新加载都无法工作的问题 这包括所有项目工件 控制器 域 服务 gsps css 和 javascript 文件 我的旧版本 grails 可以正常工
  • Spring安全“记住我”cookie在第一个请求中不可用

    我无法在登录请求后检索 Spring 记住我 cookie 但它在对受保护页面的下一个请求中工作正常 谁能告诉我怎样才能立即得到它 我在登录请求中设置了记住我的 cookie 但在 Spring 重定向回原始 受保护的 url 后无法检索它
  • Java:使用 HttpURLConnection 的 HTTP PUT

    如何执行 HTTP PUT 我正在使用的类似乎认为它正在执行 PUT 但端点将其视为我执行了 GET 我做错了什么吗 URL url new URL https HttpURLConnection conn HttpURLConnectio
  • 如何在 JSP 中导入类?

    我是一个完全的JSP初学者 我正在尝试使用java util List在 JSP 页面中 我需要做什么才能使用除以下类之外的类java lang 使用以下导入语句进行导入java util List 顺便说一句 要导入多个类 请使用以下格式
  • 使用 RecyclerView 适配器在运行时更改布局屏幕

    我有两个布局文件 如下所示 如果列表中存在数据 则我显示此布局 当列表为空时 我会显示此布局 现在我想在运行时更改布局 当用户从列表中删除最后一项时 我想将布局更改为第二张图片中显示的 空购物车布局 In getItemCount Recy
  • 如果使用的 JVM 是 x86 或 x64,则以不同的方式解决 Maven 依赖关系?

    我设置了一个 Maven 存储库来托管一些 dll 但我需要我的 Maven 项目根据使用的 JVM 是 x86 还是 x64 下载不同的 dll 例如 在运行 x86 版本 JVM 的计算机上 我需要从存储库下载 ABC dll 作为依赖
  • 如何将 android.net.Uri 转换为 java.net.URL? [复制]

    这个问题在这里已经有答案了 有没有办法从Uri to URL 我正在使用的库需要这个 它only接受一个URL但我需要在我的设备上使用图像 如果该方案的Uri is http or https new URL uri toString 应该
  • Java 服务器-客户端 readLine() 方法

    我有一个客户端类和一个服务器类 如果客户端向服务器发送消息 服务器会将响应发送回客户端 然后客户端将打印它收到的所有消息 例如 如果客户端向服务器发送 A 则服务器将向客户端发送响应 1111 所以我在客户端类中使用 readLine 从服
  • Java 8 中函数式接口的使用

    这是来自的后续问题Java 8 中的 双冒号 运算符 https stackoverflow com questions 20001427 double colon operator in java 8其中 Java 允许您使用以下方式引用
  • Java 数组的最大维数

    出于好奇 在 Java 中数组可以有多少维 爪哇language不限制维数 但是JavaVM规范将维度数限制为 255 例如 以下代码将无法编译 class Main public static void main String args
  • Dispatcher-servlet 无法映射到 websocket 请求

    我正在开发一个以Spring为主要框架的Java web应用程序 特别使用Spring core Spring mvc Spring security Spring data Spring websocket 像这样在 Spring 上下文
  • 将图像添加到自定义 AlertDialog

    我制作了一个 AlertDialog 让用户可以从我显示的 4 个选项中选择一个 前 3 个让他们在单击号码时直接拨打号码 第 4 个显示不同的视图 现在看起来是这样的 由于第四个选项的目的是不同的任务 我想让它看起来不同 因为用户可能会感
  • Java:多线程内的 XA 事务传播

    我如何使用事务管理器 例如Bitronix http docs codehaus org display BTM Home JBoss TS http www jboss org jbosstm or Atomikos http www a
  • Android - 9 补丁

    我正在尝试使用 9 块图片创建一个新的微调器背景 我尝试了很多方法来获得完美的图像 但都失败了 s Here is my 9 patch 当我用Draw 9 patch模拟时 内容看起来不错 但是带有箭头的部分没有显示 或者当它显示时 这部
  • 嵌入式 Jetty - 以编程方式添加基于表单的身份验证

    有没有一种方法可以按如下方式以编程方式添加基于表单的身份验证 我用的是我自己的LdapLoginModule 最初我使用基本身份验证并且工作正常 但现在我想在登录页面上进行更多控制 例如显示徽标等 有没有好的样品 我正在使用嵌入式 jett
  • JAXB - 列表<可序列化>?

    我使用 xjc 制作了一些课程 public class MyType XmlElementRefs XmlElementRef name MyInnerType type JAXBElement class required false
  • 在哪里存储 Java 的 .properties 文件?

    The Java教程 http download oracle com javase tutorial essential environment properties htmlon using Properties 讨论如何使用 Prop

随机推荐

  • BigDecimal的用法详解(保留两位小数,四舍五入,数字格式化,科学计数法转数字,数字里的逗号处理)

    一 简介 Java在java math包中提供的API类BigDecimal 用来对超过16位有效位的数进行精确的运算 双精度浮点型变量double可以处理16位有效数 在实际应用中 需要对更大或者更小的数进行运算和处理 float和dou
  • 推荐一款微软出品的开发神器,体验不输IDEA!

    最近微软的开发工具VSCode频繁更新Java支持 又是支持SpringBoot 又是支持Lombok 让我不禁好奇VSCode是不是也能胜任Java开发了 于是抽空体验了一把 确实完全可以胜任 Java开发者又有了新选择 不仅好用而且开源
  • 深度学习------CNN实现验证码和猫狗数据集

    1 卷积神经网络基本操作 import tensorflow as tf import numpy as np import os import matplotlib pyplot as plt import random def read
  • AI标注工具Labelme和LabelImage Labelme和LabelImage集成工具

    在AI数据标注过程中 难免会使用到标注工具 常用的工具无非是Labelme和LabelImage Labelme是标注目标轮廓 而LabelImage则是标注目标的区域 然而使用原生态的工具 需要用到python命令行 十分麻烦 为了方便大
  • C++ ——Qt的信号和槽的详解

    1 概述 信号槽是 Qt 框架引以为豪的机制之一 所谓信号槽 实际就是观察者模式 当某个事件发生之后 比如 按钮检测到自己被点击了一下 它就会发出一个信号 signal 这种发出是没有目的的 类似广播 如果有对象对这个信号感兴趣 它就会使用
  • pycharm安装需要java_安装pycharm遇到的坑

    第三周开始接触python了 结果第一步装pycharm时就遇到了坑 正常安装完成后点运行时出现错误 No JVM installation found 助教说这是缺少jdk java程序支持包 需要在网上找个最新的安装并配置下path路径
  • 【第24篇】CenterNet2论文解析,COCO成绩最高56.4mAP

    文章目录 摘要 1 简介 2 相关工作 3 准备工作 4 两阶段检测的概率解释 5 构建一个概率两级检测器 6 结果 6 1 消融研究 6 2 大词汇检测 七 结论 摘要 https arxiv org abs 2103 07461 我们开
  • 开源License的类型

    如今 Stallman率先推出的GPL已经进入到第三个版本 GNU GPLv3 且这只是几十种开源License类型中的一种 开源组织OSI 是一个在1998年成立的 为了推广开源程序和规范术语使用的组织 它已经批准了80多种开源许可证 这
  • JS数组方法&&es5数组新增方法

    1 unshift 给数组的开头添加一个或多个元素 数组名 unshift 一个值或多个值 返回添加以后的新数组的长度 2 push 给数组的末尾添加一个或多个元素 数组 push 一个值或多个值 返回新数组的长度 3 shift 给数组的
  • C++的Json库的简单实现

    我的Json库实现 Json 实现Json 我的源码 点这里 https github com jo qzy MyJson 和效果图 Json库中的类实现 JSON Value类 JSON Reader JSON Writer FastWr
  • 第十二章 Ambari二次开发之集成Alluxio

    1 Alluxio高可用部署 生产环境 使用具有高可用性的模式来运行Alluxio masters 1 1 Alluxio架构 Alluxio可以被分为三个部分 masters workers以及clients 一个典型的设置由一个主服务器
  • MySQL 过滤重复数据

    方法1 加关键字 DISTINCT 在mysql中 可以利用 SELECT 语句和 DISTINCT 关键字来进行去重查询 过滤掉重复的数据 语法 SELECT DISTINCT 字段名 FROM 数据表名 DISTINCT 关键字的语法格
  • HTML+CSS+JavaScript写计算器

    思维导图 代码 HTML div div div div div div
  • TestNg多线程—— 并行执行测试

    多线程并行执行测试 可以通过参数设置来实现不同级别的多线程配置测试 1 test级别的多线程测试 每个
  • 第二章:25+ Python 数据操作教程(第十八节如何使用 Matplotlib 库在 python 中执行绘图和数据可视化)持续更新中

    本教程概述了如何使用 Matplotlib 库在 python 中执行绘图和数据可视化 这篇文章的目的是让您熟悉该库的基础知识和高级绘图功能 它包含几个示例 将为您提供使用 Python 生成绘图的实践经验 目录 什么是 Matplotli
  • phpshe v1.7漏洞复现(Sql injection+XXE)

    前几天研究了一下xss的绕过 这两天准备深入研究下sql注入的审计 首先自动审计一波 看到疑似的一个变量覆盖点 点进去看原来是 register globals的隐患消除 简单来说如果这个配置设置为On的话 从客户端传输过来的任意参数值会被
  • jboss 热部署

    文章目录 JBoss EAP 6 4 0 GA AS 7 5 0 Final redhat 21 JBoss EAP 6 4 0 GA AS 7 5 0 Final redhat 21
  • 一文学会动态规划

    系列文章目录 注意 在学习理论之前 希望读者能看如下几个例子 有助于理解 算法导论 学习 十七 动态规划之钢条切割 C语言 算法导论 学习 十八 动态规划之矩阵链乘 C语言 算法导论 学习 十九 动态规划之最长公共子序列 C语言 文章目录
  • 浅谈数据挖掘——频繁模式、序列挖掘与搜索优化算法

    本系列将从下面几方面谈谈最近的一点点收获 令声明 本文主要是对我找到的一个莫名其妙国外英文pdf文件的学习与解读 因为我也没有找到他的出处 也没作者也没学校 所以我仅以此段文字向这个未知的作者致敬 本文主要处于科普类的理解 列出的主要算法并
  • SpringBoot学习之单点登录

    SpringBoot学习之单点登录 单点登录 登录 注销 部署 实现 主要功能 重要步骤 sso client拦截未登录请求 sso server拦截未登录请求 sso server验证用户登录信息 sso server创建授权令牌 sso