知识点记录
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8ovilnIi-1681441105895)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20211228090433836.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZjlliSi9-1681441105896)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20211228090416658.png)]
第一篇:java基础篇
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uGDWN5gz-1681441105897)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20211215090936948.png)]
第二篇:JVM篇
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U53rqPnZ-1681441105898)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20211215091102628.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IJchSqOg-1681441105898)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20211216091214280.png)]
第三篇:多线程和并发篇
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DRmqCyNG-1681441105899)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20211215091131540.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tcZOxzB5-1681441105899)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20211216090855390.png)]
第四篇:spring篇
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wlXzecat-1681441105899)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20211215091219072.png)]
第五篇:mybatis篇
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i4UaemkV-1681441105900)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20211215091256794.png)]
第六篇:springboot篇
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tyeaIUAZ-1681441105900)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20211215091336359.png)]
第七篇:mysql篇
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rSWnfLTa-1681441105901)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20211215091416083.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Jrl3s4gG-1681441105901)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20211216090938800.png)]
第八篇:redis篇
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Uc4QBz7S-1681441105902)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20211215091457190.png)]
第九篇:springcloud篇
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mMkdH5Ye-1681441105903)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20211215091527848.png)]
第十篇:nginx篇
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8e8gkCIJ-1681441105904)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20211215091545788.png)]
第十一篇:MQ篇:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XCY5UBJz-1681441105904)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20211215091619736.png)]
第十二篇:数据结构和算法篇
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tr3WsoX3-1681441105905)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20211215091647831.png)]
第十三篇:linux篇
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BQFf5Smk-1681441105906)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20211215091715846.png)]
第十四篇:Dubbo篇
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0QCsRp1I-1681441105907)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20211216091055698.png)]
第十五篇:简历篇
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tVfgiTBX-1681441105908)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20211215091804444.png)]
a1.java基本数据类型
基本类型:
int,short,long,char, byte,
float,double,
boolean
引用类型:
类,接口,数组
1.1数组:
定义:格式1:
元素类型[] 数组名 = new 元素类型[元素个数或数组长度];
示例:int[] arr = new int[5];
格式2:
元素类型[] 数组名 = new 元素类型[]{元素,元素,……};
int[] arr = new int[]{3,5,1,7};
int[] arr = {3,5,1,7};
// 初始化方式1:不使用运算符new
int[] arr = { 1, 2, 3, 4, 5 };
int[] arr2 = new int[] { 1, 2, 3, 4, 5 };
//初始化方式2:
int[] arr3=new int[3];
arr3[0]=1;
arr3[1]=5;
arr3[2]=6;
//此时初始化数组,必须将声明,创建,初始化都放在一条语句中个,分开会产生语法错误。
1.2二维数组
二维数组:实质就是存储是一维数组
数组定义:数组类型[][] 数组名 = new 数组类型[一维数组的个数][每一个一维数组中元素的个数];
int [][] a=new int{{1,2,3,4},{1,2,3,4},{1,2,3,4}};
int [][] a=new int[无长度][无长度]{{1,2,3,4},{1,2,3,4},{1,2,3,4}};
a[0][0]={1,2,3,4}; //错误写法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fmpq9STR-1681441105909)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20211215142251196.png)]
- Arrays的使用:
- 遍历: toString() 将数组的元素以字符串的形式返回
- 排序: sort() 将数组按照升序排列
package com.test;
import java.util.Arrays;
public class StringTester {
public static void main(String[] args) {
// TODO Auto-generated method stub
int [][] c={{1,2,3,2},{2,2,3,4},{2,2,3,4}};//方式1
int [][] b=new int[][]{{1,2,3,2},{2,2,3,4},{2,2,3,4}};//方式2
int [][] a=new int[3][4];//方式3 动态赋值
int value=0;
for(int i=0;i<a.length;i++) {
for(int j=0;j<a[i].length;j++) {
a[i][j]=++value;
System.out.println("=================="+Arrays.toString(a[i])); //将数组以字符串的形式返回
}
}
System.out.println("=================="+Arrays.toString(a));
}
}
a2.jVM
2.1>类加载机制
2.1类加载
2.1.1什么是类加载?
JVM将编译好的.class文件(字节码文件)以二进制流的方式加载到我们的内存中,并且将二进制流中静态的数据结构转换成我们方法区中动态运行数据结构,并且在堆内存中生产一个java.lang.class对象,作为提供给外界访问我们方法区动态运行数据结构的一个入口。
2.1.2类加载器有哪些?
主要有启动类加载器(BootStrap ClassLoader)和其他所有类加载器。
注意:启动类加载器是虚拟机的一部分,是由C++实现,其它类加载器是独立于虚拟机外的一部分,都继承了抽象类java.lang.ClassLoader.
Bootstrap是Tomcat的启动类。org.apache.catalina.startup.Bootstart类
类加载器主要分为以下四个部分:
启动类加载器:
扩展类加载器:
应用类加载器:
用户自定义加载器:
2.2双亲委派模型
2.21 什么是双亲委派模型?
当需要加载一个类的时候,子类加载器并不会马上加载,而是依次去请求父类加载器加载,一直往上请求到最高类加载器:启动类加载器。当启动类加载不了的时候,依次往下让子类加载器进行加载。当达到最底下的时候,如果还是加载不到该类,就会出现classNotFound的情况。
优点:保证了程序的安全性。例子:比如我们重新写了一个String类,加载的时候不会去加载到我们自己写的String类,因为当请求上到最高层的时候,启动类加载器发现自己能够加载String类,因此就不会加载到我们自己写的String类了。
2.22为什么使用双亲委派模型?
1.类加载器优先级层次关系
2.程序安全
2.23有哪些场景破坏双亲委派模型?
比较常见的:
1)线程上下文类加载器,典型的:JDBC使用线程上下文类加载器加载Driver实现类
2)Tomcat的多web应用程序
3)OSCI实现模块化部署
2.24为什么要破坏双亲委派模型
原因很简单,无法满足需求,只能破坏
我们知道Tomcat容器可以同时部署多个web应用程序,多个web程序可能存在依赖同一个jar包,版本不同会导致jar包冲突
2.25如何破坏双亲委派模型
2.3类加载步骤(5步)
加载:将java源文件编译后的.class字节码文件以二进制流的方式加载进内存链接。
验证:验证加载进来的二进制流是否符合虚拟机规范,不会危害到虚拟机自身的安全
准备:给类变量(静态变量)赋予初始值,基本数据/引用类型数据
解析:将字符串引用转换为直接引用
初始化:变量赋予初始值、执行静态语句块、执行构造函数等等
2.2运行时数据区
标准答案:因为规范是这么写的,因为源码是这么写的。
2.2.1运行时数据区(Run-Time Data Areas)
包括:线程间共享区域和线程间隔离的区域
线程间共享区域(堆,方法区,运行时常量池):是指一些数据区域在java虚拟机启动是被创建,随着虚拟机退出而销毁。
线程间隔离区域(程序计数器、java虚拟机栈、本地方法栈):是指数据区域在线程创建时创建,在线程退出时销毁。
1)程序计数器
2)java虚拟机栈(存储栈帧)
如果现场正在执行的是java(不是native的),则程序计数器记录的是正在执行的java虚拟机字节码指令的地址。
如果不是,那么计数器的值为空(undefined).
3) 本地方法栈
区别于java虚拟机栈,本地方法栈则为虚拟机使你用的本地(Native)方法服务
4)堆(分配内存)
是被各个线程共享的运行时内存区域,也是供所有实例和数组对象分配内存的区域。
堆在虚拟机启动时创建,堆存储的对象不会被显示释放,而是由垃圾收集器进行统一管理和回收
5)方法区(存储)
是被各个现场共享的运行时内存区域。
方法区类似于传统语言的编译代码的存储区。
它存储了每一个类的结构信息,例如:运行时常量池、字段和方法数据,构造函数和普通方法的字节码内容,还包括一些用于类、实例、接口初始化用到的特殊方法。
6)运行时常量池
是class文件中每一个类或接口的常量池表(constant_pool table)的运行时表示形式。
它包含了若干常量,从编译时已知的数值字面量到必须在运行时解析后才能获得的方法和字段引用。运行时常量池的功能类似于传统编程语言的符号表(symbol table),不过它包含的数据范围比通常意义上的符号表要更为广泛。
2.3java中常见有哪几种常量池?
主要三种:class文件常量池,运行时常量池,字符串常量池。
2.4jdk1.8元空间替换永久代
2.5为什么引入元空间?(–maxMetaspaceSize参数限制元空间大小,如果没有设置默认限制为机器内存)
在java8之前,java虚拟机使用永久代来存放类元信息,通过-XX:PermSize,-XX:MaxPermSize来控制这块内存的大小,随着动态类加载的情况越来越多,这块内存变得不太可控,到底设置多大合适是每个开发者要考虑的问题。小了内存溢出,大了浪费物理内存。
元空间:当我们没有指定-XX:MaxPermSize时,元空间可以动态调整使用的内存大小,以容纳不断增加的类。
元空间最大为机器内存
2.6怎么判断对象已经“死去”?
常见的判定方法有两种:引用计数法和可达性分析算法(如hotspot(无线热点))
引用计数法:给对象添加一个引用计数器, 每当有一个地方引用它时,计数器值加1,当引用失效时,计数器值减去1
可达性分析算法:"GC Root"作为对象的起始点,从这个节点开始向下搜索,搜索走过的路径称为引用链,所以能不能连接到GCRoot作为判断对象是否可用。
2.7介绍下四种引用(强引用,软引用,弱引用,虚引用)
2.8垃圾收集有哪些算法
引用计数 :原理是此对象有一个引用,即增加一个计数,删除一个引用则减少一个计数。垃圾回收时,只用收集计数为 0 的对象。此算法最致命的是无法处理循环引用的问题;
标记-清除 :此算法执行分两阶段。第一阶段从引用根节点开始标记所有被引用的对象,第二阶段遍历整个堆,把未标记的对象清除;
此算法需要暂停整个应用,同时,会产生内存碎片;
复制算法 :此算法把内存空间划为两个相等的区域,每次只使用其中一个区域。垃圾回收时,遍历当前使用区域,把正在使用中的对象复制到另外一个区域中;
此算法每次只处理正在使用中的对象,因此复制成本比较小,同时复制过去以后还能进行相应的内存整理**,不会出现 “碎片” 问题。当然,此算法的缺点也是很明显的,就是需要两倍内存空间**;
标记-整理 :此算法结合了 “标记-清除” 和 “复制” 两个算法的优点。也是分两阶段,第一阶段从根节点开始标记所有被引用对象,第二阶段遍历整个堆,把清除未标记对象并且把存活对象 “压缩” 到堆的其中一块,按顺序排放。
2.9 JVM 内存划分
JVM 内存划分:
-
方法区(线程共享):常量、静态变量、JIT(即时编译器) 编译后的代码也都在方法区;
堆内存(线程共享):垃圾回收的主要场所;
程序计数器: 当前线程执行的字节码的位置指示器;
虚拟机栈(栈内存):保存局部变量、基本数据类型变量以及堆内存中某个对象的引用变量;
本地方法栈 :为 JVM 提供使用 native 方法的服务。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KoxtLtyk-1681441105910)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20211216091214280.png)]
2.10内存泄漏和内存溢出
答:
概念:
内存溢出指的是内存不够用了;
内存泄漏是指对象可达,但是没用了。即本该被 GC 回收的对象并没有被回收;
内存泄露是导致内存溢出的原因之一;内存泄露积累起来将导致内存溢出。
内存泄漏的原因分析:
长生命周期的对象引用短生命周期的对象;
没有将无用对象置为 null。
————————————————
版权声明:本文为CSDN博主「zghgchao」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_22027637/article/details/806663202.11堆内存分配:
JVM 初始分配的内存由-Xms 指定,默认是物理内存的 1/64;
JVM 最大分配的内存由-Xmx 指定,默认是物理内存的 1/4;
默认空余堆内存小于 40% 时,JVM 就会增大堆直到-Xmx 的最大限制;空余堆内存大于 70% 时,JVM 会减少堆直到 -Xms 的最小限制;
因此服务器一般设置-Xms、-Xmx 相等以避免在每次 GC 后调整堆的大小。对象的堆内存由称为垃圾回收器的自动内存管理系统回收。
非堆内存分配:
JVM 使用-XX:PermSize 设置非堆内存初始值,默认是物理内存的 1/64;
由 XX:MaxPermSize 设置最大非堆内存的大小,默认是物理内存的 1/4;
-Xmn2G:设置年轻代大小为 2G;
-XX:SurvivorRatio,设置年轻代中 Eden 区与 Survivor 区的比值。
————————————————
版权声明:本文为CSDN博主「zghgchao」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_22027637/article/details/80666320
a3分布式
a4算法
a5Redis
1数据类型
Redis主要有5种数据类型,包括String,List,Set,Zset,Hash,满足大部分的使用要求
2什么是Redis持久化?
持久化就是把内存的数据写到磁盘中去,防止服务宕机了内存数据丢失。
Redis 的持久化机制是什么?各自的优缺点?
Redis 提供两种持久化机制 RDB(默认) 和 AOF 机制:
RDB:是Redis DataBase缩写快照
RDB是Redis默认的持久化方式。按照一定的时间将内存的数据以快照的形式保存到硬盘中,对应产生的数据文件为dump.rdb。通过配置文件中的save参数来定义快照的周期。
AOF:持久化
AOF持久化(即Append Only File持久化),则是将Redis执行的每次写命令记录到单独的日志文件中,当重启Redis会重新将持久化的日志中文件恢复数据。
当两种方式同时开启时,数据恢复Redis会优先选择AOF恢复。
3redis为什么要有淘汰机制?
redis淘汰机制的存在是为了更好的使用内存,用一定的缓存丢失来换取内存的使用效率。
4redis的过期策略
redis有两种过期策略,定期删除和惰性删除
-
- 定期删除:redis每个100ms随机抽取一些设置了过期时间的key,检查其是否过期,如果过期就删除。
- 惰性删除:在获取某个key的时候,redis检查一下,如果该key设置了过期时间则判断该过期时间是否已经过期,如果过期了就直接删掉并不返回任何东西。
5redis的内存淘汰机制
当redis内存快耗尽时,redis会启动内存淘汰机制,将部分key清掉以腾出内存。
redis提供6中数据淘汰策略,可在redis.conf中配置:maxmemory-policy noeviction
- noeviction:禁止驱逐数据。默认配置都是这个。当内存使用达到阀值的时候,所有引起申请内存的命令都会报错。
- volatile-lru:从设置了过期时间的数据集中挑选最近最少使用的数据淘汰。
- volatile-ttl:从已设置了过期时间的数据集中挑选即将要过期的数据淘汰。
- volatile-random:从已设置了过期时间的数据集中任意选择数据淘汰。
- allkeys-lru:从数据集中挑选最近最少使用的数据淘汰。
- allkeys-random:从数据集中任意选择数据淘汰。
redis的内存淘汰机制
5**redis缓存问题
5.1缓存雪崩
缓存雪崩是指缓存同一时间大面积的失效,所以,后面的请求都会
落实到数据库上,造成数据库短时间内承受大量请求而崩掉。
解决方案:
1.缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
2.一般并发量不是特别多的时候,使用最多的解决方案是加锁排队
3.给每一个缓存数据增加相应的缓存标记,记录缓存的是否失效,如果缓存标记
失效,则更新缓存。
5.2缓存穿透
缓存穿透是值缓存和数据库中都没有的数据,导致所以的请求都落实到数据库上
造成数据库短时间内承受大量请求而崩掉。
解决方案:
1.接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截。
2从缓存取不到的数据,在数据库中也没有找到,这是也可以将key-value
对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常
情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击。
3.采用布隆过滤器,将所有可能缓存在数据哈希到一个足够大的bitmap中,
一个一定不存在的数据会被这个bitmap拦截掉,从而避免了对底层存储系统
的查询压力。
附件:
对空间对的利用到达了一种极致,那就是bitmap和布隆过滤器(Bloom Filter)
Bitmap:典型的就是哈希表。
缺点是:Bitmap对用每个元素只能记录1bit信息,如果还想完成额外的功能,
恐怕只能靠牺牲更多的空间,时间来完成了。
布隆过滤器(推荐)
就是引入了k(k>1)k(k>1)个相互独立的哈希函数,保证在给定的空间,误判率下
完成元素判重的过程。
它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的
误识别率和删除困难。
Bloom-Filter算法的核心思想就是利用多个不同的Hash函数来解决“冲突”。
Hash存在一个冲突(碰撞)的问题,用同一个Hash得到的两个URL的值有可能相同,为了减少冲突,我们可以多引入几个Hash,如果通过其中的一个Hashz
值我们得出某元素不在集合中,那么该元素肯定不在集合中,只有在所有Hash
告诉我们该元素在集合中时,才能确定该元素存在改集合中,这便是Bloom-Filter的基本思想。
Bloom-Filter一般用于在大数据量的集合中判定某元素是否存在。
5.3缓存击穿
是指缓存中没有但是数据库中有的数据(一般是缓存时间到期),这时由于
并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成大压力。和缓存雪崩不同的是,缓存击穿指并发同一条数据,缓存雪崩是不同数据都过期了,很多数据库都查不到从而查数据库。
解决方案:
1.设置热点数据永远不过期
2.加互斥锁
5.4缓存预热
就是系统上线后,将相关的缓存数据直接加载到缓存系统。这样就可以
避免在用户请求的时候,先查到数据库,然后在将数据缓存的问题!用户
直接查询事先预热的缓存数据!
解决方案:
1.直接洗个缓存刷新页面,上线时手工操作一下
2.数据库不大,可以在项目启动的时候自动进行加载
3.定时刷新缓存
5.5缓存降级
当访问量剧增,服务出现问题(如响应时间慢或不响应)或非核心服务影响
到哦核心流程的性能时,仍然需要保证服务还是可用的,即使是有损服务。
系统可以根据一些关键数据进行自动降级,也可以配置开关实现人工降级。
缓存降级的最终目的是保证核心服务可用,即使有损的。而且有些服务是无法
降级的(如购物车,结算)。
在进行降级之前要对系统进行梳理,看看系统是不是可丢车保帅;从而梳理出
哪些必须誓死保护,哪些可降级;比如可以参考日志级别设置预案:
a6Mybatis
a7Spring
7.1SpringIoc的容器构建流程
1)获取一个新的bean工厂:通常是ApplicationContext
2)加载和解析spring的配置,解析bean对象,将解析到的bean封装成BeanDefinition,并放到本地缓存中。
3)实例化和调用BeanFactoryPostProcessor(BeanDefinitionReggistryPostProcessor)的扩展方法,这边是一个非常重要的扩展点。
4)实例化BeanPostProcessor,加载到BeanFactory中,但是这边还不触发,该扩展接口的方法在bean对象
a8Mysql
a9JAVA基础
9.1写一个冒泡排序
public static void bubbleSort() {
int arr[] = {-5, 29, 7, 10, 5, 16};
for (int i = 1; i < arr.length; i++) {
for (int j = 0; j < arr.length - i; j++) {
if (arr[j] < arr[j + 1]) {
int temp;
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
for (int i = 0; i < arr.length; i++) {
System.out.print(" " + arr[i] + " ");
}
}
9.2写一个单例的实现
单例模式一共有8种写法:
1)饿汉式 两种
2)懒汉式 三种
3)双重检查
4)静态内部
5)枚举
package com.test;
public class single {
private static single instance = new single();
public static single getInstance() {
return instance;
}
}
package com.test;
public class LazySingleton {
public static void main(String[] args) {
// TODO Auto-generated method stub
LazySingleton.getInstance();
}
private LazySingleton() {
}
private static class SingletonHolder {
private static LazySingleton instance = new LazySingleton();
}
public static LazySingleton getInstance() {
return SingletonHolder.instance;
}
public void showMessage(){
System.out.println("Hello World!");
}
}
9.3单例的应用场景
好多没怎么使用过的人可能会想,单例模式感觉不怎么用到,实际的应用场景有哪些呢?以下,我将列出一些就在咱们周边和很有意义的单例应用场景。
\1. Windows的Task Manager(任务管理器)就是很典型的单例模式(这个很熟悉吧),想想看,是不是呢,你能打开两个windows task manager吗? 不信你自己试试看哦~
\2. windows的Recycle Bin(回收站)也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。
\3. 网站的计数器,一般也是采用单例模式实现,否则难以同步。
\4. 应用程序的日志应用,一般都何用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加。
\5. Web应用的配置对象的读取,一般也应用单例模式,这个是由于配置文件是共享的资源。
\6. 数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源。数据库软件系统中使用数据库连接池,主要是节省打开或者关闭数据库连接所引起的效率损耗,这种效率上的损耗还是非常昂贵的,因为何用单例模式来维护,就可以大大降低这种损耗。
\7. 多线程的线程池的设计一般也是采用单例模式,这是由于线程池要方便对池中的线程进行控制。
\8. 操作系统的文件系统,也是大的单例模式实现的具体例子,一个操作系统只能有一个文件系统。
\9. HttpApplication 也是单位例的典型应用。熟悉ASP.Net(IIS)的整个请求生命周期的人应该知道HttpApplication也是单例模式,所有的HttpModule都共享一个HttpApplication实例.
总结以上,不难看出:
单例模式应用的场景一般发现在以下条件下:
(1)资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如上述中的日志文件,应用配置。
(2)控制资源的情况下,方便资源之间的互相通信。如线程池等。
大家可以追加其他常见的应用场景哈非常欢迎
a10集合(HashMap)
1 HashMap不是线程安全的
HashMap是map接口的子类,是将键映射到值的对象,其中键和值都是对象,并且不能包含重复键,但可以包含重复值。HashMap允许null key和null value,而hashtable不允许。
2 HashTable是线程安全。
HashMap是Hashtable的轻量级实现(非线程安全的实现),他们都完成了Map接口,主要区别在于HashMap允许空(null)键值(key),由于非线程安全,效率上可能高于Hashtable。
HashMap允许将null作为一个entry的key或者value,而Hashtable不允许。 HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey。因为contains方法容易让人引起误解。 Hashtable继承自Dictionary类,而HashMap是Java1.2引进的Map interface的一个实现。 最大的不同是,Hashtable的方法是Synchronize的,而HashMap不是,在多个线程访问Hashtable时,不需要自己为它的方法实现同步,而HashMap 就必须为之提供外同步。 Hashtable和HashMap采用的hash/rehash算法都大概一样,所以性能不会有很大的差
a11并发编程
开发环境
a12JAVAWEB
12.1 servlet
12.1.1Servlet是什么?
JAVA Servlet 是运行在Web应用服务器上的程序,它作为来自Web浏览器活其他Http客户端的请求和http 服务器上的数据库或应用程序之间的中间层。
使用Servlet,你可以收集来自网页表单的用户输入,呈现来自数据库或者其他源的记录,还可以动态创建网页。
12.1.2Servlet架构图
12.1.3Servlet包:
servlet-api-2.5.jar
12.1.4Servlet生命周期:
Servlet生命周期可以被定义为从创建直到毁灭的整个过程。
1)servlet初始化调用init()方法
2)Servlet调用service()方法来处理客户端请求
3)Servlet销毁前调用destory()方法
4)最后,Servlet是游JVM的垃圾回收器进行垃圾回收的
12.1.5Service方法:
Service()方法是执行实际任务的主要方法。Servlet容器调用service()方法来处理客户端(浏览器)的请求,并把格式化的响应写回给客户端。每次服务器接收到一个servlet请求时,服务器会产生一个新的线程并调用服务。service()方法检查HTTP请求类型(GET,POST,PUT,DELETE 等),并且在是适当的时候调用doGet,doPost,doPut,doDelete等方法。
service() 方法由容器调用,service 方法在适当的时候调用 doGet、doPost、doPut、doDelete 等方法。所以,您不用对 service() 方法做任何动作,您只需要根据来自客户端的请求类型来重写 doGet() 或 doPost() 即可。
12.1.6Servlet客户端HTTP请求
下面的方法可用在Servlet程序中读取HTTP头。这些方法通过HttpServletRequest对象可用
package javax.servlet.http;
import javax.servlet.ServletRequest;
import java.util.Enumeration;
public interface HttpServletRequest extends ServletRequest {
public static final String BASIC_AUTH = "BASIC";
public static final String FORM_AUTH = "FORM";
public static final String CLIENT_CERT_AUTH = "CLIENT_CERT";
public static final String DIGEST_AUTH = "DIGEST";
public String getAuthType();
//getCookies 返回客户端发送请求的所有Cookie对象
public Cookie[] getCookies();
public long getDateHeader(String name);
public String getHeader(String name);
public Enumeration getHeaders(String name);
public Enumeration getHeaderNames();
public int getIntHeader(String name);
public String getMethod();
public String getPathInfo();
public String getPathTranslated();
public String getContextPath();
public String getQueryString();
public String getRemoteUser();
public boolean isUserInRole(String role);
public java.security.Principal getUserPrincipal();
public String getRequestedSessionId();
public String getRequestURI();
public StringBuffer getRequestURL();
public String getServletPath();
public HttpSession getSession(boolean create);
//返回与该请求关联的当前 session 会话,或者如果请求没有 session 会话,则创建一个。
public HttpSession getSession();
public boolean isRequestedSessionIdValid();
public boolean isRequestedSessionIdFromCookie();
public boolean isRequestedSessionIdFromURL();
public boolean isRequestedSessionIdFromUrl();
}
12.1.7Servlet客户端HTTP响应
<!--1一个状态行:包括 HTTP 版本、一个状态码和一个对应于状态码的短消息(在本例中为 OK)-->
HTTP/1.1 200 OK
<!--2 一些响应报头-->
Content-Type: text/html
Header2: ...
...
HeaderN: ...
<!--3一个空行和文档-->
(Blank Line)
<!doctype ...>
<html>
<head>...</head>
<body>
...
</body>
</html>
package javax.servlet.http;
import java.io.IOException;
import javax.servlet.ServletResponse;
public interface HttpServletResponse extends ServletResponse {
/**
1 把指定的 cookie 添加到响应。
**/
public void addCookie(Cookie cookie);
public boolean containsHeader(String name);
public String encodeURL(String url);
/*4.为 sendRedirect 方法中使用的指定的 URL 进行编码,或者如果编码不是必需的,则返回 URL 未改变。*/
public String encodeRedirectURL(String url);
/*5.对包含 session 会话 ID 的指定 URL 进行编码,或者如果编码不是必需的,则返回 URL 未改变。
*/
public String encodeUrl(String url);
public String encodeRedirectUrl(String url);
/*
7.使用指定的状态发送错误响应到客户端。
*/
public void sendError(int sc, String msg) throws IOException;
/*
8.使用指定的状态码发送错误响应到客户端,并清除缓冲区。
*/
public void sendError(int sc) throws IOException;
public void sendRedirect(String location) throws IOException;
public void setDateHeader(String name, long date);
public void addDateHeader(String name, long date);
public void setHeader(String name, String value);
public void addHeader(String name, String value);
public void setIntHeader(String name, int value);
public void addIntHeader(String name, int value);
/*
为该响应设置状态码。
*/
public void setStatus(int sc);
public void setStatus(int sc, String sm);
public static final int SC_CONTINUE = 100;
public static final int SC_SWITCHING_PROTOCOLS = 101;
public static final int SC_OK = 200;
public static final int SC_CREATED = 201;
public static final int SC_ACCEPTED = 202;
public static final int SC_NON_AUTHORITATIVE_INFORMATION = 203;
public static final int SC_NO_CONTENT = 204;
public static final int SC_RESET_CONTENT = 205;
public static final int SC_PARTIAL_CONTENT = 206;
public static final int SC_MULTIPLE_CHOICES = 300;
public static final int SC_MOVED_PERMANENTLY = 301;
public static final int SC_MOVED_TEMPORARILY = 302;
public static final int SC_FOUND = 302;
public static final int SC_SEE_OTHER = 303;
public static final int SC_NOT_MODIFIED = 304;
public static final int SC_USE_PROXY = 305;
public static final int SC_TEMPORARY_REDIRECT = 307;
public static final int SC_BAD_REQUEST = 400;
public static final int SC_UNAUTHORIZED = 401;
public static final int SC_PAYMENT_REQUIRED = 402;
public static final int SC_FORBIDDEN = 403;
public static final int SC_NOT_FOUND = 404;
public static final int SC_METHOD_NOT_ALLOWED = 405;
public static final int SC_NOT_ACCEPTABLE = 406;
public static final int SC_PROXY_AUTHENTICATION_REQUIRED = 407;
public static final int SC_REQUEST_TIMEOUT = 408;
public static final int SC_CONFLICT = 409;
public static final int SC_GONE = 410;
public static final int SC_LENGTH_REQUIRED = 411;
public static final int SC_PRECONDITION_FAILED = 412;
public static final int SC_REQUEST_ENTITY_TOO_LARGE = 413;
public static final int SC_REQUEST_URI_TOO_LONG = 414;
public static final int SC_UNSUPPORTED_MEDIA_TYPE = 415;
public static final int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
public static final int SC_EXPECTATION_FAILED = 417;
public static final int SC_INTERNAL_SERVER_ERROR = 500;
public static final int SC_NOT_IMPLEMENTED = 501;
public static final int SC_BAD_GATEWAY = 502;
public static final int SC_SERVICE_UNAVAILABLE = 503;
public static final int SC_GATEWAY_TIMEOUT = 504;
public static final int SC_HTTP_VERSION_NOT_SUPPORTED = 505;
}
12.1.8Servlet过滤器方法
过滤器是一个实现了javax.servlet.Filter接口的java 类。
package com.runoob.test;
//导入必需的 java 库
import javax.servlet.*;
import java.util.*;
//实现 Filter 类
public class LogFilter implements Filter {
public void init(FilterConfig config) throws ServletException {
// 获取初始化参数
String site = config.getInitParameter("Site");
// 输出初始化参数
System.out.println("网站名称: " + site);
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws java.io.IOException, ServletException {
// 输出站点名称
System.out.println("站点网址:http://www.runoob.com");
// 把请求传回过滤链
chain.doFilter(request,response);
}
public void destroy( ){
/* 在 Filter 实例被 Web 容器从服务移除之前调用 */
}
}
12.1.9Servlet异常处理
当一个 Servlet 抛出一个异常时,Web 容器在使用了 exception-type 元素的 web.xml 中搜索与抛出异常类型相匹配的配置。
您必须在 web.xml 中使用 error-page 元素来指定对特定异常 或 HTTP 状态码 作出相应的 Servlet 调用。
<!-- servlet 定义 -->
<servlet>
<servlet-name>ErrorHandler</servlet-name>
<servlet-class>ErrorHandler</servlet-class>
</servlet>
<!-- servlet 映射 -->
<servlet-mapping>
<servlet-name>ErrorHandler</servlet-name>
<url-pattern>/ErrorHandler</url-pattern>
</servlet-mapping>
<!-- error-code 相关的错误页面 -->
<error-page>
<error-code>404</error-code>
<location>/ErrorHandler</location>
</error-page>
<error-page>
<error-code>403</error-code>
<location>/ErrorHandler</location>
</error-page>
<!-- exception-type 相关的错误页面 -->
<error-page>
<exception-type>
javax.servlet.ServletException
</exception-type >
<location>/ErrorHandler</location>
</error-page>
<error-page>
<exception-type>java.io.IOException</exception-type >
<location>/ErrorHandler</location>
</error-page>
//导入必需的 java 库
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
//扩展 HttpServlet 类
public class ErrorHandler extends HttpServlet {
// 处理 GET 方法请求的方法
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
Throwable throwable = (Throwable)
request.getAttribute("javax.servlet.error.exception");
Integer statusCode = (Integer)
request.getAttribute("javax.servlet.error.status_code");
String servletName = (String)
request.getAttribute("javax.servlet.error.servlet_name");
if (servletName == null){
servletName = "Unknown";
}
String requestUri = (String)
request.getAttribute("javax.servlet.error.request_uri");
if (requestUri == null){
requestUri = "Unknown";
}
// 设置响应内容类型
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
String title = "菜鸟教程 Error/Exception 信息";
String docType = "<!DOCTYPE html>\n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n" +
"<body bgcolor=\"#f0f0f0\">\n");
out.println("<h1>菜鸟教程异常信息实例演示</h1>");
if (throwable == null && statusCode == null){
out.println("<h2>错误信息丢失</h2>");
out.println("请返回 <a href=\"" +
response.encodeURL("http://localhost:8080/") +
"\">主页</a>。");
}else if (statusCode != null) {
out.println("错误代码 : " + statusCode);
}else{
out.println("<h2>错误信息</h2>");
out.println("Servlet Name : " + servletName +
"</br></br>");
out.println("异常类型 : " +
throwable.getClass( ).getName( ) +
"</br></br>");
out.println("请求 URI: " + requestUri +
"<br><br>");
out.println("异常信息: " +
throwable.getMessage( ));
}
out.println("</body>");
out.println("</html>");
}
// 处理 POST 方法请求的方法
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
12.1.10 Servlet Cookie处理
12.1.11 Servlet Session处理
a13设计模式
13.1 7大原
a14.Mysql
14.1存储myisam和innodb的区别吗?
myisam引擎是5.1版本之前的默认引擎,支持全文检索、压缩、空间函数等,但是不支持事务和行级锁,所以一般用于有大量查询少量插入的场景来使用,而且myisam不支持外键,并且索引和数据是分开存储的。
innodb是基于聚簇索引索引建立的,和myisam相反它支持事务、行级锁、外键,并且通过MVCC来支持高并发、索引和数据存储在一起
14.2mysql事务的四大特性?
一般来说,事务是必须满足4个条件(ACID):原子性(Atomicity)或称不可分割性、一致性(Consistency)、隔离性(Isolation,又称独立性)、持久性(Durability)
原子性:事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行。
一致性:指在事务开始之前和事务结束以后,数据不会被破坏,假如A账户给B账户转10块钱,不管成功与否,A和B的总金额不变。
隔离性:多个事务并发访问时,事务之间的相互隔离,即一个事务不影响其他事务运行效果。简言之,就是事务之间井水不犯河水
持久性:表示事务完成以后,改事务对数据库所作的操作更改,将持久地保存在数据库之中。
14.3事务的隔离级别有哪些?MySQL的默认隔离级别是什么?
Mysql默认的事务隔离级别是可重复读,而大多数数据库默认的事务隔离级别是Read committed,比如SqlServer,Oracle。
1)读未提交
2)读已提交
3)可重复读
4)串行化
14.3数据库连接池性能对比
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BlOY8lcM-1681441105912)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20220220105629821.png)]
性能方面 hikariCP>druid>tomcat-jdbc>dbcp>c3p0
a15.java 数据结构
枚举(Enumeration),位集合(BitSet), 向量(Vector),栈(Stack),字典(Dictionary),哈希表(Hashtable),属性(Properties)
15.1枚举
常用方法:
1)boolean hasMoreElements( )
测试此枚举是否包含更多的元素。
2)Object nextElement( )
如果此枚举对象至少还有一个可提供的元素,则返回此枚举的下一个元素。
package com.test;
import java.util.Enumeration;
import java.util.Vector;
public class EnumerationTester {
public static void main(String[] args) {
Enumeration<String> eu=null;
Vector<String> ver=new Vector<String>();
ver.add("Sunday");
ver.add("Monday");
ver.add("Tuesday");
ver.add("Wednesday");
ver.add("Thursday");
ver.add("Friday");
ver.add("Saturday");
eu=ver.elements();
while (eu.hasMoreElements()){
System.out.println(eu.nextElement());
}
}
}
15.2位集合
15.3向量
15.4栈
15.5字典
15.6哈希表
package com.test;
import java.util.Hashtable;
import java.util.Stack;
public class Hastable {
public static void main(String[] args) {
System.out.println("---------------------10001-------------------------");
System.out.println("---------------------10002-------------------------");
System.out.println("---------------------10003-------------------------");
Hashtable[] var7 = null;
//Hashtable[] var7=new Hashtable[8];
Hashtable bb=new Hashtable();
bb.put("客户名称", "晋能租赁11");
bb.put("客户编码", "CH0002");
bb.put("归属区域", "上海");
bb.put("客户经理", "王建");
bb.put("客户经理对应部门", "业务三部");
Stack var5 = new Stack();//栈 后进先出原则
var5.push(bb);
Hashtable bb1=new Hashtable();
bb1.put("客户名称", "三峡租赁");
bb1.put("客户编码", "CH0001");
bb1.put("归属区域", "北京");
bb1.put("客户经理", "马兵");
bb1.put("客户经理对应部门", "业务一部");
var5.push(bb1);
Hashtable bb2=new Hashtable();
bb2.put("客户名称", "兴邦租赁");
bb2.put("客户编码", "CH0003");
bb2.put("归属区域", "深圳");
bb2.put("客户经理", "中华");
bb2.put("客户经理对应部门", "业务三部");
var5.push(bb2);
var7=new Hashtable[var5.size()];
for (int var15 = var7.length - 1; var15 >= 0; --var15) {
var7[var15] = (Hashtable) var5.pop();
}
for(int i=0;i<=var7.length-1;i++) {
System.out.println("================"+var7[i].toString());
Hashtable ab=new Hashtable();
ab=var7[i];
System.out.println("========客户经理=========="+ab.get("客户经理"));
System.out.println("========客户名称=========="+ab.get("客户名称"));
System.out.println("========客户编码=========="+ab.get("客户编码"));
System.out.println("========归属区域=========="+ab.get("归属区域"));
System.out.println("========客户经理对应部门=========="+ab.get("客户经理对应部门"));
}
}
}
a16.springboot
16.0springmvc的流程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VWwE4gv1-1681441105913)(D:\有道存储\qq5489A70FB460750E3F1590EB4F0ACEFE\59e2b542710a476284fdfb6a95527bde\82-332542805.png)]
a.客户端发送请求
b.前端控制器DispatcherServlet 接收请求,并调用处理映射器HandlerMapping(可以根据xml配置、注解进行查找)
c.处理映射器找到具体的处理器进行处理,生成处理器对象Handler以及处理拦截器HandlerInterceptor(如果有则生成)返回到前端控制器
d.DispatcherServlet 调用处理适配器HandlerAdapter
e.处理适配器通过调用具体的处理器,处理器执行后生成ModelAndView,返回给处理适配器ModelAndView对象
f.处理适配器向DispatcherServlet 返回ModelAndView (ModelAndView是springmvc框架的一个底层对象,包括 Model和view)
g.DispatcherServlet 将ModelAndView 传递给视图解析器 ViewReslover
h.视图解析器解析后返回具体的view(根据逻辑视图名解析成真正的视图(jsp))
i.DispatcherServlet 根据View进行渲染视图(视图渲染将模型数据(在ModelAndView对象中)填充到request域)。
j.前端控制器向用户响应结果
16.1Spring Boot、Spring MVC 和 Spring 有什么区别
springframework 最重要的特征是依赖注入,所有的springModules不是依赖注入就是IOC控制反转。当我们恰当的使用DI或者是IOC的时候,我们开发松藕合应用。
springmvc提供一种分离式的方法来开发web应用。通过运用像DispatcherServelet,ModuleAndView 和ViewResolver等一些简单概念,开发web应用将会变的非常简单。
springboot
spring和springmvc的问题在于配置大量的参数
springboot通过一个自动配置和启动的项来解决这个问题,可以更快的构建产品
16.2什么是自动配置?
spring和springmvc的问题在于配置大量的参数
spring查看(CLASSPATH上可用的框架)已存在的应用程序的配置。在此基础上,Spring Boot提供了配置应用程序和框架所需要的基本配置。这就是自动配置
16.3 什么是spingbootstarter?
启动器是一套方便的依赖描述符,他可以放在自己的程序中。你可以一站式的获取你所需要的spring和相关技术。不需要依赖描述符的通过示例代码搜索和复制黏贴的负载。
例如,如果你想使用 Sping 和 JPA 访问数据库,只需要你的项目包含 spring-boot-starter-data-jpa 依赖项,你就可以完美进行。
16.4 能否举个例子来解释更多starter的内容?
如果你想开发一个web应用程序或者公开REST服务的应用程序。Spring-Boot Starter-Web 是首选。让我们使用Spring Initializr 创建一个Spring Boot Start Web的快速项目。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
依赖可以被分为:
Spring-core,beans,context,aop
webmvc-(Springmvc)
Jackson -for JSON Binding
Validation -Hibernate,Validation API
Enbedded Servlet Container -Tomcat
Logging -logback,slf4j
任何金典的web应用程序都会使用所有的这些依赖项。Spring Boot Starter Web 预先打包了这些依赖项。
作为一个开发者,我不需要再担心这些依赖项和它们的兼容版本。
16.5 Springboot还提供了其它的哪些 Starter Project Options?
Spring Boot 也提供了其它的启动器项目包括,包括用于开发特定类型应用程序的典型依赖项。
spring-boot -starter-web-services -SOAP web Services
spring-boot-starter-web -Web 和 RESTful 应用程序
spring-boot-starter-test --单元测试和集成测试
spring-boot-starter-jdbc- 传统JDBC
spring-boot-starter-hateoas -为服务添加HATEOAS功能
spring-boot-starter-security --使用SpringSecurity进行身份验证和授权
spring-boot-starter-data-jpa --带有hibernate的SpringData JPA
spring-boot-starter-data-rest- 使用springdatarest公布简单的rest服务
16.6Spring是如何快速创建产品就绪应用程序的?
Spring Boot致力于快速产品就绪应用程序。为此,它提供了一些譬如
高速缓存,日志记录,监控和嵌入式服务器等开箱即用的非功能性特征。
spring-boot-starter-actuator -使用一些如监控和跟踪应用的高级功能
spring-boot-starter -undertow,spring-boot-starter-jetty,spring-boot-startter-tomcat-选择您的特定嵌入式Servlet容器
spring-boot-starter-logging -使用logback进行日志记录
spring-boot-starter-cache- 启用Spring Framework 的缓存支持
###Spring2和Spring5所需要的最低Java版本是什么?
Spring Boot2.0需要java8或者更新的版本。java6 和java7 已经不再支持。
16.7 什么是spring profiles?
Spring Profiles 允许用户根据配置文件(dev,test,prod等)来注册bean.因此,当应用程序在开发运行时,只有某些bean可以加载,而在PRODUCTION中,某些其他 bean 可以加载。假设我们的要求是 Swagger 文档仅适用于 QA 环境,并且禁用所有其他文档。这可以使用配置文件来完成。Spring Boot 使得使用配置文件非常简单。
16.8 什么是FreeMarker模板?
FreeMarker 是一个基于 Java 的模板引擎,最初专注于使用 MVC 软件架构进行动态网页生成。使用 Freemarker 的主要优点是表示层和业务层的完全分离。程序员可以处理应用程序代码,而设计人员可以处理 html 页面设计。最后使用freemarker 可以将这些结合起来,给出最终的输出页面。
16.9 什么是spring batch?
Spring Boot Batch 提供可重用的函数,这些函数在处理大量记录时非常重要,包括日志/跟踪,事务管理,作业处理统计信息,作业重新启动,跳过和资源管理。它还提供了更先进的技术服务和功能,通过优化和分区技术,可以实现极高批量和高性能批处理作业。简单以及复杂的大批量批处理作业可以高度可扩展的方式利用框架处理重要大量的信息。
16.10您使用了哪些start maven 依赖项?
使用了下面的一些依赖项
spring-boot-starter-activemq
spring-boot-starter-security
这有助于增加更少的依赖关系,并减少版本的冲突。
Springboot学习笔记
1工具结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y7svY4GE-1681441105914)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20220907100044756.png)]
典型结构下的初始化(推荐使用)
由于应用主类在root package
中,所以按照上面的规则定义的所有其他类都处于root package
下的其他子包之后。默认情况下,Spring Boot的应用主类会自动扫描root package
以及所有子包下的所有类来进行初始化。
非典型结构下的初始化 (不建议使用)
方法一:使用@ComponentScan
注解指定具体的加载包,比如:
@SpringBootApplication
@ComponentScan(basePackages="com.example")
public class Bootstrap {
public static void main(String[] args) {
SpringApplication.run(Bootstrap.class, args);
}
}
方法二:使用@Bean
注解来初始化,比如:
@SpringBootApplication
public class Bootstrap {
public static void main(String[] args) {
SpringApplication.run(Bootstrap.class, args);
}
@Bean
public CustomerController customerController() {
return new CustomerController();
}
}
2配置文件
配置文件中的值可以通过${}获取
案例:
jasypt.encryptor.password=didispace
datasource.password=ENC(ecnMqfJE1qs5BSekArG4otyEIAFpKXTYj133y01ZB0qn1NfCPiQXtkB+5AnLhgz1)
加密:
mvn jasypt:encrypt -Djasypt.encryptor.password=didispace
解密:
mvn jasypt:decrypt -Djasypt.encryptor.password=didispace
3APP开发
3.1构建Restful API与单元测试
@Controller:修饰class,用来创建处理http请求的对象
@RestController:Spring4之后加入的注解,原来在@Controller中返回json需要@ResponseBody来配合,如果直接用@RestController替代@Controller就不需要再配置@ResponseBody,默认返回json格式
@RequestMapping:配置url映射。现在更多的也会直接用以Http Method直接关联的映射注解来定义,比如:GetMapping、PostMapping、DeleteMapping、PutMapping等
a17 MQ篇
17.1消息中间件概述
消息队列已经逐渐成为企业IT系统内部通信的核心手段。它具有低耦合、可靠投递、广播、流量控制、最终一致性等一系列功能,成为异步RPC的主要手段之一。当今市面上有很多主流的消息中间件,如老牌的ActiveMQ、RabbitMQ,炙手可热的Kafka,阿里巴巴自主开发RocketMQ等。
17.2消息中间件的组成
1)Broker
消息服务器,作为server提供消息核心服务
2)Producer
消息生产者,业务的发起方,负责生产消息传输给borker
3)Consumer
消息消费者,业务的处理方,负责从broker获取消息并进行业务逻辑处理
4)Topic
主题,发布订阅模式下的消息统一汇集地,不同生产者向topic发送消息 ,
由MQ服务订阅者,实现消息的广播。
5)Queue
队列,PTP模式下,特定生产者向特定queue发送消息,
消费者订阅特定的queue完成指定消息的接收
6)Message
消息体,根据不同通信协议定义的固定格式进行编码的数据包,来封装业务数据
17.3消息中间件模式分类
1)点对点
PTP点对点:使用queue作为通信载体
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O0QaqAo9-1681441109349)(null)]
说明:
消息生产者生产消息发送到queue中,然后消息消费者从queue中取出并且消费消息。
消息被消费以后,queue中不再存储,所以消息消费者不可能消费到已经被消费的消息。 Queue支持存在多个消费者,但是对一个消息而言,只会有一个消费者可以消费。
2)发布/订阅
pub/sub 发布订阅(广播):使用topic作为通信载体
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VSrfraZy-1681441107838)(null)]
说明:
消息生产者(发布)将消息发布到topic中,同时有多个消息消费者(订阅)消费该消息。和点对点方式不同,发布到topic的消息会被所有订阅者消费。
queue实现了负载均衡,将producer生产的消息发送到消息队列中,由多个消费者消费。但一个消息只能被一个消费者接受,当没有消费者可用时,这个消息会被保存直到有一个可用的消费者。
topic实现了发布和订阅,当你发布一个消息,所有订阅这个topic的服务都能得到这个消息,所以从1到N个订阅者都能得到一个消息的拷贝。
17.4消息中间件的应用场景
异步,消峰,解耦
数据流处理
缓冲
顺序保证
17.5消息中间件常用协议:
1)AMQP协议
2)MQTT协议(消息中间件的协议)
MQTT(message queuing telemetry transport)是IBM开发的即时通讯协议,是一种发布/订阅极其轻量级的消息传输协议,专门为网络受限设备、低宽带以及高延迟和不可靠的网络而设计的。由于以上轻量级的特点,是实现智能家居的首选传输协议,相比于XMPP,更加轻量级而且占用宽带低。
特点
a.由于采用发布/订阅的消息模式,可以提供一对多的消息发布
b.轻量级,网络开销小
c.对负载内容会有屏蔽的消息传输
d.有三种消息发布质量(Qos):
qos=0:“至多一次”,这一级别会发生消息丢失或重复,消息发布依赖于TCP/IP网络
qos=1:“至少一次”,确保消息到达,但消息重复可能会发生
qos=2:“只有一次”,确保消息到达一次
e.通知机制,异常中断时会通知双方
MQTT 启动说明:进入bin目录用cmd方式启动
启动命令emqx start,
关闭 emqx stop, 注意是 bin目录下。
管理网页http://192.168.128.8:18083/#/topics
账户 admin/public
3)STOMP协议
4)XMPP协议
5)其他基于TCP/IP自定义的协议
17.6常用的消息中间件
rocketmq ,rabbitmq,activemq,redis,kafka,zeromq
a18接口和抽象类的区别
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B5nq1uhx-1681441105917)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20220110113116269.png)]
17.7
a19JAVA中几种常用的RPC框架介绍
从语言兼容上的rpc框架有
thrift facebook
protbuf --google
从服务治理角度的rpc架构有 dubbo RMI、Hessian spring Cloud
所谓服务治理,主要包括服务发现、负载均衡、容错、日志收集等功能
a20分布式/集群部署的时候session的解决方案?
1 tomcat + redis 的方案
分布式部署两台机器的时候用户请求(机器1)数据到系统 返回的session数据会放在session中和redis中,
用户在请求(机器2)数据到系统,tomcat从redis中读取session数据 放在机器2上的session中。返回。
2 spring session + redis
通过spring session 从redis中读取数据
a21简述你对RPC、RMI的理解
RPC:在本地调用远程的函数,远程过程调用,可以跨语言实现httpclient
RMI:远程方法调用,java中用于实现RPC的一种机制,RPC的java版本,是j2ee的网络调用机制,跨JVM调用对象的方法,面向对象的思维方式
直接或间接实现接口 java.rmi.remote成为存在于服务器端的远程对象,供客户端访问并提供一定的服务远程对象必须实现java.rmi.server,unicastremoteobject类。
a21分布式id生产方案
1)UUID
2)数据库自增序列
3)leaf-segment 美团
4)基于redis,mongodb ,zk等中间件生产
5)雪花算法
a22分布式锁的解决方案
1数据库
利用主键冲突控制一次只有一个线程能获取锁,非阻塞,不可重入,单点,失效时间
2zookeeper分布式锁:
zK通过临时节点,解决了死锁问题,一旦客户端获取到锁之后突然挂掉(session连接会断开),那么这个时候临时节点就会被自动删除,其他客户端自动获取锁,临时节点解决惊群效应
redis分布式锁
setnx
问题:1.
2.后期版本提供加锁与设置时间原子操作,但是存在任务超时,锁自动释放,导致并发问题,加锁和释放锁不是同一线程问题。
key:定期清除,读取的时候清除 get ,set方法设置时间 lua来指定分布式锁时间
可重入性以及锁续期没有实现,通过redisson解决(类似AQS的实现,看门狗监听机制)
a23分布式事务的解决方案
1.消息队列的事务消息:
a)发送prepare消息到消息中间件
b)发送成功后,执行本地事务
如果事务执行成功,则commit,消息中间件将消息发至消费端(commit前,消息不会被消费)
如果事务执行失败,则回滚,消息中间件将这调prepare消息删除
c)消息端接收到消息进行消费,如果消费失败,则不断重试。
2.TCC(补偿事务):try,confirm,cancel (主要通过业代码来处理,需要解决3个接口之间的幂等性问题)
3.XA规范: 3阶段协议
a24如果实现接口幂等性
1.唯一id,每次操作,都根据
2.服务端提供发送token的接口,业务调用接口前先获取token,然后在调用业务接口请求时,把token携带过去,服务器判断token是否存在redis中,存在表示是第一次请求,可以继续执行业务代码,执行完成后,最好需要把redis中的token删除
3。建去重表,将业务中有唯一标识的字段保存到去重表,如果表中存在,则表示已经处理过了
4.版本控制,增加版本号,当版本符合时,才能更新数据。
5.状态控制。
a25css布局
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BTUYw24n-1681441105918)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20220413115057590.png)]
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
<style>
.row:after {
content: "";
display: table;
clear: both;//列后清除浮动
}
.top{
outline:black dotted thick;
}
.leftdiv{
float: left;
width: 20%;
margin-top:20px;
outline:YELLOW dotted thick;
}
.cnterdiv{
float: left;
width: 50%;
margin-top:20px;
outline:BLUE dotted thick;
}
.rightdiv{
float: left;
width: 30%;
margin-top:20px;
outline:red dotted thick;
}
.buttomdiv{
margin-top:20px;
outline:GREY dotted thick;
}
.row{
outline:green dotted thick;
}
body {
font-family: Arial;
padding: 10px;
background: #f1f1f1;
}
</style>
</head>
<body>
<div class="top">
<h1>顶部<h1>
<form>
First name: <input type="text" name="firstname"><br>
Last name: <input type="text" name="lastname">
<input type="radio" name="sex" value="male">Male<br>
<input type="radio" name="sex" value="female">Female
</form>
</div>
<div class="row">
<div class="leftdiv">左边
<h1>左边<h1>
</div>
<div class="cnterdiv" >中间
<h1>中间<h1>
</div>
<div class="rightdiv" >
右边
<h1>右边<h1>
</div>
</div>
<div class="buttomdiv">底部</div>
</body>
</html>
display:
float:浮动布局;
1div1,div2,div3;初始都是挤在一起的,
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x6TY9I5d-1681441105918)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20220413121946724.png)]
2然后通过margin-top:20px 来实现上下布局 ;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pZCGIvB7-1681441105919)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20220413122055938.png)]
3div2中在增加divleft,divcenter,divright
4首先指定宽度:20% 50% 30%,这样三个div会没有内容就会重叠在一起,有内容
会上下排列。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-adcu2a1Y-1681441105920)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20220413122653481.png)]
5在使用float: left;就会平铺开; 此时底部div3 会和 中间div2重叠在一起。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ehxY6o7g-1681441105920)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20220413123021068.png)]
6在对div2:after { content: “”;
display:table;
clear: both;//列后清除浮动} 清除后续浮动效果,实现div3在div2下方
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MMts85WT-1681441105921)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20220413123432595.png)]
7增加响应布局
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oggV8ecV-1681441105921)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20220413124044874.png)]
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
<style>
.div1{
outline:YELLOW dotted thick;
margin-top:20px;
}
.div2{
outline:green dotted thick;
margin-top:20px;
}
.div2:after{
content: "";
display:table;
clear: both;//列后清除浮动
}
.div3{
outline:blue dotted thick;
margin-top:20px;
}
.dleft{
outline:red dotted thick;
width:20%;
float:left;
}
.dcenter{
outline:black dotted thick;
width:50%;
float:left;
}
.dright{
outline:red dotted thick;
width:30%;
float:left;
}
/* 响应式布局 -屏幕尺寸小于 400px 时,导航等布局改为上下布局 */
@media screen and (max-width: 400px) {
.dleft{
float: none;
width: 100%;
}
.dcenter{
float: none;
width: 100%;
}
.dright{
float: none;
width: 100%;
}
}
</style>
</head>
<body>
<div class="div1">顶部</div>
<div class="div2">
<div class="dleft">左边</div>
<div class="dcenter">中间</div>
<div class="dright">右边</div>
</div>
<div class="div3">底部</div>
</body>
</html>
a26css选择器
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P0S8N0Lj-1681441105922)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20220413131909860.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tXZT5PbX-1681441105922)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20220413130939036.png)]
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
<style>
a:link {color:green;}
a:visited {color:green;}
a:hover {color:red;}
a:active {color:yellow;}
</style>
</head>
<body>
<p>将鼠标移上并点击此链接: <a href="http://www.runoob.com/">runoob.com</a></p>
</body>
</html>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fAUk8zw9-1681441105923)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20220413130543080.png)]
选中高亮:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bvxpTgTn-1681441105923)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20220413131054332.png)]
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<style type="text/css">
::selection
{
color:#ff0000;
}
::-moz-selection
{
color:#ff0000;
}
</style>
</head>
<body>
<h1>尝试选择本页的一些文本</h1>
<p>这是一些文本.</p>
<div>这是div元素中的一些文本.</div>
<a href="http://www.w3cschool.cc/" target="_blank">链接W3Cschool!</a>
</body>
</html>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C551H1PZ-1681441105924)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20220416165137826.png)]
position :absolute,fixed,relative,static(无定位)
diplay:none,inline,block,inline-block,table-cell,flex(弹性盒)
float: left,right,clear
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Oll1B43N-1681441105924)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20220416165617139.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0DltcwaP-1681441105925)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20220416165937631.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K1o6dCBi-1681441105926)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20220416170004277.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8s488fMG-1681441105926)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20220416165205030.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KI5EsW1L-1681441105926)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20220416165252107.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eMb3xGI5-1681441105927)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20220416165332962.png)]
a26.1 表格列自动换行
.jsgrid-cell { white-space: normal !important; height:auto; } /**jsgrid表格内容自动换行 */
a27json 系列
1.console.log(“----”+JSON.stringify(data))
a29 系统编码
Windows的默认编码为GBK,Linux的默认编码为UTF-8。在Windows下编辑的中文,在Linux下显示为乱码。为了解决此问题,修改Linux的默认编码为GBK。方法如下:
方法1:
vi /etc/sysconfig/i18n
默认为:
LANG=“en_US.UTF-8”
SYSFONT=“latarcyrheb-sun16”
修改为:
LANG=“zh_CN.GBK”
SUPPORTED=“zh_CN.UTF-8:zh_CN:zh”
SYSFONT=“latarcyrheb-sun16”
方法2:
vi /etc/profile
export LC_ALL=“zh_CN.GBK”
export LANG=“zh_CN.GBK”
//获取系统默认编码
System.out.println("系统默认编码:" + System.getProperty("file.encoding")); //查询结果GBK
//系统默认字符编码
System.out.println("系统默认字符编码:" + Charset.defaultCharset()); //查询结果GBK
//操作系统用户使用的语言
System.out.println("系统默认语言:" + System.getProperty("user.language")); //查询结果zh
a30 三种分页
1 序号
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-asWD2jbe-1681441105928)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20220603214857023.png)]
<%--
Created by IntelliJ IDEA.
User: admin
Date: 2022/6/2
Time: 15:52
To change this template use File | Settings | File Templates.
--%>
<%@page import="java.sql.*"%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<table border="1">
<tr>
<th>编号</th>
<th>用户姓名</th>
<th>用户编号</th>
<th>角色</th>
<th>是否启用</th>
</tr>
<%
String curpage=request.getParameter("pageNow");
//分页
int pagesize=5;
int lineCount;//一共多少行
int pageCount=0;//一共多少页
int pageNow=1;//当前第几页
if(!"".equals(curpage)&& null!=curpage){
pageNow=Integer.parseInt(curpage);
}
String username="";
try {
Class.forName("com.mysql.cj.jdbc.Driver");
String url="jdbc:mysql://localhost:3306/swt3_sanxia?useUnicode=true&serverTimezone=UTC&characterEncoding=UTF8&useOldAliasMetadataBehavior=true&&zeroDateTimeBehavior=convertToNull";
Connection conn=DriverManager.getConnection(url,"root","123123");
String sql1="select count(1) from sysusertb ";
PreparedStatement ps1=conn.prepareStatement(sql1);
ResultSet rs1=ps1.executeQuery();
rs1.next();
lineCount=rs1.getInt(1);
pageCount=lineCount%pagesize==0?lineCount/pagesize : lineCount/pagesize+1;
String sql="select * from sysusertb limit ?,?";
PreparedStatement ps=conn.prepareStatement(sql);
ps.setInt(1,pagesize*(pageNow-1));
ps.setInt(2,pagesize);
ResultSet rs=ps.executeQuery();
String username1="";
int i=0;
while(rs.next()){
username=(String)rs.getString("username");
System.out.println(rs.getString("username"));
i=i+1;
%>
<tr>
<td><%=i%></td>
<td><%=rs.getString("usercode")%></td>
<td><%=rs.getString("username")%></td>
<td><%=rs.getString("rolecode")%></td>
<td><%=rs.getString("userstat")%></td>
</tr>
<%
}
ps.close();
conn.close();
} catch (Exception e) {
out.print("图书信息添加失败!");
e.printStackTrace();
}
%>
</table>
<div>
<%
for (int i=1;i<=pageCount;i++){
%>
<a href="/test1.jsp?pageNow=<%=i%>">[<%=i%>]</a>
<%
}
%>
</div>
<div>
</div>
</body>
</html>
2 首页,末页,上一页,下一页
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8TfcftBs-1681441105929)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20220603214944403.png)]
<%--
Created by IntelliJ IDEA.
User: admin
Date: 2022/6/2
Time: 15:52
To change this template use File | Settings | File Templates.
--%>
<%@page import="java.sql.*"%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<table border="1">
<tr>
<th>编号</th>
<th>用户姓名</th>
<th>用户编号</th>
<th>角色</th>
<th>是否启用</th>
</tr>
<%
String curpage=request.getParameter("pageNow");
//分页
int pagesize=5;
int lineCount;//一共多少行
int pageCount=0;//一共多少页
int pageNow=1;//当前第几页
if(!"".equals(curpage)&& null!=curpage){
pageNow=Integer.parseInt(curpage);
}
String username="";
try {
Class.forName("com.mysql.cj.jdbc.Driver");
String url="jdbc:mysql://localhost:3306/swt3_sanxia?useUnicode=true&serverTimezone=UTC&characterEncoding=UTF8&useOldAliasMetadataBehavior=true&&zeroDateTimeBehavior=convertToNull";
Connection conn=DriverManager.getConnection(url,"root","123123");
String sql1="select count(1) from sysusertb ";
PreparedStatement ps1=conn.prepareStatement(sql1);
ResultSet rs1=ps1.executeQuery();
rs1.next();
lineCount=rs1.getInt(1);
pageCount=lineCount%pagesize==0?lineCount/pagesize : lineCount/pagesize+1;
if(pageNow<=0){
pageNow=1;
}
if(pageNow>=pageCount){
pageNow=pageCount;
}
String sql="select * from sysusertb limit ?,?";
PreparedStatement ps=conn.prepareStatement(sql);
ps.setInt(1,pagesize*(pageNow-1));
ps.setInt(2,pagesize);
ResultSet rs=ps.executeQuery();
String username1="";
int i=0;
while(rs.next()){
username=(String)rs.getString("username");
System.out.println(rs.getString("username"));
i=i+1;
%>
<tr>
<td><%=i%></td>
<td><%=rs.getString("usercode")%></td>
<td><%=rs.getString("username")%></td>
<td><%=rs.getString("rolecode")%></td>
<td><%=rs.getString("userstat")%></td>
</tr>
<%
}
ps.close();
conn.close();
} catch (Exception e) {
out.print("图书信息添加失败!");
e.printStackTrace();
}
%>
</table>
<div>
<%
%>
<a href="/test2.jsp?pageNow=1">首页</a>
<a href="/test2.jsp?pageNow=<%=pageNow-1%>">上一页</a>
<a href="/test2.jsp?pageNow=<%=pageNow+1%>">下一页</a>
<a href="/test2.jsp?pageNow=<%=pageCount%>">末页</a>
<br>一共分了<%=pageCount%>页,当前在<%=pageNow%>页
<%
%>
</div>
<div>
</div>
</body>
</html>
3下拉选择
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U9d3xOct-1681441105929)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20220603214735225.png)]
<%--
Created by IntelliJ IDEA.
User: admin
Date: 2022/6/2
Time: 15:52
To change this template use File | Settings | File Templates.
--%>
<%@page import="java.sql.*"%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<table border="1">
<tr>
<th>编号</th>
<th>用户姓名</th>
<th>用户编号</th>
<th>角色</th>
<th>是否启用</th>
</tr>
<%
String curpage=request.getParameter("pageNow");
//分页
int pagesize=5;
int lineCount;//一共多少行
int pageCount=0;//一共多少页
int pageNow=1;//当前第几页
if(!"".equals(curpage)&& null!=curpage){
pageNow=Integer.parseInt(curpage);
}
String username="";
try {
Class.forName("com.mysql.cj.jdbc.Driver");
String url="jdbc:mysql://localhost:3306/swt3_sanxia?useUnicode=true&serverTimezone=UTC&characterEncoding=UTF8&useOldAliasMetadataBehavior=true&&zeroDateTimeBehavior=convertToNull";
Connection conn=DriverManager.getConnection(url,"root","123123");
String sql1="select count(1) from sysusertb ";
PreparedStatement ps1=conn.prepareStatement(sql1);
ResultSet rs1=ps1.executeQuery();
rs1.next();
lineCount=rs1.getInt(1);
pageCount=lineCount%pagesize==0?lineCount/pagesize : lineCount/pagesize+1;
if(pageNow<=0){
pageNow=1;
}
if(pageNow>=pageCount){
pageNow=pageCount;
}
String sql="select * from sysusertb limit ?,?";
PreparedStatement ps=conn.prepareStatement(sql);
ps.setInt(1,pagesize*(pageNow-1));
ps.setInt(2,pagesize);
ResultSet rs=ps.executeQuery();
String username1="";
int i=0;
while(rs.next()){
username=(String)rs.getString("username");
System.out.println(rs.getString("username"));
i=i+1;
%>
<tr>
<td><%=i%></td>
<td><%=rs.getString("usercode")%></td>
<td><%=rs.getString("username")%></td>
<td><%=rs.getString("rolecode")%></td>
<td><%=rs.getString("userstat")%></td>
</tr>
<%
}
ps.close();
conn.close();
} catch (Exception e) {
out.print("图书信息添加失败!");
e.printStackTrace();
}
%>
</table>
<div>
<select οnchange="location.href='/test3.jsp?pageNow='+this.value">
<%
for (int i=1;i<=pageCount;i++){
%>
<%
if (pageNow==i) {
%>
<option value="<%=i%>" selected><%=i%></option>
<%
}else{
%>
<option value="<%=i%>" ><%=i%></option>
<%
}
}
%>
</select>
<br>一共分了<%=pageCount%>页,当前在<%=pageNow%>页
</div>
<div>
</div>
</body>
</html>
请求转发
<%--
Created by IntelliJ IDEA.
User: admin
Date: 2022/6/2
Time: 15:52
To change this template use File | Settings | File Templates.
--%>
<%@page import="java.sql.*"%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<table border="1">
<tr>
<th>编号</th>
<th>用户姓名</th>
<th>用户编号</th>
<th>角色</th>
<th>是否启用</th>
</tr>
<%
String curpage=request.getParameter("pageNow");
//分页
int pagesize=5;
int lineCount;//一共多少行
int pageCount=0;//一共多少页
int pageNow=1;//当前第几页
if(!"".equals(curpage)&& null!=curpage){
pageNow=Integer.parseInt(curpage);
}
String username="";
try {
Class.forName("com.mysql.cj.jdbc.Driver");
String url="jdbc:mysql://localhost:3306/swt3_sanxia?useUnicode=true&serverTimezone=UTC&characterEncoding=UTF8&useOldAliasMetadataBehavior=true&&zeroDateTimeBehavior=convertToNull";
Connection conn=DriverManager.getConnection(url,"root","123123");
String sql1="select count(1) from sysusertb ";
PreparedStatement ps1=conn.prepareStatement(sql1);
ResultSet rs1=ps1.executeQuery();
rs1.next();
lineCount=rs1.getInt(1);
pageCount=lineCount%pagesize==0?lineCount/pagesize : lineCount/pagesize+1;
if(pageNow<=0){
pageNow=1;
}
if(pageNow>=pageCount){
pageNow=pageCount;
}
String sql="select * from sysusertb limit ?,?";
PreparedStatement ps=conn.prepareStatement(sql);
ps.setInt(1,pagesize*(pageNow-1));
ps.setInt(2,pagesize);
ResultSet rs=ps.executeQuery();
String username1="";
int i=0;
while(rs.next()){
username=(String)rs.getString("username");
System.out.println(rs.getString("username"));
i=i+1;
%>
<tr>
<td><%=i%></td>
<td><%=rs.getString("usercode")%></td>
<td><%=rs.getString("username")%></td>
<td><%=rs.getString("rolecode")%></td>
<td><%=rs.getString("userstat")%></td>
</tr>
<%
}
ps.close();
conn.close();
} catch (Exception e) {
out.print("图书信息添加失败!");
e.printStackTrace();
}
%>
</table>
<div>
<select onchange="location.href='/myfirst?' +
'pageNow='+this.value">
<%
for (int i=1;i<=pageCount;i++){
%>
<%
if (pageNow==i) {
%>
<option value="<%=i%>" selected><%=i%></option>
<%
}else{
%>
<option value="<%=i%>" ><%=i%></option>
<%
}
}
%>
</select>
<br>一共分了<%=pageCount%>页,当前在<%=pageNow%>页
</div>
<div>
</div>
</body>
</html>
package com.test;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.*;
public class MyFirstServlet extends HttpServlet{
protected void doPost(HttpServletRequest request,HttpServletResponse response) throws IOException, ServletException {
System.out.println("这是doPost方法");
//PrintWriter out = response.getWriter();
// out.println("<strong>Hello Servlet!</strong><br/>");
System.out.println("username=1="+request.getParameter("username"));
HttpSession session = request.getSession(true);
session.setAttribute("username",request.getParameter("username"));
System.out.println("username=2="+session.getAttribute("username"));
String addr= request.getRemoteAddr();
System.out.println("addr=2="+addr);
String host= request.getRemoteHost();
System.out.println("host=2="+host);
int ports=request.getRemotePort();
System.out.println("ports=2="+ports);
String user= request.getRemoteUser();
System.out.println("user=2="+user);
// String path1="/index.jsp";
String path1="/test2.jsp";
/**
* (1)重定向
* 两次请求,两次响应
* 重定向不携带数据
* 重定向地址栏发生改变
* (2)转发
* 一次请求,一次响应
* 转发需要携带数据,请求域中数据不会丢失
* 转发地址栏不会发生变化
*/
//重定向
request.getRequestDispatcher(path1).forward(request, response);
// response.sendRedirect(path1);
}
protected void doGet(HttpServletRequest request,HttpServletResponse response) throws IOException, ServletException {
System.out.println("这是doGet方法");
//指定request请求时的字符编码格式
request.setCharacterEncoding("UTF-8");
//设置response响应的字符编码格式
response.setCharacterEncoding("UTF-8");
//设置响应内容类型为 text/html(文本/超文本标记语言);文本编码为UTF-8
response.setContentType("text/html'charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("<strong>Hello Servlet!</strong>");
String path1="/test4.jsp";
/**
* (1)重定向
* 两次请求,两次响应
* 重定向不携带数据
* 重定向地址栏发生改变
* (2)转发
* 一次请求,一次响应
* 转发需要携带数据,请求域中数据不会丢失
* 转发地址栏不会发生变化
*/
//重定向
HttpSession session = request.getSession(true);
session.setAttribute("username",request.getParameter("username"));
System.out.println("username=1="+request.getParameter("username"));
System.out.println("username1=1="+request.getParameter("username1"));
// response.sendRedirect(path1);
request.getRequestDispatcher(path1).forward(request, response);
}
}
4总结:
请求路径:
jsp跳转到/*.jsp不用到后台servlet
jsp跳转到/myfirst 会找到web.xml中 sevlet-class
跳转到MyFirstServlet类中,经过逻辑处理后在转发到前台页面,这里只能用转发
因为请求转发,请求地址不变,始终是同一个请求,request.respose都是共享的
所有参数可以传递。
<servlet>
<servlet-name>first</servlet-name>
<servlet-class> com.test.MyFirstServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>first</servlet-name>
<url-pattern>/myfirst</url-pattern>
</servlet-mapping>
5请求转发和重定向的区别
1请求转发地址不变,request,response共享,可以获取
2重定向,会重新发送到新的请求地址,之前的请求路径的request,response不能共享,由于不是同一个请求。是客户端重新发送请求。
3请求顺序 ,请求转发 客户端login.jsp–》访问服务端-服务端访问客户端–》访问index.jsp==》服务端—》服务端-login.jsp (全程是同一个请求)
重定向,客户端
1.login.jsp–》访问服务端—》login.jsp
2.login.jsp --》访问index.jsp (全程是2个请求)
a31.hbase
2.2.1基本操作
1)进入HBase客户端命令行
启动:start-hbase.sh
进入:bin/hbase shell
2)查看帮助命令 help
能够展示HBase中所有能使用的命令,
主要使用的命令有namespace命名空间相关,
DDL创建修改表格,DML读入读取数据
2.2.2namespace
1)创建命名空间
create_namespace ‘qhxb’
create_namespace ‘qhxb’,{‘property_name’=>‘property_value’}
2)查看命名空间
list_namespace
2.23DDL
1)创建表
create ‘student’ ,‘info’,‘msg’
create ‘bigdata:person’,{NAME=>‘f1’,VERSIONS=>5}
2)查看表
describe ‘student’
describe ‘bigdata:student’
3)修改表:
(1)增加列族和修改信息都使用覆盖方法
alter ‘student’,{NAME =>‘f1’,VERSIONS =>3}
(2)删除信息使用特殊的语法
alter ‘student1’,NAME =>‘f1’,METHOD =>‘delete’
alter ‘student1’,‘delete’ =>‘f1’
4)删除表:
shell中删除表,需要先将表格状态设置为不可用。
disable ‘student1’
drop ‘student1’
5)写数据
put ‘命名空间:表名’,‘行号’,‘列名:NAME’,‘值’
put ‘bigdata:student’,‘1001’,‘info:name’,‘zhangsan’
如果同时put 相同行号的数据,是覆盖作用。
put ‘bigdata:student’,‘1001’,‘info:age’,‘zhangsan’
2.2.2DML
2)读取数据
读取数据的方法有两个:get和scan
get最大范围是一行数据,也可以进行列的过滤,
读取数据的结果为多行cell
get 'bigdata:student','1001'
get 'bigdata:student','1001',{column=>'info:name',versions =>6}
scan 是扫描数据,能读取多行
scan 'bigdata:student'
scan 'bigdata:student',{STARTROW =>'1001',STOPROW='1002'}
2)删除 delete deleteall
delete ‘bigdata:student’,‘1001’,‘info:name’
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Jgx9BDHU-1681441105930)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20220727155313447.png)]
a32 k8s和docker
markdow工作流
a32.ES6
ES5中的for循环,正常遍历中 i 指的是数组的下标
ES6中,for…in循环,遍历中的 i 指的是数组的下标
ES6中,for…of循环,遍历中的 i 指的是数组中的值
let len=[3,3,5]
for(let j in len){
console.log(j);// 0,1,2
}
for(let k of len){
console.log(k)//3,3,5
}
a32.VUE
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aZIrd8fC-1681441105931)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20221031155407117.png)]
查看npm镜像文件
npm get registry
npm get registry
切换npm镜像为淘宝
npm config set registry http://registry.npm.taobao.org
安装vue
npm i -g @vue/cli
创建项目:
vue create demo
启动项目:
npm run serve
computed:多个值的改变,为了得到一个结果,使用计算属性。
watch:一个值的改变,会影响多个值(或处理多件事),使用侦听器。
<template>
<div id="app">
<p>{{name}}</p>
<p>{{name}}</p>
<p>{{name}}</p>
<HelloWorld msg="Welcome to Your Vue.js App"/>
<MyHello></MyHello>
<h1>{{h1Data}}</h1>
<my-cart></my-cart>
<my-brother></my-brother>
<my-sister></my-sister>
单价:{{price}}
数量:
<button @click="sub">-</button>
{{count}}
<button @click="add">+</button>
,折扣:{{discount}}
<p>总价:{{totalPrice}}</p>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
import MyHello from './components/MyHello.vue'
import MyCart from './components/MyCart.vue'
import MyBrother from './components/MyBrother.vue'
import MySister from './components/MySister.vue'
export default {
name: 'App',
components: {
HelloWorld,
MyHello,
MyCart,
MyBrother,
MySister
},
data(){
return{
message:"app.vue data",
h1Data: "before",
firstName:"张",
laseName:"三",
price:20,
count:0,
discount:0.75,
}
},
methods:{
changeData(data){
this.h1Data=data;
},
sub(){
this.count--;
},
add(){
this.count++;
}
},
computed:{
name(){
return this.firstName+this.laseName
},
totalPrice(){
return this.price*this.count*this.discount;
}
},
watch:{
count(p){
console.log(p);
}
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
每个Vue实例在被创建时,都要经过一系列的初始化过程。
created():组件初始化完成。
mounted():模板已创建。
表单:
双向绑定:v-model=“user.sex”
1、http协议:前端(浏览器)发送请求,服务器给予相应。
2、请求方法:get(查询)、post(添加)、put(修改)、delete(删除)
3、ajax:不刷新页面与后台交互数据
4、axios:封装好的ajax模块
5、koa:基于node的web框架
//路由使用
1.安装路由
npm install vue-router --save
问题1:安装版本过高
Uncaught TypeError: Cannot read properties of undefined (reading ‘install’)
方式1:先卸载:
npm uninstall vue-router --legacy-peer-deps
在安装
npm install --save vue-router@3
方式2:修改package.json 中包,然后npm install 一下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-itDFKWCN-1681441105932)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20221109162231863.png)]
问题2:解决报错error Component name “index“ should always be multi-word vue/multi-word-component-names
解决方法是关闭语法检查,在vue.config.js中增加下面配置
lintOnSave:false
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
lintOnSave:false
})
问题3
在开发过程中遇到Mixed spaces and tabs no-mixed-spaces-and-tabs的报错,就像下面这样:
在package.json找到eslintConfig ,在其rules下加入"no-mixed-spaces-and-tabs":0
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Vv0RUU9J-1681441105932)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20221109163646080.png)]
2安装axios
1安装
npm install axios --save
2、在main.js中写入一下代码
import axios from 'axios'
Vue.prototype.axios = axios
3调用
this.axios({
url: '',//请求地址
method:'POST',//请求方法
responseType: 'json',//返回值类型
params: {
arg1: "arg1"//请求携带参数
}
}).then(res => {
console.log(res)//请求成功
}).catch(error => {
console.log(error);//请求失败
})
4使用拦截器—添加
在src创建util目录,在里面创建request.js文件
import axios from 'axios';
const service = axios.create({
baseURL: "http://127.0.0.1:8080/projectName",//请求地址前缀
timeout: 0
});
// 请求拦截器
service.interceptors.request.use(
config => {
//添加请求头部参数
config.headers['arg1'] = "arg1Value";
return config;
},
error => {
return Promise.reject(error);
}
);
// 响应拦截器
service.interceptors.response.use(
response => {
//拦截到成功的数据
return response.data;
},
error => {
//拦截到失败的数据
return Promise.reject(error);
}
);
export default service;
在src创建api目录,在里面创建user.js文件
import request from '@/utils/request'; //引入request.js
export function getUserInfo(data) {
return request({
url: 'userController/getUserInfo',
method: 'post',
data: data
});
}
4、Vue页面调用拦截器
<template>
<div>
<h1>{{userInfo}}</h1>
</div>
</template>
<script>
//引入api
import { getUserInfo } from './api/user.js';
export default {
date(){
return{
userInfo: {}
}
},
mounted(){
const par = {arg1: "arg1Value"};
//调用api
getUserInfo(par).then(re=>{
//请求成功 返回re
this.userInfo = re.data;
}).catch(err=>{
//请求失败
})
}
}
</script>