is_uploaded_file ile总是返回false,根据以下方法进行检查,全部检查通过。
1 2 3 4 5 6 |
1,是否通过http协议上传。 2,form中是否有 enctype="multipart/form-data"。 3,上传文件是否超出了规定的大小。 4,存放上传文件的文件夹是否存在,上传的文件夹是否具有写权限。 5,上传文件应该是使用move<span class="hljs-emphasis">_uploaded_</span>file()这个函数吧! 6,请确保$_FILES[<span class="hljs-string">"upload"</span>][<span class="hljs-symbol">'error'</span>] = 0; |
最后,找到一篇帖子, 将文件名用realpath函数过滤一下即可。
1 |
<span class="hljs-meta">is_uploaded_file(realpath($</span><span class="bash">file[<span class="hljs-string">'tmp_name'</span>]))</span> |
原文链接:http://www.xiumu.org/other/under-the-iis-is_uploaded_file-always-returns-false.shtml from:https://my.oschina.net/qii/blog/400692?p=1
View Detailsbytes[] 到数字类型的转换是个经常用到的代码,解决方式也不止一种,最近需要将bytes[]转为long,有机会深入了解了一下,此文做个总结。 java代码实现 如果不想借助任何已经有的类,完全可以自己实现这段代码,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/** * 将字节数组转为long<br> * 如果input为null,或offset指定的剩余数组长度不足8字节则抛出异常 * @param input * @param offset 起始偏移量 * @param littleEndian 输入数组是否小端模式 * @return */ public static long longFrom8Bytes(byte[] input, int offset, boolean littleEndian){ long value=0; // 循环读取每个字节通过移位运算完成long的8个字节拼装 for(int count=0;count<8;++count){ int shift=(littleEndian?count:(7-count))<<3; value |=((long)0xff<< shift) & ((long)input[offset+count] << shift); } return value; } |
借助java.nio.ByteBuffer实现 java.nio.ByteBuffer 本身就有getLong,getInt,getFloat….方法,只要将byte[]转换为ByteBuffer就可以实现所有primitive类型的数据读取,参见javadoc。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/** * 利用 {@link java.nio.ByteBuffer}实现byte[]转long * @param input * @param offset * @param littleEndian 输入数组是否小端模式 * @return */ public static long bytesToLong(byte[] input, int offset, boolean littleEndian) { // 将byte[] 封装为 ByteBuffer ByteBuffer buffer = ByteBuffer.wrap(input,offset,8); if(littleEndian){ // ByteBuffer.order(ByteOrder) 方法指定字节序,即大小端模式(BIG_ENDIAN/LITTLE_ENDIAN) // ByteBuffer 默认为大端(BIG_ENDIAN)模式 buffer.order(ByteOrder.LITTLE_ENDIAN); } return buffer.getLong(); } |
借助java.io.DataInputStream实现 java.io.DataInputStream 同样提供了readLong,readLong,readLong….方法,只要将byte[]转换为DataInputStream就可以实现所有primitive类型的数据读取,参见javadoc。 完整测试代码 下面的Junit 测试代码计算String 的MD5校验码(16 bytes),然后使用上述方式分别将16 bytes转换为2个long(大端模式)然后以16进制模式输出结果,以验证三种方式一致性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
package net.gdface.facelog; import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import org.junit.Test; public class TestSerialVersionUID { /** * 生成MD5校验码 * * @param source * @return */ static public byte[] getMD5(byte[] source) { if (null==source) return null; try { MessageDigest md = MessageDigest.getInstance("MD5"); return md.digest(source); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return null; } /** * 将16位byte[] 转换为32位的HEX格式的字符串String * * @param buffer * @return */ static public String toHex(byte buffer[]) { if (null==buffer) return null; StringBuffer sb = new StringBuffer(buffer.length * 2); for (int i = 0; i < buffer.length; i++) { sb.append(Character.forDigit((buffer[i] & 240) >> 4, 16)); sb.append(Character.forDigit(buffer[i] & 15, 16)); } return sb.toString(); } /** * 将字节数组转为long<br> * 如果input为null,或offset指定的剩余数组长度不足8字节则抛出异常 * @param input * @param offset 起始偏移量 * @param littleEndian 输入数组是否小端模式 * @return */ public static long longFrom8Bytes(byte[] input, int offset, boolean littleEndian){ if(offset <0 || offset+8>input.length) throw new IllegalArgumentException(String.format("less than 8 bytes from index %d is insufficient for long",offset)); long value=0; for(int count=0;count<8;++count){ int shift=(littleEndian?count:(7-count))<<3; value |=((long)0xff<< shift) & ((long)input[offset+count] << shift); } return value; } /** * 利用 {@link java.nio.ByteBuffer}实现byte[]转long * @param input * @param offset * @param littleEndian 输入数组是否小端模式 * @return */ public static long bytesToLong(byte[] input, int offset, boolean littleEndian) { if(offset <0 || offset+8>input.length) throw new IllegalArgumentException(String.format("less than 8 bytes from index %d is insufficient for long",offset)); ByteBuffer buffer = ByteBuffer.wrap(input,offset,8); if(littleEndian){ // ByteBuffer.order(ByteOrder) 方法指定字节序,即大小端模式(BIG_ENDIAN/LITTLE_ENDIAN) // ByteBuffer 默认为大端(BIG_ENDIAN)模式 buffer.order(ByteOrder.LITTLE_ENDIAN); } return buffer.getLong(); } @Test public void test() throws IOException { String input="net.gdface.facelog.dborm.person.FlPersonBeanBase"; byte[] md5 = getMD5(input.getBytes()); System.out.printf("md5 [%s]\n",toHex(md5)); // 三种方式运算结果对比验证 DataInputStream dataInput = new DataInputStream(new ByteArrayInputStream(md5)); long l1 = dataInput.readLong(); long l2 = dataInput.readLong(); System.out.printf("l1=0x%x l2=0x%x,DataInputStream\n", l1,l2); long ln1 = bytesToLong(md5,0, false); long ln2 = bytesToLong(md5,8, false); System.out.printf("ln1=0x%x ln2=0x%x,ByteBuffer\n", ln1,ln2); long ll1 = longFrom8Bytes(md5,0, false); long ll2 = longFrom8Bytes(md5,8, false); System.out.printf("ll1=0x%x ll2=0x%x\n", ll1,ll2); } } |
输出结果 md5 [39627933ceeebf2740e1f822921f5837] l1=0x39627933ceeebf27 l2=0x40e1f822921f5837,DataInputStream ln1=0x39627933ceeebf27 ln2=0x40e1f822921f5837,,ByteBuffer ll1=0x39627933ceeebf27 ll2=0x40e1f822921f5837 参考资料 《Java 中 byte、byte 数组和 int、long 之间的转换》 from:https://blog.csdn.net/10km/article/details/77435659
View Details第一种:饿汉模式(线程安全)
1 2 3 4 5 6 7 8 9 10 11 12 |
public class Single2 { private static Single2 instance = new Single2(); private Single2(){ System.out.println("Single2: " + System.nanoTime()); } public static Single2 getInstance(){ return instance; } } |
第二种:懒汉模式 (如果方法没有synchronized,则线程不安全)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public class Single3 { private static Single3 instance = null; private Single3(){ System.out.println("Single3: " + System.nanoTime()); } public static synchronized Single3 getInstance(){ if(instance == null){ instance = new Single3(); } return instance; } } |
第三种:懒汉模式改良版(线程安全,使用了double-check,即check-加锁-check,目的是为了减少同步的开销)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
public class Single4 { private volatile static Single4 instance = null; private Single4(){ System.out.println("Single4: " + System.nanoTime()); } public static Single4 getInstance(){ if(instance == null){ synchronized (Single4.class) { if(instance == null){ instance = new Single4(); } } } return instance; } } |
第四种:利用私有的内部工厂类(线程安全,内部类也可以换成内部接口,不过工厂类变量的作用域要改为public了。)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public class Singleton { private Singleton(){ System.out.println("Singleton: " + System.nanoTime()); } public static Singleton getInstance(){ return SingletonFactory.singletonInstance; } private static class SingletonFactory{ private static Singleton singletonInstance = new Singleton(); } } |
from:https://my.oschina.net/yangchunlian/blog/1607947
View Details在同步块中调用 wait() 和 notify()方法,如果阻塞,通过循环来测试等待条件。请参考答案中的示例代码。 【生产者】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; public class Producer implements Runnable { private final Vector sharedQueue; private final int SIZE; public Producer(Vector sharedQueue, int size) { this.sharedQueue = sharedQueue; this.SIZE = size; } @Override public void run() { // 生产数据 for (int i = 0; i < 7; i++) { System.out.println("Produced:" + i); try { produce(i); } catch (InterruptedException ex) { Logger.getLogger(Producer.class.getName()).log(Level.SEVERE, null, ex); } } } private void produce(int i) throws InterruptedException { // wait if queue is full while (sharedQueue.size() == SIZE) { synchronized (sharedQueue) { System.out.println("Queue is full " + Thread.currentThread().getName() + " is waiting , size: " + sharedQueue.size()); sharedQueue.wait(); } } // producing element and notify consumers synchronized (sharedQueue) { sharedQueue.add(i); sharedQueue.notifyAll(); } } } |
【消费者】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; public class Consumer implements Runnable { private final Vector sharedQueue; private final int SIZE; public Consumer(Vector sharedQueue, int size) { this.sharedQueue = sharedQueue; this.SIZE = size; } @Override public void run() { // 消费数据 while (true) { try { System.out.println("Consumer: " + consume()); Thread.sleep(50); } catch (InterruptedException ex) { Logger.getLogger(Consumer.class.getName()).log(Level.SEVERE, null, ex); } } } private int consume() throws InterruptedException { // wait if queue is empty while (sharedQueue.isEmpty()) { synchronized (sharedQueue) { System.out.println("Queue is empty " + Thread.currentThread().getName() + " is waiting , size: " + sharedQueue.size()); sharedQueue.wait(); } } //otherwise consume element and notify waiting producer synchronized (sharedQueue) { sharedQueue.notifyAll(); return (Integer) sharedQueue.remove(0); } } } |
【测试函数】
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import java.util.Vector; public class ProducerConsumerSolution { public static void main(String[] args) { Vector sharedQueue = new Vector(); int size = 4; Thread prodThread = new Thread(new Producer(sharedQueue, size), "Producer"); Thread consThread = new Thread(new Consumer(sharedQueue, size), "Consumer"); prodThread.start(); consThread.start(); } } |
运行结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
Produced:0 Queue is empty Consumer is waiting , size: 0 Produced:1 Consumer: 0 Produced:2 Produced:3 Produced:4 Produced:5 Queue is full Producer is waiting , size: 4 Consumer: 1 Produced:6 Queue is full Producer is waiting , size: 4 Consumer: 2 Consumer: 3 Consumer: 4 Consumer: 5 Consumer: 6 Queue is empty Consumer is waiting , size: 0 |
from:https://www.cnblogs.com/xbq8080/p/10371214.html
View Details事故现场: 解决办法: 一是命令行,
1 |
mvn clean package -Dmaven.test.skip=true |
二是写入pom文件
1 2 3 4 5 6 7 8 |
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.4.2</version> <configuration> <skipTests>true</skipTests> </configuration> </plugin> |
from:https://www.cnblogs.com/lxcy/p/8279899.html
View Details1.git 项目到仓库中。 2.运行maven 导入JAR包 3.配置项目project structure(CTRL+ALT+SHIFT+S) project settings 第一项 Project compiler output 路径 : D:\git\CMS\target\shishuocms-2.0.1\WEB-INF\classes 第二项 Modules: Paths 选择第一个 Inherit project compile output path 复制 applicationContext.xml 、 log4j.properties、 shishuocms.properties 到 target/shishuocms-2.0.1/WEB-INF/classes下面。 别忘了修改shishuocms.properties的数据库连接配置。 ———————————————— 版权声明:本文为CSDN博主「matt0614」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/matt0614/article/details/44972539
View DetailsFAQ 什么是持续交付(CD)? CD是一种软件工程方法,团队在短周期内生成软件,确保软件可以随时可靠地发布。微服务、云原生架构的兴起引发了持续交付实践的必然结果。这与CI/CD有关,其中包括持续集成(CI) – 将所有开发者工作副本一天多次合并到共享主线的做法。 宣布了什么? CDF(Continuous Delivery Foundation,持续交付基金会)是一个新的、中立的组织,将发展和维持一个开放的持续交付生态系统。它将提供统一的治理和与供应商中立的管理,以及对资金和运营的监督。CD基金会的第一批项目是Jenkins、Jenkins X、Spinnaker和Tekton。 为什么CD社区组成基金会。为什么需要? 整个行业都迫切需要围绕管道、工作流程和其他CI/CD领域合作定义行业规范,并为CI/CD工具提供基础支持。例如,Jenkins社区正在寻求一个“全方位服务”的基金会来托管Jenkins(最受欢迎的CI/CD项目之一),并构建一个增强协作的平台。还需要一个全行业的中立DevOps/CD会议。 这是否代表了云原生态系统的转变? 是的,市场已转向容器化和云原生技术,因此CI/CD系统、DevOps和相关工具的生态系统发生了根本性的变化。CNCF云原生互动景观展示了CI/CD领域的多样性,以及在该领域中活跃的众多项目和供应商。 通过建立供应商中立的持续交付基金会,业界顶级开发者、最终用户和供应商可以将CI/CD作为方法,定义/记录最佳实践以及创建培训材料,以使全球任何软件开发团队能够交付代码更改更快、更可靠、无论它们是否为云原生。 开发者为何要关心? CI/CD项目目前面临的挑战,包括工具复杂性和管道和其他CI/CD工具缺乏行业标准化,正在抑制增长和创新。由于缺乏中立的法律实体和强有力的治理,项目很难吸引新开发者和组织的宝贵支持。项目维护者和开发者花费大量时间和金钱处理安全程序和监督等方面的变通方法。这使人们不再关注新的发展和创新。拥有广泛行业支持的基金会将能够更快地定义行业规范,并为跨项目协作创造更多机会,以改善开发者的工具。 谁用CD? CD广泛应用于云计算、企业IT,并且正在迅速扩展到其他顶级行业垂直领域。例如,在网络运营商与供应商并肩工作,开发CI/CD工具,使开发者能够直接与上游项目的分支合作 – 大幅缩短实施新功能的时间,并解决数月到数天的错误。使用云原生技术(如Kubernetes)时,设置CI/CD管道将加快发布生命周期。这使开发者每天可以多次发布;让团队灵活到足以快速迭代。 CDF如何与渐进式交付相关? 渐进式交付(Progressive delivery)是现代持续交付技术的一种形式,例如灰度发布、功能标记、A/B测试、经过验证的部署组等。渐进式交付技术和技术与持续交付密切相关。有关渐进式交付的更多信息,请阅读James Governor关于此主题的Redmonk博客:https://redmonk.com/jgovernor… 这将如何影响开源软件的开发? 持续交付可提高软件开发团队的速度、生产力和可持续性。CDF促进行业顶级开发者、最终用户和供应商之间的合作,以确保CD方法的软件工程充分发挥其潜力,推进开源软件开发。 哪些项目将包含在CDF中? CDF正在推出四个项目:Jenkins、Jenkins X、Spinnaker和Tekton,还有更多感兴趣的项目正在筹备中。我们邀请人们关注CDF技术监督委员会(“TOC”),该委员会将在未来做出项目决策:https://github.com/cdfoundati…。 我是否必须是成员才可以贡献到CDF项目? 绝对不是,CDF中的开源项目或任何Linux基金会计划的技术贡献都不需要成员资格。组织作为成员加入CDF,因为它们希望在持续交付模型和最佳实践的增长和发展中扮演积极的角色,而不只是支持CDF中的开放源码项目。如果你有兴趣加入,请参阅https://cd.foundation/members…。 什么是Jenkins? Jenkins是领先的开源自动化服务器,由大量不断增长的开发者、测试者、设计者和其他对持续集成、持续交付和现代软件交付实践感兴趣的人提供支持。它基于Java虚拟机(JVM),提供超过1,500个插件,可将Jenkins扩展为几乎所有技术软件交付团队使用的自动化服务器。2019年,Jenkins有超过了200,000个已知安装,使其成为部署最广泛的自动化服务器。 什么是Jenkins X? Jenkins X是Kubernetes上现代云应用程序的开源CI/CD解决方案。Jenkins X提供管道自动化、内置GitOps和预览环境,以帮助团队协作并加速他们的软件交付。Jenkins X使用最好的OSS工具自动化Kubernetes的CI + CD,如Jenkins、Tekton、Prow、SkaffoldKaniko和Helm。 为什么Jenkins和Jenkins X成为CDF的一员? Jenkins和Jenkins X将成为与技术兴趣相关的中立社区的一部分,并在构建开发者社区和项目治理方面获得帮助。CD基金会还将协助Jenkins和Jenkins X的营销和文档工作。 这对现有Jenkins用户有何影响? 将Jenkins和Jenkins X捐赠给CD基金会将促进行业内开发者、最终用户和供应商之间的更多合作。有关详细信息,请参阅此电子邮件和与Jenkins社区的对话:https://groups.google.com/for… 什么是Tekton? Tekton是一组用于构建CI/CD系统的共享开源组件。它使持续交付控制平面现代化,并将软件部署的大脑转移到Kubernetes。Tekton的目标是通过供应商中立的开源基金会为CI/CD管道、工作流程和其他构建模块提供行业规范。Tekton的代码在https://github.com/tektoncd/p…。 为什么Tekton成为CDF的一员?为什么Google会捐赠代码? 作为CDF的创始成员,谷歌正在捐赠Tekton。正如Kubernetes通过提供一组标准的API在云中进行交互而彻底改变了应用程序开发,Google的目标是通过CD基金会为DevOps从业者提供相同的优势。CDF将提供行业规范、安全、实用和可扩展的持续交付构建块,可用于在任何地方部署代码。 Tekton对knative build的影响是什么? 从第1天开始,可插拔性一直是knative的核心功能。将Build与Serving分离的目标是强化这种可插拔性概念。已经对构建系统感到满意的用户可以将其与Knative Serving一起使用。Tekton将继续支持Knative生态系统作为一流的目标环境。Tekton管道将部署到Knative环境。 在可预见的未来,Knative Build将继续作为Knative的一部分,专注于无服务器环境的源到容器工作流程。这两个项目将在标准和界面上保持紧密联系。 什么是Spinnaker? Spinnaker是云端优先的持续交付平台,最初由Netflix创建,目前由Netflix和Google共同领导。它支持所有主要的云平台和Kubernetes,并得到各个供应商的贡献。Spinnaker通常用于大规模组织,DevOps团队通过提供“黄金路径”(golden path)应用程序部署管道来支持许多开发者。 为什么Google/Netflix将Spinnaker捐赠给CDF? 随着Spinnaker最近将其治理正式化,将其转移到基金会是社区自然的下一步。Spinnaker设计为持续交付平台,通常与Jenkins结合使用,因此CDF真的是项目的理想之家。 Spinnaker也是一个多组件系统,在概念上与Tekton分享了许多想法 – 看到两个项目在一个基金会上聚集在一起,是将持续交付向前推进的巨大机会。 这对Spinnaker用户有何影响? Spinnaker作为CDF的一员,社区将有更多机会创建更简单、更强大的端到端体验,并就CI/CD的一套通用标准进行协作。Spinnaker用户在持续交付领域拥有丰富的经验,加入CDF提供了一个与更广泛的社区分享专业知识的绝佳机会。 Spinnaker用户还将受益于CDF社区中广泛的CI/CD知识,他们使用的各种工具之间的一致性,当然还有不断改进的生态系统! 未来的CI/CD项目进入CDF的过程是怎样? 其他项目预计将通过其即将成立的技术监督委员会(TOC)加入CDF:https://github.com/cdfoundati…,重点是将CD生态系统整合在一起,围绕可移植性和互操作性构建规范和项目。 CDF的下一步是什么? 接下来的步骤是启动治理结构。将成立一个理事会、技术和外联/营销委员会。我们计划在未来几个月内实现这一目标,并邀请新成员加入我们的社区。如果你有兴趣加入社区推进CD,请到https://cd.foundation/members…。 CNCF的参与程度,为什么需要一个单独的基金会? 首先要注意的是,CD适用于整个软件行业,而不仅仅适用于现代云原生应用程序。CNCF(Cloud Native Computing Foundation,云计算本地计算基金会)是CDF的姐妹基金会,拥有自己的治理结构和使命。每个基金会都有不同的使命,由其创始成员和技术专家定义。CNCF认为大多数与CD相关的工具超出了他们专注的云原生定义的范围,后者主要关注容器化、微服务、服务网格和编排。CDF超越云和容器,包括传统基础设施、移动、物联网、裸机等。CNCF和CDF都属于较大的Linux基金会旗下,计划在许多领域进行合作,包括同场会议。例如,CDF将于5月20日在西班牙巴塞罗那的KubeCon + CloudNativeCon Europe 2019举办持续交付峰会(CDS)活动。 CDF如何支持或与DevOps领域的其他玩家合作? CDF的使命是为开发者、最终用户和供应商提供一个中立的家庭,以便在CI/CD方法上进行协作。在这方面,CDF将通过发布关注可移植性的最佳实践、培训材料和行业指南来支持DevOps从业者。 有兴趣成为这个新基金会成员并制定治理方案的组织应到CDF加入的页面。开发者可以在此处注册CD基金会邮件列表:info@lists.cd.foundation。任何有兴趣加入CDF的项目都可以联系技术监督委员会(TOC):https://github.com/cdfoundati…。 KubeCon […]
View DetailsVS工程导入protobuf-net(https://github.com/mgravell/protobuf-net) 源码,报错。 解决方法:项目右键属性 —> 生成 —> 找到最下面的高级按钮,点击高级按钮 —> 常规 —> 语言版本 —> 选择 C#最新次要版本,或者比当前版本更高的版本即可,点击确定,然后保存即可。 from:https://blog.csdn.net/iningwei/article/details/86490259
View Details目录 IdentityServer4是什么? OpenID Connect 和 OAuth2.0是什么 Authentication 和 Authorization的区别 OAuth2.0的原理 IdentityServer4能做什么 IdentityServer4定义的基本术语 IdentityServer4的简单示例 IdentityServer4是什么? IdentityServer4是基于ASP.NET Core实现的认证和授权框架,是对OpenID Connect和OAuth 2.0协议的实现。 OpenID Connect 和 OAuth2.0是什么 OpenID Connect: OpenID Connect由OpenID基金会于2014年发布的一个开放标准, 是建立在OAuth 2.0协议上的一个简单的身份标识层, OpenID Connect 兼容 OAuth 2.0. 实现身份认证(Authentication) 参考资料:https://openid.net/connect/ OpenID Connect文档:https://openid.net/specs/openid-connect-discovery-1_0.html OAuth2.0: OAuth2.0是一个开放的工业标准的授权协议(Authorization),它允许用户授权让第三方应用直接访问用户在某一个服务中的特定资源,但不提供给第三方账号及密码信息 参考资料:https://www.cnblogs.com/xiandnc/p/9763121.html OAuth2.0 文档:https://tools.ietf.org/html/rfc6749#page-73 Authentication 和 Authorization的区别 1 2 authentication: n. 证明;鉴定;证实 authorization: n. 授权,认可;批准,委任 前者是身份识别,鉴别你是谁;后者是授权许可,告诉你可以做什么。 举个例子:你吭哧吭哧写了一天的代码,急于回家吃上一口媳妇做的热饭。当你走到小区门口的时候你需要刷小区的门禁卡才能进入到小区里面,然后再找到你家在哪一栋楼,几单元几号,然后掏出钥匙开门才能回到家。在这个过程中刷小区的门禁就是认证你是这个小区的人,拿你家的钥匙开门就是授权的过程,如果你的认证不通过,那就不存在授权。 OAuth2.0的原理 我们先来了解一下OAuth2.0中的几个关键概念: 资源所有者(Resource Owner): 一个能够访问受保护资源的实体。当资源所有者是一个人时,它被称为终端用户 资源服务器(Resource Server): 托管受保护资源的服务器,能够使用访问令牌接受和响应受保护的资源请求 客户端(Client): 代表资源所有者和其授权的应用程序来保护资源请求。术语客户端并不意味着任何特定的实现特征(例如,应用程序是否在服务器、桌面或其他设备上执行) 授权服务器(Authorization Server): 在成功验证资源所有者并获得授权之后,服务器向客户端发出访问令牌。(授权服务器是用来管理Resource Owner,Resource Server,Client的中间人) 场景:小李想要打印(美图快印)自己三年来发布在新浪微博相册中和女朋友的照片,有没有什么方法他既不告诉工作人员自己的新浪微博用账号和密码又能够方便快捷的把照片给到美图快印呢?(排除存U盘这种手工操作) Authorization Server和Resource Server可以使独立的服务提供商,也可以是在一起的,比如例子中新浪微博既作授权服务器也用来存储用户的图片资源。我们可以看到OAuth2解决的问题是:通过Authorization Server可以提供一个访问的凭据(token)给client(美图快印的工作人员),使得client可以在不知道Resource Owner以及Resource Server的用户名和密码的情况下访问到Resource Owner受保护的资源,它是一个完美的中间人。 OAuth2.0详细内容请参考:https://www.cnblogs.com/xiandnc/p/9763121.html IdentityServer4能做什么 用户认证服务 基于OpenID Connect实现的独立的认证服务实现对多平台(web, native, mobile, services)的集中认证 API访问授权 […]
View Details一,Set Set:注重独一无二的性质,该体系集合可以知道某物是否已近存在于集合中,不会存储重复的元素 用于存储无序(存入和取出的顺序不一定相同)元素,值不能重复。 对象的相等性 引用到堆上同一个对象的两个引用是相等的。如果对两个引用调用hashCode方法,会得到相同的结果,如果对象所属的类没有覆盖Object的hashCode方法的话,hashCode会返回每个对象特有的序号(java是依据对象的内存地址计算出的此序号),所以两个不同的对象的hashCode值是不可能相等的。 如果想要让两个不同的Person对象视为相等的,就必须覆盖Object继下来的hashCode方法和equals方法,因为Object hashCode方法返回的是该对象的内存地址,所以必须重写hashCode方法,才能保证两个不同的对象具有相同的hashCode,同时也需要两个不同对象比较equals方法会返回true 该集合中没有特有的方法,直接继承自Collection。
1 2 3 4 5 6 7 8 9 10 11 |
---| Itreable 接口 实现该接口可以使用增强for循环 ---| Collection 描述所有集合共性的接口 ---| List接口 可以有重复元素的集合 ---| ArrayList ---| LinkedList ---| Set接口 不可以有重复元素的集合 |
案例:set集合添加元素并使用迭代器迭代元素。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
public class Demo4 { public static void main(String[] args) { //Set 集合存和取的顺序不一致。 Set hs = new HashSet(); hs.add("世界军事"); hs.add("兵器知识"); hs.add("舰船知识"); hs.add("汉和防务"); System.out.println(hs); // [舰船知识, 世界军事, 兵器知识, 汉和防务] Iterator it = hs.iterator(); while (it.hasNext()) { System.out.println(it.next()); } } } |
二,HashSet
1 2 3 4 5 6 7 8 9 10 11 12 13 |
---| Itreable 接口 实现该接口可以使用增强for循环 ---| Collection 描述所有集合共性的接口 ---| List接口 可以有重复元素的集合 ---| ArrayList ---| LinkedList ---| Set接口 不可以有重复元素的集合 ---| HashSet 线程不安全,存取速度快。底层是以哈希表实现的。 |
HashSet 哈希表边存放的是哈希值。HashSet存储元素的顺序并不是按照存入时的顺序(和List显然不同) 是按照哈希值来存的所以取数据也是按照哈希值取得。 HashSet不存入重复元素的规则.使用hashcode和equals 由于Set集合是不能存入重复元素的集合。那么HashSet也是具备这一特性的。HashSet如何检查重复?HashSet会通过元素的hashcode()和equals方法进行判断元素师否重复。 当你试图把对象加入HashSet时,HashSet会使用对象的hashCode来判断对象加入的位置。同时也会与其他已经加入的对象的hashCode进行比较,如果没有相等的hashCode,HashSet就会假设对象没有重复出现。 简单一句话,如果对象的hashCode值是不同的,那么HashSet会认为对象是不可能相等的。 因此我们自定义类的时候需要重写hashCode,来确保对象具有相同的hashCode值。 如果元素(对象)的hashCode值相同,是不是就无法存入HashSet中了? 当然不是,会继续使用equals 进行比较.如果 equals为true 那么HashSet认为新加入的对象重复了,所以加入失败。如果equals 为false那么HashSet 认为新加入的对象没有重复.新元素可以存入. 总结: 元素的哈希值是通过元素的hashcode方法 来获取的, HashSet首先判断两个元素的哈希值,如果哈希值一样,接着会比较equals方法 如果 equls结果为true ,HashSet就视为同一个元素。如果equals 为false就不是同一个元素。 哈希值相同equals为false的元素是怎么存储呢,就是在同样的哈希值下顺延(可以认为哈希值相同的元素放在一个哈希桶中)。也就是哈希一样的存一列。 hashtable 图1:hashCode值不相同的情况 图2:hashCode值相同,但equals不相同的情况。 HashSet:通过hashCode值来确定元素在内存中的位置。一个hashCode位置上可以存放多个元素。 当hashcode() 值相同equals() 返回为true 时,hashset 集合认为这两个元素是相同的元素.只存储一个(重复元素无法放入)。调用原理:先判断hashcode 方法的值,如果相同才会去判断equals 如果不相同,是不会调用equals方法的。 HashSet到底是如何判断两个元素重复。 通过hashCode方法和equals方法来保证元素的唯一性,add()返回的是boolean类型 判断两个元素是否相同,先要判断元素的hashCode值是否一致,只有在该值一致的情况下,才会判断equals方法,如果存储在HashSet中的两个对象hashCode方法的值相同equals方法返回的结果是true,那么HashSet认为这两个元素是相同元素,只存储一个(重复元素无法存入)。 注意:HashSet集合在判断元素是否相同先判断hashCode方法,如果相同才会判断equals。如果不相同,是不会调用equals方法的。 HashSet 和ArrayList集合都有判断元素是否相同的方法, boolean contains(Object o) HashSet使用hashCode和equals方法,ArrayList使用了equals方法 案例: 使用HashSet存储字符串,并尝试添加重复字符串 回顾String类的equals()、hashCode()两个方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
public class Demo4 { public static void main(String[] args) { // Set 集合存和取的顺序不一致。 Set hs = new HashSet(); hs.add("世界军事"); hs.add("兵器知识"); hs.add("舰船知识"); hs.add("汉和防务"); // 返回此 set 中的元素的数量 System.out.println(hs.size()); // 4 // 如果此 set 尚未包含指定元素,则返回 true boolean add = hs.add("世界军事"); // false System.out.println(add); // 返回此 set 中的元素的数量 System.out.println(hs.size());// 4 Iterator it = hs.iterator(); while (it.hasNext()) { System.out.println(it.next()); } } } |
使用HashSet存储自定义对象,并尝试添加重复对象(对象的重复的判定)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
public class Demo4 { public static void main(String[] args) { HashSet hs = new HashSet(); hs.add(new Person("jack", 20)); hs.add(new Person("rose", 20)); hs.add(new Person("hmm", 20)); hs.add(new Person("lilei", 20)); hs.add(new Person("jack", 20)); Iterator it = hs.iterator(); while (it.hasNext()) { Object next = it.next(); System.out.println(next); } } } class Person { private String name; private int age; Person() { } public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public int hashCode() { System.out.println("hashCode:" + this.name); return this.name.hashCode() + age * 37; } @Override public boolean equals(Object obj) { System.out.println(this + "---equals---" + obj); if (obj instanceof Person) { Person p = (Person) obj; return this.name.equals(p.name) && this.age == p.age; } else { return false; } } @Override public String toString() { return "Person@name:" + this.name + " age:" + this.age; } } |
问题:现在有一批数据,要求不能重复存储元素,而且要排序。ArrayList 、 LinkedList不能去除重复数据。HashSet可以去除重复,但是是无序。 所以这时候就要使用TreeSet了 三,TreeSet 案例:使用TreeSet集合存储字符串元素,并遍历
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
public class Demo5 { public static void main(String[] args) { TreeSet ts = new TreeSet(); ts.add("ccc"); ts.add("aaa"); ts.add("ddd"); ts.add("bbb"); System.out.println(ts); // [aaa, bbb, ccc, ddd] } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
---| Itreable 接口 实现该接口可以使用增强for循环 ---| Collection 描述所有集合共性的接口 ---| List接口 有序,可以重复,有角标的集合 ---| ArrayList ---| LinkedList ---| Set接口 无序,不可以重复的集合 ---| HashSet 线程不安全,存取速度快。底层是以hash表实现的。 ---| TreeSet 红-黑树的数据结构,默认对元素进行自然排序(String)。如果在比较的时候两个对象返回值为0,那么元素重复。 |
红–黑树 红黑树是一种特定类型的二叉树 红黑树算法的规则: […]
View Details