目录
Java基础
1.Java中内存管理及各区域内存储数据的生命周期?
2.JVM堆内存的分代管理以及垃圾回收流程?
3.面向对象三大特征及详细理解?
4.重载(overload)与重写(override)的区别?
5.接口和抽象类区别? ,
6.实例变量和静态变量的区别?
7.八大基本类型及字节数和位数?
8.switch case是否支持byte,short和long,是否支持String?
9.String中和Array中是否有length属性和length()方法?
10.==和equals的区别?
11.String str=new String("abc");创建了几个对象?
12.String,StringBuffer,StringBulider的区别?
13.怎么把ISO8859-1编码的字符串转换成GBK或者UTF-8的字符串?
14.Integer i1=127;Integer i2=127;i1==i2结果为true还是false?Integer i3=Integer.valueOf(127);Integer i4=Integer.valueOf(127); i3==i4结果为true还是false?
15.List和Set以及Map他们的实现类有哪些?
16.ArrayList和LinkedList的区别?
17.HashMap和HashTable的区别?
18.HashMap内部存储数据的原理?(PPT上有张原理图务必会画)《一 67》
19.创建线程有几种方式?有何区别?
20.线程运行中的五种状态? (新建 就绪 运行 阻塞 结束)
21.线程中synchronized的用法?
22.synchronized什么情况下是同步锁,什么情况下是互斥锁?
23.什么是死锁?怎么解决死锁?
24.Exception和RuntimeException区别?throw和throws的区别?
25.请说出五种以上常见运行时异常的名字以及产生的原因和解决方案?
26.final,finalize,finally的区别?
27.什么是反射,怎么通过反射获取类对象,并且实例化该类对象,怎么获取类对象中属性和方法并执行方法?
CSS/JS
28.表单控件有哪些?
29.三种弹出框分别是?
30.什么是盒子模型?盒子模型计算公式?
31.JQuery提供on()函数用法?
32.怎么获取select下来选选中的option的value值?
33.怎么获取checkbox选中的多个value值?
34.怎么获取radio单选框选中的value值?
35.CSS选择器有哪些?
36.JQuery选择器有哪些?
37.JQuery中val(),val("值"),html(),html("值"),text(),text("值")有什么区别?分别支持哪些类型标签?
38.JQuery中addClass("样式名");removeClass("样式名");hasClass("样式名");
39.mysql和oracle的端口号?
40.oracle和mysql中的聚合函数和空值函数有哪些?
41.oracle和mysql中各自的分页查询怎么写?
42.oracle和mysql中怎么做行列转换?
43.复制表:包含结构和数据以及只包含结构不包含数据分别怎么实现?
44.将一个表中的数据插入到另外一张表结构相同的表中怎么实现?
45.oracle中的rowid和rownum分别是什么?
46.数据库约束有哪些?
47.(1)TRUNCATE和DELETE以及DROP的区别?(面)
(2)WHERE过滤句子和having过滤子句的区别?(面)
48.删除表中重复数据保留一条怎么实现?
49.union和unionall的区别?
50.创建用户并授权?
51.真删除和假删除?真分页和假分页?
52.什么是事务?事务有哪4项特性?《三---6题》
53.事务隔离级别,脏读,幻读,不可重复读?
54.数据库中乐观锁和悲观锁?
55.JDBC的运行过程?
56.Statement和Preparedstatement的区别?《三---5题》
Servlet/JSP
57.什么是HTTP协议?包含哪些数据包,各数据包内又有什么?
58.有几种方式可以修改tomcat的端口号?
59.servlet生命周期?
60.JSP的运行过程?
61.JSP九大内置对象?其中哪4个是作用域对象?怎么从某个作用域中取值?《四--15 16 题》
63.转发和重定向的区别以及是哪个对象调用其哪个方法执行的?
64.get和post请求的区别?
65.Spring框架的核心模块(PPT上有一张图)?
66.SpringIOC和DI?
67.SpringMVC的五大核心组件及工作流程?《高萌面试》
68.SpringMyBatis整合需要做哪些相关配置?
69.单例模式,工厂模式?《四--23-24》
70.Ajax技术(js版和jquey版)?<四---46>
71.JSON技术?<四---48>
72.Spring框架的 组件扫描 注解有哪些?《四题----28》
73.RequestMapping和ResponsBody注解分别是做什么用的?
74.什么是AOP?通知方式有几种?切入点有哪些?
222》什么是OOP?
75.拦截器和过滤器的区别?
76.MyBatis中#{}和${}的区别?
77.spring cloud 介绍?(了解就可以了,小白面试一般不会问)
项目
77.项目某模块思路
提高题:
78.Nginx是什么技术?(面试题五--4)
79.Redis是什么技术?(面试题五--5)
关于Shiro技术?
Shiro框架介绍
什么是MyCat:
Vue是啥?
API是啥?{application programming interface}
啥是JavaScript(动态效果)?Css? (颜色);
js函数
什么是单点登录?
一、jsonp 原理
Feign详解与实例?
SpringBoot优点?
JVM会将申请到的内存从逻辑上划分为三个区域:堆、栈、方法区。这三个区域分别用于存储不同的数据。
堆:用于存储使用new关键字所创建的对象以及对象的属性成员变量。
栈:用于存储程序运行时在方法中声明的所有的局部变量。
方法区:用于存放类的各种信息(包括方法)都在方法区存储。
局部变量:
1) 定义在方法中;
2) 没有默认值,必须自行设定初始值;
3) 方法被调用时,存在栈中,方法调用结束时局部变量从栈中清除;
成员变量:
1) 定义在类中,方法外;
2) 由系统设定默认初始值,可以不显式初始化;
3) 所在类被实例化后,存在堆中,对象被回收时,成员变量失效;
存放对象的实例,垃圾收集器管理的主要区域,分为新生代,老年代
新生代又分为Eden区域, Survivor区域
Survivor区域又分为form,to区域
新生代Eden:新对象和没有达到一定年龄的对象保存在该区域
老年代Tenured:新创建的超大对象,长时间被使用的对象,经过GC清理后还存活的对象
元空间:像一些方法中操作的参数,临时的对象都保存在元空间
1).创建一个新对象,会把这个新对象的实例放在新生代的Eden区域,当Eden区空间不足,无法保存创建新的对象时则会触发MinerGC进行清理
2).当经过一次MinorGC进行清理后Eden区还存活的一些对象会通过复制算法把它复制到Survivor区(存活区)的from 区(原to区).
3).Survivor区的两块区域是相同大小的两块区域,是可以互相交换的,交换以后form的叫to,to的叫from,交换的过程中会把其中一个的对象复制到另外一个,保证有一个是空的.
--经历一次MinorGC,如果Eden区有对象被保存到Survivor区的原to区时,然后对原from区域中进行一次清理,把清理后还依然存活的对象复制到原to区,然后把原to区更名为from区,把原form区更名为to区,这样就保证每次to区都是空的
4).当原from区进行MinorGC进行清理后往原to区进行复制的时候,原to区复制一部分对象后满了的情况下,会将原form区的剩余对象复制到老年代区域.
--另外Survivor区中的对象每熬过一次MinorGC年龄就会增长一次,还可以通过设置年龄阈值参数:-XX:MaxTenuringThreshold,当年龄增到到我们设定的阈值时,将该对象直接复制到老年代中.
5).老年代区域没有可用空间时会触发Full GC,Full GC会扫描整个老年代区域将还存活的对象进行标记,然后把不存活的对象进行清除.
优点:空间内存活对象多的情况下,效率高.
缺点:直接回收不存活对象所占用的内存空间,回收后造成整个空间不连贯,产生内存碎片.
堆内存空间满的情况会抛出OutOfMemoryError异常.
GC的垃圾回收策略:
串行策略,并行策略,并发策略
GC的垃圾回收算法:
复制,标记-清除,标记-清除-整理
封装,继承,多态
封装:把描述一个对象的属性和行为封装成一个类,把具体的业务逻辑功能实现封装成一个方法,其次封装的意义还有效的保护属性通过访问修饰符私有化属性(成员变量),公有化方法.
继承:实现代码的复用,所有的子类所共有的行为和属性抽取为一个父类,所有的子类继承该类可具备父类的属性和行为,继承具有单一性和传递性.
多态:程序中定义的引用类型变量所指向的具体类型和调用具体的方法在编译期无法确定,而是在运行期才能确定该引用类型变量指向具体哪个对象而调用在哪个类中声明的方法.
多态的表现形式有强制类型转换,向上造型等,多态可分为行为多态和对象多态:
行为多态:同一个run(){}方法,不同的对象调用时会有不同的实现,猫调用时是跑,鱼调用时是游,鸟调用时是飞.
对象多态:同一个对象,可以被造型为不同的类型,比如同一个人对象,可以被造型为儿子,父亲,员工等.
Overload是重载的意思,Override是覆盖的意思,也就是重写。
重载Overload表示同一个类中可以有多个名称相同的方法,但这些方法的参数列表各不相同(即参数个数或类型不同)。
重写Override表示子类中的方法可以与父类中的某个方法的名称和参数完全相同,通过子类创建的实例对象调用这个方法时,将调用子类中的定义方法,这相当于把父类中定义的那个完全相同的方法给覆盖了,这也是面向对象编程的多态性的一种表现。
(重写要遵循"两同两小一大"原则:
两同:1)方法名相同 2)参数列表相同
两小: 1)子类方法的返回值类型小于或等于父类的
1.1)void时必须相等
1.2)基本类型时必须相等
1.3)引用类型时小于或相等:父类大,子类小
2)子类抛出的异常小于或等于父类的
一大:子类方法的访问权限大于或等于父类的)
含有abstract修饰符的class即为抽象类,抽象类不能创建的实例对象。含有抽象方法的类必须定义为abstract class.
接口(interface)可以说成是一种特殊的抽象类,接口中的所有方法都必须是抽象的。接口中的方法定义默认为public abstract类型,接口中的成员变量类型默认为public static final。
下面比较一下两者的语法区别:
在语法定义上的区别:静态变量前要加static关键字,而实例变量前则不加。
在程序运行时的区别:实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量。静态变量不属于某个实例对象,而是属于类,所以也称为类变量,只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间,静态变量就可以被使用了。总之,实例变量必须创建对象后才可以通过这个对象来使用,静态变量则可以直接使用类名来引用。
在switch(expr1)中,expr1只能是一个整数表达式,整数表达式可以是int基本类型或Integer包装类型,由于byte,short,char都可以自动转换成int型,所以可以使用.
long类型由于不能自动转换成int类型,所以不能使用.
关于字符串类型,在JDK是1.7版本之前,swicth case中不可以使用字符串,但在JDK1.7之后是可以用字符串的,这是最新版本新加入的特性.
String有length()这个方法。
Array(数组)有length的属性。
集合没有length()方法,有size()方法。
==比较基本数据类型时比较的时值是否相等,比较引用类型时比较的是对象的地址值是
否相同,也就是否是同一对象。
未重写的equals方法调用的是Object的方法,用法==一样,重写后的equals方法是用
于比较两个独立对象的内容是否相同,就好比去比较两个人的长相是否相同,它比较的
两个对象是独立的。例如对于下面的代码:
String a=new String("foo");
String b=new String("foo");
两条new语句创建了两个对象,然后用a和b这两个变量分别指向了其中一个对象,
这是两个不同的对象,它们的地址是不同的,所以表达式a==b将返回false,而这两
个对象中的内容是相同的,所以,表达式a.equals(b)将返回true.
String这个类重写过equals方法, StringBuffer,StringBuilder未重写过equals方法.
再以上基础上又String str1=new String("abc");一共创建几个对象?
创建了两个对象,一个str引用指向堆内存中的String对象,另外一个则是String类有参构造方法中的直接量字符串对象,该字符串对象在字符串常量池中.
如果在执行一次String str1=new String("abc");此时共创建了几个对象?
因为在第一次常量池中已经有一个"abc"字符串对象,第二个创建时并没有创建新的,而是拿过来直接用,只是创建了1个str1指向堆内存中的String对象,共3个.
String类是final修饰的,该类所表示的字符串对象不可变,一旦发生改变即创建新对象, 当我们通过字面量,常量来初始化一个字符串时,JVM首先会从字符串的常量池(一个JVM内部维护的内存区域,用来保存已经创建过的字符串对象)中查询用来保存该字符串的对象是否存在,若存在则直接引用,若不存在则创建该字符串对象并存入常量池,然后引用它.
StringBuffer和StringBuilder是可变字符串对象,对字符串的修改操作不会创建新对象,都是在原有对象基础上进行修改,内部有很多操作字符串的方法,比如append()等.另外StringBuffer是线程安全的,同步处理的,性能稍慢;StringBuilder是非线程安全的,并发处理的,性能稍快。
String类有一个重载的构造方法:
String(byte bytes[], String charsetName)
第一个参数为一个byte数组,第二个参数为指定的字符集类型
字符串有 第一个是数组,第二个可以传你想变得类型;
Integer i1=new Integer(i);
Integer i2=new Integer(i);
System.out.println(i1==i2);
System.out.println(i1.equals(i2));
输出的结果是false true
因为i1和i2使用new关键字new了两次,在堆内存中创建了2个对象,所以==比较为false,内容相同equals比较为true
Integer i3=Integer.valueOf(i);
Integer i4=Integer.valueOf(i);
System.out.println(i3==i4);
System.out.println(i3.equals(i4));
输出结果为false true
在包装类的内存中有一块区域,缓存着Integer的byte范围内的值(-128~127),如果未超出此范围,则直接在该缓存区取值,并不会在堆中创建新对象,如果超出此范围则会在堆内存中创建新对象.
如上代码i=128超出了取值范围,则在i3和i4创建了两个对象,所以双等号比较为false,内容相同equals比较为true
是引用类型取的地址值从Integer缓存区拿出来的 第一个是true 第二个是是fasle记住缓存区范围是127~-128之间
List是可重复集合,Set是不可重复集合,这两个接口都实现了Collection父接口.
Map未继承Collection,而是独立的接口, Map是一种把键对象和值对象进行映射的集
合,它的每一个元素都包含了一对键对象和值对象, Map中存储的数据是没有顺序的,
其key是不能重复的,它的值是可以有重复的。
List的实现类有ArrayList, Vector和LinkedList.
ArrayList和Vector内部是线性动态数组结构,在查询效率上会高很多,Vector是线程安全的,相比ArrayList线程不安全的,性能会稍慢一些.
LinkedList:是双向链表的数据结构存储数据,在做查询时会按照序号索引数据进行前向或后向遍历,查询效率偏低,但插入数据时只需要记录本项的前后项即可,所以插入速度较快。
Set的实现类有HashSet和TreeSet;
HashSet: 内部是由哈希表(实际上是一个 HashMap 实例)支持的。它不保证 set元素的迭代顺序.
TreeSet: TreeSet使用元素的自然顺序对元素进行排序,或者根据创建 set 时提供的 Comparator 进行排序.
Map接口有三个实现类:Hashtable,HashMap,TreeMap,LinkedHashMap
Hashtable: 内部存储的键值对是无序的是按照哈希算法进行排序,与HashMap最大的区别就是线程安全.键或者值不能为null,为null就会抛出空指针异常
HashMap: 内部存储的键值对是无序的是按照哈希算法进行排序,与Hashtable最大的区别就是非线程安全的,键或值可以为null
TreeMap: 基于红黑树(red-black tree)数据结构实现, 按 key 排序,默认的排序方式是升序.
LinkedHashMap:有序的Map集合实现类,相当于一个栈,先put进去的最后出来,先进后出.
List的实现类有ArrayList, Vector和LinkedList.
ArrayList和Vector内部是线性动态数组结构,在查询效率上会高很多,Vector是线程安全的,相比ArrayList线程不安全的,性能会稍慢一些.
LinkedList:是双向链表的数据结构存储数据,在做查询时会按照序号索引数据进行前向或后向遍历,查询效率偏低,但插入数据时只需要记录本项的前后项即可,所以插入速度较快。
1.)HashMap: 内部存储的键值对是无序的是按照哈希算法进行排序,与Hashtable最大的区别就是非线程安全的,键或值可以为null
2.)Hashtable: 内部存储的键值对是无序的是按照哈希算法进行排序,与HashMap最大的区别就是线程安全.键或者值不能为null,为null就会抛出空指针异常
1)当调用put方法往HashMap中存键值对时,会把key的hashCode值交给Hash
算法进行计算,算出来一个地址值,该地址值决定着该键值对存在数组中的那个位置.
2)找到该存储地址位置时会在调用equals方法来比较是否存在相同的key,如果不存在则把该键值对存在该位置,如果存在则替换其value值.
3)如果在调用put方法时传入key不相同,但是key的hashCode值交给Hash算法进行计算时得到了相同的地址值,那么就会产生链表.会在同一个地址上存入两个key不相同的键值对,先存入的键值对被放到链表的尾部,后存入放到链表首部.
4)产生链表会影响查询效率,所以被存入的键值对对象都会重写equals和hashcode方法,但链表不能完全避免,原因是可能存在巧合key不相同但HashCode值相同.
5)当调用get方法时传入key,把key的hashCode值交给Hash算法进行计算,算出来一个地址值, 通过该地址找到元素后在调用equals方法来比较key是否存在,若存在则返回其value值.
1)继承Thread类.重写run方法 单继承
2)实现Runnable接口.重写run方法 可以将创建线程的代码和代码要执行的代码分开, 降低了耦合性
另外:一个线程仅需要一个实例时可以使用匿名内部类创建,这种方式有助于简化代码
继承Thread类:
实现Runnable接口:
New(新建):当我们创建一个线程时该线程并没有纳入线程调度处于一个new状态。
Runnable(就绪):当调用线程的start方法后,该线程纳入线程调度的控制,其处于一个可运行状态,等待分配时间片段以并发运行。
Running(运行):当该线程被分配到时间片段后被CPU运行,该线程处于running状态。
Blocked(阻塞):当线程在运行过程中可能会出现阻塞现象,比如等待用户输入信息等。但阻塞状态不是百分百出现的,具体要看代码中是否有相关需求。
Dead(结束):当线程的任务全部运行完毕,或在运行过程中抛出了一个未捕获的异常,那么线程结束,等待GC回收.
当使用new线程创建完毕后调用start方法后线程进入就绪状态,线程调度系统将就绪状态的线程转为运行状态,遇到synchronized语句时,由运行状态转为阻塞,当该线程获得synchronized对象锁后,由阻塞状态转为运行,在这种情况下可以调用wait 方法转为挂起状态,当线程关联的代码执行完毕后,线程变为结束状态.
java中有一个关键字名为:synchronized,该关键字是同步锁,用于将某段代码变为同步操作,从而解决线程并发安全问题.
用于将某段代码变为同步操作,解决线程并发的问题
synchronized加在普通方法上:当一个普通方法是用synchronized修饰后,该方法称为:"同步方法" 即:多个线程不能"同时"执行该方法,只能有先后顺序同步执行.锁定的是当前对象,也就是this.
注:只针对同一个对象访问同一个方法会产生同步,两个不同的对象访问各自的同步方法不会产生同步.
synchronized加在静态方法上:当一个静态方法是用synchronized修饰后, 该方法一定具有同步效果,因为只有1份,跟对象无关, 实际上上锁的对象为当前方法所属类的类对象,即:Class的一个实例.
注:与普通方法加锁有区别,在静态方法上加锁由于锁的是当前类,所以通过该类创建出来的多个对象访问该静态方法都会出现同步.
synchronized代码块: 为了有效缩小同步范围,来提高多线程并发执行效率,可以使用同步块,同步块写在方法内部,同步方法内的某一段代码.
注:同步块需要自行指定"同步监视器",即:上锁的对象,只要保证需要排队执行的多个线程看到是同一个对象即可!,一般写的是this
同步锁:多个线程 同一对象 同一个加锁方法 上锁对象是同一个
互斥锁:多个线程 同一对象 不同加锁方法 上锁对象是同一个
Synchronized也是互斥锁: 当修饰的是两段不同的代码,但是同步监视器对象是同一个的时候,那么就具有了互斥性.
如下案例:
Boo类中有两个Synchronized同时修饰2个不同的方法,锁定的都是当前对象this,在访问该对象的两个不同同步方法时都会将当前对象锁定,互相牵制,谁也不让谁,必须等一个执行完另外一个才能执行.
注意:上述案例如果Boo里有一个synchronized修饰的是静态方法,那么将不会产生互斥,因为静态方法用synchronized修饰锁定的是当前.class,而普通方法使用synchronized修饰锁定的是当前对象,也就是this, 同步监视器监视的对象并非同一个,所以不会产生互斥.
死锁: 就是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。
线程死锁可能发生在以下的情况:
1)当两个线程相互调用Thread.join();
2)当两个线程使用嵌套的同步块时,一个线程占用了另一个线程的必需的锁,互相等待时被阻塞,就有可能出现死锁。
死锁一般都是由于对共享资源的竞争所引起的。但对共享资源的竞争又不一定就会发生死锁,死锁的发生必需满足4个必要条件:
如何解决死锁:可以从死锁的四个条件去解决,只要破坏了一个必要条件,那么死锁问题就解决了,在java中使用多线程的时候一定要考虑是否有死锁的问题.
Java异常结构中定义有Throwable(可抛出)类,Exceotion(异常)和Error(错误)是其派生的两个子类。
Exception(异常):表示由于网络故障、文件损坏、设备错误、用户输入非法等情况导致的异常,这类异常是可以通过Java异常捕获机制处理的。
Error(错误): 表示程序无法处理的错误,表示运行应用程序中较严重问题,例如:JVM内存溢出等。
Exception(异常):又分为检查型异常和运行时异常
检查型异常:需要经过编辑器检查处理的异常,对于声明抛出异常的方法,必须经过强制处理或者自己捕获处理,否则编译无法通过,此类异常继承Exception,典型的检查性异常有IOException,ClassNotFoundException等.
运行时异常:编辑期间编译器不做检查,在运行时才会抛出的异常,此类异常继承RuntimeException.运行时异常有NullPointerException, NumberFormatException, ArrayIndexOutOfBoundsException等.
继承Exception时自定义异常属于检查型异常,编译器会做检查,会主动提示抛出.
继承RuntimeException时自定义异常属于运行时异常,编译期不会检查,运行时会抛出相关异常.
throw:是指抛出的一个具体的异常类型,写在方法的内部, 需要用户自己捕获相关的异
常,而后在对其进行相关包装,最后在将包装后的异常信息抛出.
//假设自定义了一个IllegalAgeException异常,此处省略:
public class Exception_throw {
public static void main(String[] args){
Person p=new Person();
try {
p.setAge(10);
} catch (IllegalAgeException e) {
e.printStackTrace();
System.out.println("出错了!");
}
System.out.println("年龄是:"+p.getAge()); }}
class Person{
private int age;
public int getAge(){
return age;}
public void setAge(int age) throws IllegalAgeException{
if(age<0||age>100){
throw new IllegalAgeException("年龄不合法");}
this.age=age;
}}
throws:是用来声明一个方法可能抛出的所有异常信息,多个异常之间逗号隔开,写在方法上, 通常不用显示的捕获异常,可由系统自动将所有捕获的异常信息抛给上级调用者.
RuntimeException子类:
ArrayIndexOutOfBoundsException: 数组下标越界异常。当对数组的下标为负数或大于等于数组大小时抛出。
ArithmeticException: 算术条件异常。如:整数除以零。
NullPointerException:空指针异常, 调用null对象的实例方法、访问null对象的属性、计算null对象的长度、使用throw语句抛出null等等.
ClassNotFoundException: 找不到类异常。根据字符串形式的类名在遍CLASSPAH之后找不到对应名称的class文件时,抛出该异常。
NegativeArraySizeException 数组长度为负异常
ArrayStoreException 数组中包含不兼容的值抛出的异常
SecurityException 安全性异常
IllegalArgumentException 非法参数异常
ClassCastException 类型转换异常类
ArrayStoreException 数组中包含不兼容的值抛出的异常
SQLException 操作数据库异常类
NoSuchFieldException 字段未找到异常
NoSuchMethodException 方法未找到抛出的异常
NumberFormatException 字符串转换为数字抛出的异常
StringIndexOutOfBoundsException 字符串索引超出范围抛出的异常
IllegalAccessException 不允许访问某类异常
IOException:操作输入流和输出流时可能出现的异常。
EOFException 文件已结束异常
FileNotFoundException 文件未找到异常
final:修饰符:
final修饰的类不能被继承,
final修饰的变量不可改变,在声明的同时初始化.
final修饰的方法不可被重写.
finalize:方法名
在垃圾回收器将内存中的没有引用指向的对象清空之前,调用finalize() 进行清理工作.
finally:异常处理中的程序块
在异常处理时,使用finally块来进行必要的清理工作,不论是否有异常发生,finally语句块中的语句都会被执行,如果发生了异常,则执行catch语句,再执行finally块.
反射是Java 动态执行机制,可以实现动态执行功能:
1.反射提供了在运行时判断任意一个对象所属的类型并可以检查解析类型的内部结构。
2.反射可以动态加载类型,并能够动态创建对象
3.反射可以动态访问对象的属性。
4.反射可以动态执行对象的方法。
5.利用反射API还可以动态的访问,不可见的属性和方法,打破面向对象的封装性.
优点:可以动态执行!在运行期间根据业务功能动态执行方法、访问属性,最大限度发
挥了java的灵活性。
缺点:对性能有影响,这类操作总是慢于直接执行java代码。
有一个实体类Person:
通过反射机制获取该类的类对象和内部的属性及方法,并给属性赋值和调用方法:
JDBC中,利用反射动态加载了数据库驱动程序。
Web服务器中利用反射调用了Sevlet的服务方法。
很多框架用到反射机制,注入属性,调用方法,如Hibernate、Struts2、Spring等
反射是Java 动态执行机制,可以实现动态执行功能
通过反射获取类对象有三种方法:类名.class,class.forname(类的全路径名),对象.getclass;
获取类中的属性及方法:用类对象调用getDeclaredDield(“变量名”)给属性赋值:Field对象调用set(实例对象.值)
获取类中的方法并执行:
获取:类对象调用getDeclaredMethod(方法名.参数类型的class)
执行:返回一个method类型的对象,用它调用invoke(实例对象,参数)
表单是浏览器向服务器传送数据的手段,使用
标签将表单元素及书写包裹在内.有三个主要属性:
action:表单提交的URL地址路径
method: 表单的提交方式,默认为get请求方式,可设置为post请求方式.
enctype:表单数据的编码方式
表单控件分为input元素和其他元素:
input元素:
文本框:
密码框:
主要属性:value:用户输入的文本数据 maxlength:最大输入字符数 readonly:只读
单选框:男性
女性
复选框:checked name="like" value="1"/>篮球
足球
主要属性:value:单/复选框文本 name:分组,一组单/复选框name属性必须相同
checked:设置选中
按钮元素:
提交按钮::自带表单提交效果
重置按钮::重置表单内容
普通按钮::普通按钮
主要属性:value:按钮名字
隐藏框,文件选择框元素:
隐藏框::一个用户看不到的框体
文件框::选择要上传的文件
其他元素:
文本域:
主要属性:cols:列数 rows:行数 readonly:只读
下拉选:
主要属性: selected: 设置默认选中,如果设置多个,位置最下的生效
value: select的value值,主要是用作表单提交的时候将用户选中的option
的value值的传递给服务器
注:input元素中的name属性规定 input 元素的名称, 只有设置了 name 属性的表
单元素才能在提交表单时传递它们的value值.
比如在servlet中可以通过request.getParameter(name 属性的值)来获取浏览器提
交表单时传递给服务器的value值数据.
对于不同的input 元素,value 属性的用法也不同:
type="button", "reset", "submit" -按钮上的显示的文本
type="text", "password", "hidden" -框体内的初始值
type="checkbox", "radio" -与单/复选框相关联的值
注意: 和 中必须设置 value 属
性,在表单提交时会将chekcd(选中的)单选和复选框的value属性值发送给服务器.
比如在Jquery中可以通过选择器以及val()获取浏览器表单中标签元素的value值
$('#id').val();
常用的有三种:
提示对话框:alert():弹出并显示字符串文本信息
function f1(){
alert("你好");
}
确认对话框:confirm():弹出确认框,点击确定返回true,点击取消返回false.
function f2(){
var b=confirm("你吃了吗");
console.log(b);
}
输入对话框: prompt():弹出输入框,让用户输入信息
function f3(){
var r=prompt("你吃了吗?");
console.log(r);
}
盒子模型指的是页面标签的实际宽高
公式:宽:左外边距+左边框线+内容的宽+右外边距+右边框线
高:上外边距+上边框线+内容的高+下外边距+下边框线
$obj.on():选中的元素及其子元素绑定对应事件
案例:div标签下有p标签,p标签下有button按钮:
对div绑定单击事件时,点击div下范围内的任意后代元素都会触发绑定的事件
如果只想让父标签下某些子标签生效可以设置指定子元素,比如指定button按钮标签,这是点击p元素范围时将不再触发事件:
$("div").on('click','#btn',function(){
alert("我行");
});
在没用on()函数之前是前绑定事件,一般用加on函数来实现后绑定比较方便;
on() 方法在被选元素及子元素上添加一个或多个事件处理程序。
使用 on() 方法添加的事件处理程序适用于当前及未来的元素(比如由脚本创建的新元素)
可以使用层次选择器+过滤选择器,获取id为city的父元素下的符合状态过滤选择器是selected(选中状态)的option元素.
使用层次选择器+过滤选择器,获取id为good的父元素下的符合表单元素选择器:checkbox的元素再次使用状态过滤选择器:checked定位到被选中的复选框.
$("#f1 :radio:first").val(0);
可以使用层次选择器+过滤选择器,获取id的值再加具体的判断条件radio的第几个?最后在点个val;
根据选择器
{ 类选择器 ID选择器 选择器组 派生选择器 伪类选择器 元素选择器}
派生:根据父元素找到子元素;
{ --基本选择器 -层次选择器 --过滤选择器又分为(基本 内容 可见性 属性 状态)}
val() 获取元素 value 值; val()只支持form表单控件中的标签
val(‘值’) 设定元素的 value 值;
html() 获取元素的 html 内容; html()返回选择器中的页面值,包括标签
html("html 内容") 设定元素的 html 内容;
text() 获取元素的文本内容,不包含 html ; text()只获取文本值,不获取标签
不能获取form表单中的标签的值,除了select下拉框
text("text 内容") 设置元素的文本内容,不包含 html;
data("绑定名");data("绑定名","绑定值");attr("属性名","属性值");attr("属性名");函数都是做什么用的?
添加样式class选择器:addClass()
删除样式class选择器:removeClass()
hasClass():判断是否有某个class选择器
data("绑定名"); 给元素添加属性
data("绑定名","绑定值"); 给属性赋值
data是保存在jquery对象里,attr是保存在DOM元素上);
attr(“class”) 获取 class 属性的值,即样式名称
attr(“class”,”样式名”) 修改 class 属性的值,修改样式
mysql:3306
oracle:1521(一个我爱你)
聚合函数:是对查询结果集进行进一步处理的函数(求和,求平均,计数,最大值,最小值)
sum(),avg(),count(字段名)/count(*),max(),min()
空值函数:判断某个字段是否为null,如果为空可以将其替换成其他值
mysql:ifnull(字段,值1):当字段为null时,取值1的值,否则取字段的值
select ifnull(sal,0);
oracle:nvl(字段,值1)
nvl2(字段,值1,值2):当字段的值为null的取值2,不为null取值1
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class itemController {
@RequestMapping("/test")
public String test (String itemId){
return "test";
}
}
mysql:
Select * from 表名 limit 10,5 :表示从第11行开始,返回5行数据。(11,12,13,14,15)
Select * from 表名 limit 5 offset 10; :表示从第11行开始,返回5行数据。
oracle:rownum:伪列:对查询结果集生成一个编号,作为过滤条件时不能大于几
1.排序
select * from emp order by sal desc;
2.取最大范围数据
select rownum rn,name,sal from(
select * from emp order by sal desc)
where rownum <=10;
3.取开始的范围
select * from (
select rownum rn,name,sal from(
select * from emp order by sal desc)
where rownum <=10)
where rn>=3;
1.case when then end;/通用/
2.结合聚合函数中的sum或者count
3.若需要分组使用group by
1.if(条件,值1,值2);/mysql特有
2.结合聚合函数中的sum或者count
3.若需要分组使用group by
mysql中:
使用if函数和case when
if(条件,值1,值2):当条件为true时取值1,false取值2
select age '年龄',
sum(if(sex='男',1,0)) '男',
sum(if(sex='女',1,0)) '女'
from stu
group by age;
或者
select age '年龄',
count(if(sex='男','男',null)) '男',
count(if(sex='女','女',null)) '女'
from stu
group by age;
oracle中:
使用case when
case 值 when 匹配值1
then
语句...
else
语句...
end :当值匹配到配置1成立时执行then后语句,否则执行else
case when 条件
then
语句...
else
语句...
end :当条件成立时执行then后语句,否则执行else
select age '年龄',
sum(case when sex='男' then 1 else 0 end) '男',
sum(case when sex='女' then 1 else 0 end) '女'
from stu
group by age;
或者
select age '年龄',
count(case when sex='男' then 1 else null end) '男',
count(case when sex='女' then 1 else null end) '女'
from stu
group by age;
带数据复制
create table 新表名 as select * from 原始表名 where 1=1;
不带数据复制
create table 新表名 as select * from 原始表名 where 1=2;
拷贝数据到相同结构的表中
insert into 目标表 select * from 源表;
批量插入
insert into 目标表 select * from 原始表名;
rownum:伪列:对查询结果集生成一个编号,作为过滤条件时不能大于几
rowid :伪id:是每一条添加到数据库表中的数据的物理地址
约束(CONSTRAINT):限制条件,均用于创建表时对字段进行添加限制条件.
约束类型:
非空约束(NOT NULL):简称NN 1)确保字段值不为空;
唯一性约束(UNIQUE):简称UK 2)保证指定的字段不允许有重复的值(NULL除外);
主键约束(PRIMARY KEY):简称:PK 3)约定的字段非空且唯一,并且一个表中只能有一个主键或者联合主键;
外键约束(FOREIGN KEY):简称:FK 4)一张表保存的是另一张表的主键字段的值, 两个方面的数据约束:
检查约束(CHECK):简称:CK 5)用来强制在字段上的每个值都满足CHECK 中定义的条件;
默认约束: 6)对字段的默认值进行约束,设置默认值
--TRUNCATE语句属于DDL语句,删除表中数据保留表结构,立即生效,不可以回滚,大数据量删除记录时效率高.
--DELETE语句属于DML语句,删除表中数据保留表结构,逐行删除记录,大数据量删除效率低,可执行条件删除,若不指定条件是全表删除.
--DROP语句是DDL语句,是删除数据库中表的操作语句.
一)WHERE过滤子句是查询过程中对表中数据的过滤条件, 不允许使用聚合函数作为过滤条件,原因在于时机不对,聚合函数是对表中数据查询后的结果集进行统计处理的,两者的执行时机不一致.
二)HAVING过滤子句是对查询结果集进行过滤的,可以在该子句后使用聚合函数,因为时机相同,聚合函数是处理结果集的,HAVING子句又是过滤结果集的,可以在一起使用,另外HAVING不能单独使用,只能跟在GROUP BY分组子句后面使用.
1.找到每一组的最小id数据
select min(id) id
from u
group by name,age,sal;
2.解决mysql中不能变查边删的问题(用查询语句再次查询起个别名)
3.使用delete嵌套刚才的查询进行删除并保留刚才查询到的数据
delete from u
where id not in(
select * from (
select min(id) id
from u
group by name,age,sal) t);
1.找到每一组的最大id数据
2.解决mysql中不能变查边删的问题(用查询语句再次查询起个别名)
3.使用delete配合not in嵌套刚才的查询进行删除并保留刚才查询到的数据
delete from u
where id not in(
select * from (
select max(id) id
from u
group by name,age,sal)t);
并集:对多个查询结果集的数据进行合并
union:结果集合并时会去重
select * from u where id=4
union
select * from u where id=8
union
select * from u where id=8;
union all:结果集合并时不会去重
select * from u where id=4
union all
select * from u where id=8
union all
select * from u where id=8;
create user 新的用户名 identified by 密码;
grant 权限名字(select,update....) on 库名.表名(*所有表) to 用户名;
flush privileges; 授权后刷新权限表
revoke 权限名字(select,update....) on 库名.表名(*所有表) from 用户名;
注:all是所有权限
查看权限:
show grants for 用户名;
真删除:真的使用delete语句删除数据
假删除:使用update语句改变数据库表中数据的状态
假分页:一次性从数据库中查询出所有数据放到内存中,每次使用从内存取对应数据
真分页:多次访问数据库查询出对应范围的数据
事务:保护数据库数据可靠交易的安全机制
事务特性ACID:
1)原子性(Atomicity)原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
2)一致性(Consistency)一个事务中,事务前后数据的完整性必须保持一致。
3)隔离性(Isolation)多个事务,事务的隔离性是指多个用户并发访问数据库时, 一个用户的事务不能被其它用户的事务所干扰,多个并发事务之间数据要相互隔离。
4)持久性(Durability)持久性是指一个事务一旦被提交,它对数据库中数据的改变 就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。
事务的隔离级别:
1)read uncommitted : 读未提交 :最低级别,任何情况都无法保证。
2)read committed:读已提交 :可避免脏读的发生。 ---- oracle、sql server默认
3)repeatable read:可重复读:可避免脏读、不可重复读的发生。 ---mysql默认的
4)serializable:串行化:可避免脏读、不可重复读、幻读的发生---相当于锁表
1)脏读:B事务读取到了A事务尚未提交的数据 ------ 要求B事务要读取A事务提交的数据
2)不可重复读:一个事务中两次读取的数据的内容不一致 ----- 要求的是一个事务中多次读取时数据是一致的
--- update
3)幻读/虚读:一个事务中 两次读取的数据的数量不一致 ----- 要求在一个事务多次读取的数据的数量是一致的
--insert delete
悲观锁:认为操作一定会发生数据冲突,每次操作前都要获取锁
1)排他锁:对一资源增加排他锁后,只有自身可以进行增删改查操作,其他人无法进行操作。默认对增删改假排他锁
对查询语句加排他锁:select * from goods_lock where id=1 for update ; 表示id等于1的资源不能被其他人操作
2)共享锁:对一资源加共享锁后,自身可以进行增删改查,别人只可以进行查询,其他操作必须等共享锁释放
对查询语句加共享锁: select * from goods_lock where id=1 lock in share mode;
乐观锁:认为操作不会导致数据冲突,操作数据时,不加任何特殊处理,在操作完成后,判断是否有冲突。它属于开发人员编写的锁,与数据库无关。
具体是,开发人员给相关表增加version字段,修改前,先将version查询出来,然后将查询的结果做为where中的一个条件,满足条件时,表明没有其他操作同时进行,可以对数据进行更新,并将version+1,保证每次修改后version是一个新值。
如果条件不满足,表明有其他操作同时进行,本次操作失败,重新查询version值,并将结果再次做为where条件,进行判断
JDBC是java应用程序访问数据库的解决方案
JDBC访问数据库的工作过程:
1)注册加载驱动:
Class.forName("oracle.jdbc.driver.OracleDriver");
2)建立连接:
Connection conn =DriverManager.getConnection(url,username,password);
3)创建执行SQL语句对象及SQL语句:
Statement stmt=conn.createStatement();
String sql="SELECT * FROM emp";
4)执行SQL语句:
ResultSetrs = stmt.executeQuery(sql);
5)处理结果集
while (rs.next()) {
rs.getInt(...);
rs.getString(...);
rs.getDate(...);
}
6)关闭连接
conn.close();
都属于jdbc的执行对象
关系:Preparedstatement继承自Statement,都是接口
1)Statement:内部是拼接的方法
Statement执行两条相同结构的语句,只是参数不同时被认定2个不同的SQL,需要创建两个执行计划;
所以Statement执行有条件的语句时效率低,更适合执行不带条件的静态语句(DDL)
2)Preparedstatement
可以使用占位符,是预编译的,下次再执行该对象,效率更高
可以防止sql注入,方法是:把用户非法输入的单引号用\反斜杠做了转义 提高了安全性
一.Http协议也叫超文本传输协议:由w3c制订的一种网络应用层协议,
规定了浏览器与web服务器之间如何通信及相应的数据格式。
二.(1)请求数据包:Request
请求行:包含请求类型GET/POST、请求路径、协议类型/版本
消息头:访问主机的IP和端口号,浏览器版本,接受的资源类型等
实体内容:GET请求时为空,POST请求时为请求时,实体内容为要提交的表单数据
(2)响应数据包:Response
状态行: 包括协议类型/版本、状态码、状态描述
消息头:响应给浏览器的相关信息:响应数据类型,数据大小,服务器版本信息,响应时间等
实体内容:响应给浏览器的具体数据,浏览器逐行解析.
1.在本地文件夹 外部端的应用服务器server.xml,
2.在eclipese中进行修改 ,在idea/eclipse上修改
实例化:在第一次访问或启动tomcat时,tomcat会调用此无参构造方法实例化servlet
初始化:tomcat在实例化此servlet后,会立刻调用init方法初始化servlet
就绪:容器收到请求后会调用servlet的service方法来处理请求
销毁:容器依据自身算法删除servlet对象,删除前会调用destroy方法
其中实例化,初始化和销毁只执行一次,service方法执行多次,默认情况下servlet 是在第一次接收到用户请求的情况下才会被实例化,可以在web.xml中的
当第一次访问jsp页面时,会向一个servlet容器(tomcat等)发出请求,servlet容器先要把 jsp页面转化为servlet代码(.java),再编译成.class 文件 再进行调用。当再次访问jsp页面时 跳过翻译和编译的过程 直接调用
Servlet主要是控制的处理,如调用业务层,跳转不同的jsp页面。
JSP主要在于页面的显示动态生成页面,可以与html标记一起使用,本质上还是servlet.
JSP在第一次接收到用户请求后会先将JSP编译成.java文件,然后再编译成.class文件,最终被JVM加载执行.
JSP九大内置对象:
4个是作用域对象:
作用域 |
作用域范围 |
作用域对象 |
page |
在当前JSP页面有效 |
pageContext |
request |
在当前请求中有效 |
request |
session |
当前会话中有效 |
session |
application |
在所有web应用中有效 |
application |
从某个作用域中取值:
四个作用域范围由小到大依次取值的顺序为:page,request,session,application,
如果在page中未取到值,则会继续在request中寻找取值,若依然未取到值则向下一个对象中寻找,依次类推.
除了默认由小到大的顺序外,也可以指定从某个作用域范围内取值:假设分别从session,request中取值:
sessionScope.绑定名
requestScope.绑定名
session{会话};cookie{可以设置30天免密码登录}不安全,绑定ip能阻止75%的请求。
Cookie和Session都是负责状态管理的,因为HTTP协议是无状态协议,需要利用Cookie和Session来记录状态.
1.cookie在客户端保存信息,session在服务器端保存信息
2.cookie可以在客户端设置,也可以在服务端设置(response.add,添加到浏览器),session在服务端设置
3.cookie生命周期设置,setMaxAge(x秒),大于0时,保存到本地硬盘,到达设置秒销毁,小于0时,保存在浏览器,浏览器关闭时销毁,等于0时,直接删除
4.第一次请求时,会创建一个session对象存储到内存中,并生成一个SID,并将SID发送到cookie中,之后的请求时,会通过cookie中携带的SID,找到对应的session对象,获取存储的数据。
5.session默认生命周期30分钟,通过setMaxInactiveInterval(int seconds)设置,通过invalidate()删除session
Cookie和Session都是负责状态管理的,因为HTTP协议是无状态协议,需要利用Cookie和Session来记录状态.
Cookie默认保存在浏览器端,随着浏览器的关闭而生命结束,可以调用setMaxAge(int seconds)方法来设置Cookie的生命时长,以秒为单位:
当seconds>0时保存在本地硬盘
当seconds<0时保存在浏览器,默认保存在浏览器
当seconds=0时立刻结束Cookie的生命
另外存储的数据大小只能为4K左右的数据,安全性较低, 别人可以分析存放在本地的Cookie并进行Cookie欺骗.
Session保存在服务器,当第一次用户请求时,服务器为其分配一个内存来保存session对象,并生成一个SID,在响应时将该SID以Cookie的形式发送给浏览器被保存在内存中,当同一用户再次发起请求时会携带SID到服务器,服务器会依据SID来找到对应的session并使用该session对象中保存的数据,由于数据保存的服务器,数据相对安全,但保存的session较多时会影响服务器性能.
session默认在服务器端保存30分钟,可以调用setMaxInactiveInterval(int seconds)方法来设置生命时长,seconds单位为秒.
想要删除session可以使用invalidate()进行删除.
转发和重定向都是解决WEB组件之间跳转问题的
转发:一次请求,地址不改变,共用1个request对象,只能转发到项目内组件。
request.getRequestDispatcher("emp_list.jsp").forward(req, res);
重定向:二次请求,向浏览器响应信息时会响应302状态码和要重定向的地址,地址会发生改变,两个请求中不能共享request对象,可以重定向到项目外的组件。
通常查询时候用转发,增删改之后重定向到查询。
response.sendRedirect("findEmp");
转发:return "forward:/findDog"; 转发到findDog请求
重定向:return "redirect:/findDog"; 重定向到findDog请求
get请求,浏览器默认发送get请求,使用请求路径传参,请求路径在请求行中,所以请求参数是可见的不安全,请求参数的大小有限制,一般小于2K,多用于到服务器请求数据
post请求,将参数存放在请求数据包的实体内容中,传递过程中不可见,隐私性好,参数大小无限制,用于向服务器提交数据
请求方式分为:get请求和post请求.
get请求:浏览器发送请求默认都是get请求,使用请求路径传参,将参数附加在路径上发送服务器, 由于请求路径是在请求数据包中的请求行中,所以参数在传递过程中可见,隐私性差, 只能携带少量参数(2k左右).
post请求: 在form表单上增加method="post"时,请求方式为post请求, 将参数存放在请求数据包的实体内容中通过实体内容传参, 参数在传递过程中不可见,隐私性好,传递的参数大小没有限制.
一般向服务器索取(查询)数据时用get, 向服务器提交数据时用post.
1.IOC
2.DI
3.AOP:AOP是面向横切面编程,在不改变原有功能的情况下横向织入扩展功能代码或扩展横切功能,比如:在原有项目上扩展新的模块,统一记录日志、事务,安全验证等.
Spring容器是Spring框架的一个核心模块,用来管理对象.
Spring容器有BeanFactory和ApplicationContext两种类型,其中ApplicationContext继承于BeanFactory接口.
IOC是控制反转:对象之间的依赖关系交给容器来建立.
DI是依赖注入:容器通过调用对象的set方法或者构造方法来建立对象之间的依赖关系
注:IOC是目标,DI是手段.
依赖注入的方式有三种:
1.通过set方法注入 2.通过构造方法注入 3.通过自动装配
1)set 方法注入:
假设现在有两个类A类和B类,在A类中execute()方法中调用B类中的f1()方法,需要在A类中声明B类型的引用, 在创建该引用的set方法,并声明B类型参数,在set方法内部将参数赋值给B类型的引用.
2)构造器注入:
假设现在有两个类A类和B类,在A类中execute()方法中调用B类中的f1()方法,需要在A类中声明B类型的引用, 创建A类的有参构造器,并声明B类型参数,在构造方法内部将参数赋值给B类型的引用.
《假设现在有两个类,A类中的一个方法调用B类中的一个方法,需要A中声明B类的类型引用,》
3)自动装配:(了解)
默认情况下,容器禁止自动装配。
设置autowire属性让容器自动装配。比如:autowire="byType"
byName:容器查找id等于属性名称的bean,然后调用对应 的set方法来完成注入。
注意:如果找不到对应的bean, 会注入null值。
byType:容器查找与属性类型一致的bean,然后调用对应 的set方法来完成注入。
注意:如果找不到对应的bean, 会注入null值。如果找到多个对应的bean,会出错。
constructor:类似byType,只不过调用的是构造器来 完成注入。
Spring IOC注解:
这组注解的作用是写在控制层/业务层/持久层类上,让Spring框架帮助创建对象并放入IOC容器中
@Component 通用IOC注解
@Controller 控制层IOC注解
@Service 业务层IOC注解
@Repository 持久层IOC注解(持久层目前只提供接口,所以不需要写该注解)
Spring DI注解:
这组注解的作用是在从IOC容器中取出来对应对象依赖注入到需要用的地方
@Autowired Spring提供的依赖注入注解
@Resource (瑞骚死) Servlet提供的依赖注入注解
mvc:model、view、controller,模型、视图、控制层、三层;
五大核心组件分别是:
DispatcherServlet (前端控制器) 接受所有所有请求
HandlerMapping (映射处理器)查找用户的请求与业务处理的映射
Controller (处理器)
ModelAndView 《一般是搭配jsp来使用的》一般不刷新,要钱啊
ViewResolver (视图解析器)实现路径的动态拼接
工作流程:
1.在tomcat启动时会实例化一个DispatcherServlet对象,该对象负责接收请求.
2.DispatcherServlet接收到用户请求后依据HandlerMapping中的配置路径与请求
路径进行比对,比对成功调用相应的Controller进行业务处理.
3.处理完毕后将结果封装到ModelAndView对象中(视图名和响应数据)返回给
DispatcherServlet, DispatcherServlet依据ViewResolver的解析,将视图名与
ViewResolver视图解析器中的前缀和后缀进行拼接得到一个具体的视图信息比如 hello.jsp,
调用相应的视图对象(比如jsp)来生成相应的页面.
4.然后DispatcherServlet将该页面响应给浏览器.
1. mapper标签的namespace的值填写接口的全路径名
2.返回值和mapper中的resultType一致
3.方法名和sql标签的id一致
4.方法参数类型和sql标签的parameterType一致
单列模式:
单例模式的核心:结构中只包含一个,被称为单例的特殊类。通过单例模式可以保证系统中
一个类只有一个实例, 可以减少频繁创建对象对内存的开销,保证核心业务只有一个对
象在进行处理;
(1) 懒汉式单例类:在第一次调用的时候实例化自己 (直接设置一个为null的对象);
(2) 饿汉式单例类:在类初始化时,已经自行实例化(是指一个实体对象);
(3) 线程安全单例类:对获取方法加锁,但性能稍慢(设置一个为空的用SingletonSync的对象);
(4) 双检锁线程安全单例类:使用同步块并进行双重判断;(用线程多做了个上锁在if判断中);
工厂模式:
工厂模式分为:普通工厂模式,抽象工厂模式,工厂方法模式.
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
本人总结:一个父接口,有三个子接口,三个字接口有不同的方法,父接口可以让第一个字接口做第二个子接口的方法;
单例模式的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中
一个类只有一个实例, 可以减少频繁创建对象对内存的开销,保证核心业务只有一个对
象在进行处理
单例模式的特点:
1. 初始化为null私有的静态自身引用,且被private修饰,其它类不得直接访问。
2. 单例模式的类还需要有private的构造方法,这一点不难理解,如果构造方法是public的,那么类外部可以直接调用该类的构造方法,如此一来便不具备单例的特性.
3. 公有的静态get方法,返回单个实例对象给调用者.
案例:请将如下代码务必写熟练(笔试题)
1) 懒汉式单例类:在第一次调用的时候实例化自己
public class Singleton {
//1.初始化为null私有的静态自身引用
private static Singleton single=null;
//2.private的构造方法
private Singleton(){
}
//3.public的静态获取方法
public static Singleton getSingleton(){
//如果当前的实例为null则创建对象
if(single==null){
single=new Singleton();
}
return single;
}
}
2) 饿汉式单例类:在类初始化时,已经自行实例化
public class Singleton1 {
//1.类加载时初始化自行进行实例化
private static final Singleton1 sin=new Singleton1();
//2.私有的构造方法
private Singleton1(){
}
//3.公有的获取方法
public static Singleton1 getSin(){
return sin;
}
}
3) 线程安全单例类:对获取方法加锁,但性能稍慢
public class SingletonSync {
private static SingletonSync sin=null;
private SingletonSync(){
}
/**对创建对象的方法加锁,保证线程安全,但性能稍慢*/
public synchronized static SingletonSync getSin(){
if(sin==null){
sin=new SingletonSync();
}
return sin;
}
}
}
4) 双检锁线程安全单例类:使用同步块并进行双重判断
public class SingletonSync {
private static SingletonSync sin=null;
private SingletonSync(){
}
/**该方法可保证线程安全下的性能问题*/
public SingletonSync getSin1(){
if(sin==null){
synchronized(sin){
if(sin==null){
sin=new SingletonSync();
}
}
}
return sin;
}
}
小故事:话说十年前,有一个暴发户,他家有三辆汽车——Benz奔驰、Bmw宝马、Audi
奥迪,还雇了司机为他开车。不过,暴发户坐车时总是怪怪的:上Benz车后跟司机说“开
奔驰车!”,坐上Bmw后他说“开宝马车!”,坐上Audi说“开奥迪车!”,你一定说:
这人有病!直接说开车不就行了?!
通过以上小故事可以看出,如果按照这种方式去设计程序是存在弊端的,为了解决这种弊端
我们可以使用工厂模式,最终解决的方案就是:暴发户直接说开车就行了.
工厂模式分为:普通工厂模式,抽象工厂模式,工厂方法模式.
如下以普通工厂模式模式(也叫普通静态工厂模式)来解决以上小故事的弊端:
1.创建一个Car接口,封装开车的方法,让老板下达统一的开车命令,而非下达开某种车命令
2.创建不同品牌的具体汽车实例类来实现Car接口,重写开车的方法
3.创建一个工厂类,本案例的核心,通过该工厂类来实例化不同品牌汽车的具体实例
重点出场:工厂类
js版
1)首先创建xmlhttprequest对象
2)使用对象调用open方法,传入三个参数,请求类型,请求地址,是否是异步请求,默认是
3)对象上绑定事件处理函数onreadstatechange,当readstate值改变时,触发readstatechange函数
4)readstate由5个值,0是未初始化,1是正在发送请求,2是请求发送完成,3是正在接收响应数据,4是接收完成响应数据
5)然后用对象调用send方法,发送请求
jQuery版
$.ajax()
用法:
$.ajax({});其中,{}表示一个对象,用来封装选项参数。 常用的选项参数如下。
url : 请求地址
type: 请求类型 (get/post)
data: 请求参数,有两种格式:
第一种: 请求字符串,比如 "username=tom&age=20"
第二种: 对象,比如 {"username":"tom","age":20}
dataType: 服务器返回的数据类型,常用的有:
text: 文本 html: 文档 json: json字符串 xml: xml文档
script: javascript脚本。
success: 当服务器处理正确,用来处理服务器返回的 数据的函数。
error:当服务器发生异常,用来处理服务器返回的数据 的函数。
async: 同步还是异步(缺省是异步)。true表示异步, false表示同步。
案例如下:
function data(){
$.ajax({url:"demo/hello.do",
type:"post",
dataType:"json",
success:function(data){
alert(data);
$("#s1").html(data);
}
});
};
load():
作用:
向服务器发送异步请求,将服务器返回的数据直接 添加到符合要求的节点之上。
用法:
$obj.load(url,[data]);
url:请求地址。
data:请求参数。同上。
案例如下:
var url="team/editUI.do"
$("#modal-dialog .modal-body").load(url,function(){
$(".modal-title").html(title);
$("#modal-dialog").modal("show");
});
另外还有:$.get(); $.post(); $.getJSON();
以$.get ()为例:
作用:$.ajax的简写方式,作用相同
用法:
$.get(请求路径,请求参数,回调函数,返回数据类型):
其中返回数据类型可选,默认ajax将根据返回的数据智能判断.
var url='note/list.do';
var param = {notebookId:id};
$.get(url, param, function(result){
if(result.state==SUCCESS){
var notes=result.data;
model.updateNotesView(notes);
}else{
alert(result.message);
}
});
JSON是一种轻量级的数据交换格式。将要交换的数据转换成一种与平台无关的数据,然后发送给接收方来处理,有解析速度快,JSON文档小等优点.
语法:
{属性名:属性值,属性名:属性值,....}
注意:
a. 属性名必须使用双引号括起来。
b. 属性值可以string,number,null,true/false,object。
c. 属性值如果是string,必须使用双引号括起来。
一种轻量级的数据交换格式,以kv键值对的形式存储,{“属性名”:属性值}
后端将对象转换为json数据,发给前端,前端将json数据,解析为js对象;
(2)分布式系统的CAP基本概念?
分布式系统的三个指标
1)Consistency 一致性--数据实时同步备份始终保持一致
2)Availability 可用性--保证每个请求不管成功或者失败都有响应
3)Partition tolerance 分区容错性--任意信息的丢失或失败不会影响系统的继续运行
三者不可得兼,要么AP,要么CP,要么AC,但是不存在CAP。
组件扫描是指容器自动扫描指定包及其子包下的所有类,如果这些类中包含指定的注解,就将这些类交给spring容器进行管理,容器创建对象,并管理对象
注:相当于配置文件当中有一个
组件扫描注解:
@Component 通用组件
@Service 业务层注解
@Controller 控制层注解
@Respository 持久层组件
@Mapper/@MapperScan(包名)在主启动类上;
后两个作用相同,都是持久层注解
需要在配置文件当中,配置组件扫描。
@RequestMapping url和控制器请求,映射注解,能够处理所有请求类型
也可以添加method属性处理特定请求。
比如:
@RequestMapping(value="/user/",method = RequestMethod.GET)
@ResponseBody 请求业务处理后数据响应注解,一般和Ajax搭配使用,返回json数据,Ajax请求结束,返回字符串本身,不执行mvc的视图解析器。
备注:如果控制层使用的是RestController注解,该注解包含了@Controller和@ResponseBody两个注解,则无需再次书写
切面 = 切入点表达式 + 通知方法
AOP(面向切面编程) 主要利用(动态代理的模式) 降低程序的耦合度,扩展业务功能方法.
也就是说,可以在不修改原代码逻辑的基础上添加新的逻辑。
通知(Advice)方式:
before: 在目标方法执行之前执行
afterReturning: 在目标方法执行之后返回时执行
afterThrowing: 在目标方法执行之后,抛出异常时执行
after: 无论程序是否执行成功,都要最后执行的通知
around: 在目标方法执行前后 都要执行的通知(完美体现了动态代理模式)
功能最为强大 只有环绕通知可以控制目标方法的执行
关于通知方法总结:
1.环绕通知是处理业务的首选. 可以修改程序的执行轨迹
2.另外的四大通知一般用来做程序的监控.(监控系统) 只做记录
切入点:
1)使用注解做为切入点 @annotation(包名.注解名)
2)使用execution(访问权限 返回值类型 包名.类名.方法名(参数列表)) 万能切入点表达式,可以使用*进行代替
3)bean(“bean的ID”) 根据beanId进行拦截 只能匹配一个
4)within(包名.类名)可以使用通配符*? 能匹配多个
AOP是面向横切面编程,在不改变原有功能的情况下横向织入扩展功能代码或扩展横切功能,比如:在原有项目上扩展新的模块,统一记录日志、事务,安全验证等.
SSM配置: <aop:aspectj-autoproxy/>
SpringBoot只需导入jar包即可
需要再切面类上添加@Aspect
AOP中的创建术语:
@Before("execution(public void cn.tedu.XiaoMing.morning())")
public void bus() {
System.out.println("我是前置通知,在执行moring方法之前先执行我的逻辑");}
其中Around(环绕通知)可以替代其他Before和After通知,必须结合ProceedingJoinPoint程序连接点使用,调用proceed()执行连接点方法
@Around("execution(public void cn.tedu.XiaoMing.noon())")
public void tetsAround(ProceedingJoinPoint point) throws Throwable {
System.out.println("放学回到家");//在连接点目标方法之前切入
point.proceed();//调用连接点方法
System.out.println("睡了个午觉~~");//在连接点目标方法之后切入
}
比如上面案例:通知使用的Before,并且切入的是morning(),那么连接点就是在morning()方法
案例:通过JoinPoint可以获取连接点的相关信息
@Before("execution(public void cn.tedu.XiaoMing.morning())")
public void washface(JoinPoint join) {
//JoinPoint是连接点
String name=join.getSignature().getName();
System.out.println("连接点的方法名是:"+name);
}
@Before("execution(public void cn.tedu.XiaoMing.morning())")
"execution(public void cn.tedu.XiaoMing.morning())"就是切入点,表示切入到morning方法前执行.
以上切入点是写死固定的只能匹配一个方法,还可以使用对应的表达式模糊匹配:
execution(* *(..)):表示匹配所有方法
execution(public * cn.tedu.service.UserService.*(..)):
表示匹配cn.tedu.service.UserService中所有的公有方法
execution(* cn.tedu.server..*.*(..)):
表示匹配cn.tedu.server包及其子包下的所有方法
切入点的其他分类:
备注:在写切入点的使用可以先声明切入点方法使用@PointCut()写入切入点表达式,然
后在通知里写入切入点方法名,也可以直接把切入点表达式写入通知里
@Aspect
@Component
public class GoodHabit {
@Before("execution(public void cn.tedu.XiaoMing.morning())")
public void washface(JoinPoint join) {
//JoinPoint是连接点
String name=join.getSignature().getName();
System.out.println("连接点的方法名是:"+name);
}
@After("execution(public void cn.tedu.XiaoMing.morning())")
public void bus() {
System.out.println("7点出门做公交去学校");
}
}
OOP是什么:oop 是面向对象编程,面向对象编程是一种计算机编程架构,OOP 的一条基本原则是计算机程序是由单个能够起到子程序作用的单元或对象组、合而成。
OOP有什么特性:(共五点)1. 类,2.对象,
3、封装性:也称为信息隐藏,有效避免程序间相互依赖,实现代码模块间松藕合。
4、继承性:继承增加了代码的可重用性。PHP 只支持单继承,也就是说一个子类只能有一个父类。
5、多态性:多态性增强了软件的灵活性。
使用OOP用什么好处:
1、易维护
采用面向对象思想设计的结构,可读性高,由于继承的存在,即使改变需求,那么维护也只是在局部模块,所以维护起来是非常方便和较低成本的。
2、质量高
在设计时,可重用现有的,在以前的项目的领域中已被测试过的类使系统满足业务需求并具有较高的质量。
3、效率高
在软件开发时,根据设计的需要对现实世界的事物进行抽象,产生类。使用这样的方法解决问题,接近于日常生活和自然的思考方式,势必提高软件开发的效率和质量。
4、易扩展
由于继承、封装、多态的特性,自然设计出高内聚、低耦合的系统结构,使得系统更灵活、更容易扩展,而且成本较低。
都能实现:权限认证,过滤方法;
拦截器是spring中的组件,在HandlerMapping之前执行,只能拦截action请求;
1.创建拦截器(Interceptor (音特色不特)),实现HandlerInterceptor接口,重写
preHandle():前端控制器调用的方法,结果为true是才能调用HandlerMapping处理器
postHandle():处理器执行完请求后返回结果之前执行,可以在该方法中设置ModleAndView对象
afterCompletion():最后执行的方法,处理处理器抛出的异常;
2.过滤器(filter(费油特)),是servlet中的组件,在servlet之前执行,可以对所有请求进行过滤
创建过滤器实现Filter接口,重写init()、doFilter()、destroy()方法,分别是初始化、过滤器逻辑、销毁过滤器的方法
过滤器是Servlet的组件,可以对所有的请求进行拦截,比如.html,.do,.mp3,.jpg等.
拦截器是Spring框架的组件,只能拦截action请求,注:action指的就是xx.do这类请求.
另外还有拦截时机的不同:拦截器,servlet和过滤器,controller同时存在的情况下,运行过程如下图:
1.#{} 表示创建的是prepareStatement,对象即sql 预编译,防止sql注入;
2.${}表示创建的是statement对象,即 sql 拼接,还需要加上单引号。
3.总结:在程序中能用#{}就不用${},不过有时你只是想直接在 SQL 语句中插入一个不改变的字符串,比如一个数据对象中的表名等,或者ORDER BY排序时可以使用${}.
select * from user where name = "dato";
select * from user where name = #{name};
select * from user where name = ${name};
#{} 在解析时会解析成JDBC中PreparedStatement预编译sql,防止sql注入:
select * from user where name = ?;
${}在解析时会解析成字符串参数,类似于JDBC中Statement sql,无法防止sql注入:
select * from user where name = "dato";
spring cloud 是一系列框架的集合。它利用 spring boot 的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用 spring boot 的开发风格做到一键启动和部署。spring cloud 并没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过 spring boot 风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。
SpringCloud的核心组件:
Eureka注册中心:
Eureka工作原理:
(90秒)无法完成续约,则注册中心会将其从注册列表中删除.(心跳检测)
删除任何注册的服务信息(自我保护)
搭建Eureak注册中心和服务提供者
1. 搭建Eureka注册中心:
eureka:
server:
#关闭自我保护 测试关闭,上线开启
enable-self-preservation: false
instance:
# eureak名字
hostname: eureak1
client:
# 不向自身注册 单台false 集群true
register-with-eureka: false
# 不从自身拉取注册信息 单台false 集群true
fetch-registry: false
2. 搭建服务提供者向注册中心注册
1)导入Eureakk客户端jar包
2)添加配置
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka
3)在启动类上添加注解 @EnableDiscoveryClient
4)启动注册中心和服务提供者测试注册服务
配置Eureka的高可用:
eureka:
instance:
# eureak名字
hostname: eureak1
client:
# 不向自身注册
register-with-eureka: true
# 不从自身拉取注册信息
fetch-registry: true
service-url:
defaultZone: http://eureka2:2002/eureka
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
面试题:eureka和zookeeper的区别?
eureka是强调AP可用性的注册中心,集群是对等结构
zookeeper是强调CP一致性的注册中心,集群是主从结构
Ribbon 负载均衡/重试
Ribbon解决的是服务之间的调用问题并且能够解决负载均衡问题和系统容错重试的问题,底层是使用SpringBoot提供的RestTemplate(远程调用)相关的API实现的.
RestTemplate提供的常用方法:
getForObject():执行get请求
postForObject():执行post请求
注:Ribbon不需要单独下载jar包,Eureka客户端jar包里包含了Ribbon
负载均衡
Ribbon负载均衡配置:
@LoadBalanced注解实现负载均衡,默认轮询
@Bean
@LoadBalanced
public RestTemplate getRt() {
return new RestTemplate();
}
件中的spring:application:name: item-service比如:
http://item-service/8
重试
重试是Ribbon的容错机制,当请求到后台出错或者服务器故障则自动向其他的服务器重试服务.
重试的配置:
ribbon:
MaxAutoRetriesNextServer: 2 #更换服务器的次数
MaxAutoRetries: 1 #当前服务器重试次数
OkToRetryOnAllOperations: true #默认get请求重试,true所有请求
@LoadBalanced
@Bean
public RestTemplate getRestTemplate() {
SimpleClientHttpRequestFactory f =
new SimpleClientHttpRequestFactory();
f.setConnectTimeout(1000); //建立连接等待时间
f.setReadTimeout(1000); //等待响应的时间
return new RestTemplate(f);
}
Feign/OpenFeign RPC远程调用
Feign是一个声明式webService客户端,能够让RPC远程调用客户端更加简单,使用方法是定义一个服务接口然后在上面添加注解,内置了Ribbon实现负载均衡
OpenFeign是在Feign的基础上支持了SpringMVC的注解,OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务
使用步骤:
调用的服务路径
注:与Dubbo的区别就是不需要在提供者方进行设置,因为提供方的服务信息都在注册中
心注册只需在消费端使用
默认情况下Feign的调用超时时间为1秒,也可以自行设置,若调用超时可以结合
Hystrix实现降级
Hystrix 断路器
Hystrix也是一种容错机制,主要是通过服务降级和熔断进行容错.
降级:如果请求服务出错,Hystrix可以执行另外一段业务代码返回响应.
通过降级注解@HystrixCommand(=”方法名”)来指定降级方法
熔断:当一个服务出现故障,会快速断开这个故障微服务,保护其他服务不受影响
熔断条件:默认10秒20次请求,50%请求失败执行了降级代码
半开状态:断路器打开5秒会进入半开状态,尝试发送一次请求,如果请求成功则恢复正常,若请求失败,断路器继续保持打开状态,这些都不需要做设置,自动触发熔断
Hystrix断路器流程:
Hystrix配置:
注:降级方法和原请求方法的参数类型需要保持一致.
Hystrix 超时设置:
默认情况下Hystrix的超时时间是1秒,可以通过hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds配置,由于ribbon也有超时设置,默认1秒的超时会出现Hystrix执行了降级方法,此时ribbon还在进行重试即使服务器正常了也无法将正确的数据返回,所以两个超时时间应配合设置:
Hystrix的超时时间应>=ribbon的超时时间
hystrix dashboard 断路器仪表盘
仅仅是做hystrix 对请求的降级和熔断的一个监控手段,需要借助springboot提供的actuator服务监控工具暴露监控端点来实现监控
actuator监控:
management.endpoints.web.exposure.include:hystrix.stream
http://localhost:3001/actuator/hystrix.stream
hystrix dashboard:
6.访问各个服务的请求,观察断路器仪表盘的变化
Zuul 网关
zuul API 网关,为微服务应用提供统一的对外访问接口,还提供过滤器,对所有微服务提供统一的请求校验,整合了ribbon和hystrix,可以实现负载均衡和服务降级
网关接口:启动类添加@EnableZuulProxy注解,通过配置zuul.routes.服务id=服务请求路径,
配置完毕后请求时使用:
http://ip:zuul的端口/服务请求路径/资源路径
比如:zuul的端口:9627,网关配置的服务请求路径:item-service/**
http://localhost:9627/item-service/getItem
负载均衡:默认开启负载均衡并采用轮询策略
服务降级:自定义类实现实现FallbackProvider接口,重写getRoute(指定失败的微服务id),
fallbackResponse(降级逻辑方法)当getRoute设置为*或者null时是所有微服务
均执行降级方法fallbackResponse
过滤器:自定义类继承ZuulFilter类,重写filterType(过滤类型,pre前置,post后置,error
异常),filterOrder(过滤器优先级,值越小优先级越高),shouldFilter(过滤器是
否生效,true生效,false不生效) ,run(具体过滤逻辑方法)
Zuul配置:
zuul:
routes:
cloud-payment-service: /cloud-payment-service/**
#配置ribbon重试,默认未开启,需配置开启
retryable: true
3)启动类上添加注解@EnableZuulProxy
4)http://localhost:9526/cloud-payment-service/payment/get/1
Config 配置中心,统一配置文件,手动刷新
每个微服务都有自己的配置文件,维护起来很麻烦,所以一套集中式的,动态的配置管理设施是必不可少的,SpringCloud的Config组件可以解决该问题,默认采用git来存储配置文件信息
Config分为Server端和Client端
Server端:也称为分布式配置中心,一个独立的微服务应用,用来连接配置服务器并为客户端提供获取配置信息,加密/解密信息等接口
Client端:通过指定的配置中心来管理应用资源,业务相关的配置内容,在启动的时候从配置中心获取配置信息
工作原理:
ConfigServer(配置中心服务端)从远端git拉取配置文件并在本地git一份,ConfigClient(微服务)从ConfigServer端获取自己对应 配置文件;
配置流程:
在拉取到本地仓库
Bus 消息总线,动态刷新
在单独使用Config组件的时候虽然可以统一管理配置文件,但是无法实现所有服务的动态刷新,结合Bus消息总线组件可以实现动态刷新,目前仅支持RabbitMQ和Kafka两个消息中间件。
工作原理:
每次配置文件有更新时都经过消息提供者(ConfigSever或者ConfigClient)将更新信息推送给RabbitMQ消息中间件的队列Queue来保存,然后广播通知其他所有消息消费者(ConfigClient)进行各自的同步更新来实现动态刷新。
Bus有两种动态刷新机制:
1.将更新后的配置发送给其中一台客户端,由这台客户端同步到其他客户端
2.将更新后的配置发送给服务端,由服务端同步给所有客户端
但通常采用第二种:客户端本身就是用来处理单一业务功能得,不能给其分配其他更多的任务,并且破坏了服务之间的对等性。
配置过程:
curl -X POST "http://localhost:3344/actuator/bus-refresh"
#rabbitmq相关配置
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
#rabbitmq相关配置,暴露bus刷新配置的端点
management:
endpoints:
web:
exposure:
include: 'bus-refresh'
注:如果想单点更新可以在发送POST请求时指定对应服务名字和端口
curl -X POST "http://localhost:3344/actuator/bus-refresh/config-client:3355"
curl -X POST "http://localhost:3344/actuator/bus-refresh/
config-client:{3355,3366}"
1)该模块是解决用户什么问题的?
2)牵涉到了那些数据库相关表,表里有哪些主要字段,多表的情况下表之间的关系?
3)项目中都用到了那些技术?每个技术都在请求流程中哪些环节生效?
4)从请求发起时以一个完整的流程把相关技术和业务穿插到该请求中?
Nginx是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务,主要用于负载均衡和反向代理. C语言开发,服务内存占用不超过3M,并发能力强,测试数据5万/秒,实际测试:2-3万/秒,开源免费.
一般情况下 正向代理和反向代理都会使用. 正向服务实现网络通讯,反向负责获取服务器数据.
正向代理:正向代理的典型用途是为在防火墙内的局域网客户端提供访问Internet的途径。
反向代理:反向代理服务器通常可用来作为Web加速,来降低网络和服务器的负载,提高访问效率。
总结:
正向代理是客户端代理,反向代理是服务端代理
正向代理,服务器不清楚真实的用户是谁.认为代理服务器就是用户,反向代理,用户不清楚真实的服务器是谁.认为代理服务器就是目标服务器.
正向代理 保护的是真实的用户.对于服务器而言屏蔽真实的用户信息,反向代理 保证的是后台的全部的服务器. 对于用户而言屏蔽服务器相关信息
1.Redis【集群规则、分片机制、缓存】;
Redis集群?
Redis哨兵虽然可以实现Redis的高可用,但是哨兵本身没办法实现高可用,程序调用存在风险,我们需要搭建集群来实现高可用.
Redis哨兵机制?
集群的工作原理:
1)集群中所有点都会保存集群中全部主从关系的信息并且所有节点之间可以互相通信.
2)定时向其他节点发送ping pong心跳检测,若某主机无法回应超一半以上则该主机宕机
3)剩余主机重新选举宕机主机的从机变为主机(从机只有判断宕机的投票权没有选举权)
4)此时新主机没有从机,若其他主机有可用从机借用其他主机的从机作为自己的从机
5)若宕机后无法借用也无法在推举新的主机发生主机数量减少则集群崩溃
哨兵机制是为了解决Redis分片存在的无法高可用的问题,因为如果redis分片的节点有一个服务器宕机,则直接影响用户的使用.
Redis分片机制?
单台Redis的内存大约是10M左右,若需要保存的缓存数据特别大,单台不够用,那么我们可以准备多台Redis来实现扩容.
Redis的缓存穿透,缓存雪崩,缓存击穿以及解决方案?
reids缓存的执行流程:
正常的使用缓存流程:数据查询先进行缓存查询,如果key不存在或者key已经过期,再对数据库进行查询,并把查询到的数据,放进缓存。如果数据库查询数据为空,则不放进缓存。
!!!!!!!!!!!!!!!缓存穿透
说明: 在高并发的条件下,用户频繁访问<一个不存在的数据>.导致大量的请求直接发往数据库.导致服务器宕机.
解决方案:
1. 只要能够保障用户访问的数据 数据库中一定存在. 布隆过滤器
2. IP限流 黑名单. 微服务中可以通过API网关进行控制,设置空值。
!!!!!!!!!!!!!!!缓存击穿
说明: 在高并发条件下 <用户频繁访问一个热点数据>. 但是该热点数据在缓存中失效.导致用户直接访问数据库.
俗语: 称它病,要它命
解决方案:
异步定时更新,
互斥锁:就是当Redis中根据key获得的value值为空时,先锁上,然后从数据库加载,加载完毕,释放锁。若其他线程也在请求该key时,发现获取锁失败,则先阻塞。
!!!!!!!!!!!!!!!!缓存雪崩
说明: 在高并发的条件下, <有大量的缓存同时过期或缓存服务宕机>. 导致redis缓存服务器命中率太低.从而导致用户直接访问数据库.
主要问题: 热点数据失效.
解决方案:
1.为热点数据设定超时时间时 采用随机数. 10秒+随机数 保障数据不会同时失效.
2. 设定多级缓存
布隆过滤器介绍?
布隆过滤器(Bloom Filter)是1970年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都比一般的算法要好的多,缺点是有一定的误识别率和删除困难
Redis内存优化策略?
Redis的缓存数据都在内存中,若数据量越来越大,则内存压力也会越来越大,甚至出现内
存溢出,因为我们需要将不使用的数据进行淘汰.
LRU算法:按照时间维度,将时间特别久最近使用少的数据进行淘汰。
LFU算法:按照引用计数的次数将最少引用的数据进行淘汰,最少引用次数是将引用计数
寄存器定时向右移一位,形成指数衰减的平均使用次数。
是一个轻量级的安全框架,主要提供了 授权、认证、加密、会话管理这几个功能。
Shiro运行流程
比如一个登陆流程:
1、首先调用Subject.login(token)进行登录,他会委托给SecurityManager
2、SecurityManager负责真正的身份验证逻辑;它会委托给Authenticator进行身份验证;
3、Authenticator会把相应的token传入Realm,从Realm获取身份验证信息,如果没有就返回认证失败,有的话就继续执行操作。
Shiro 的优点
简单的身份认证, 支持多种数据源
非常简单的加密 API
对角色的简单的授权, 支持细粒度的授权(方法级)
支持一级缓存,以提升应用程序的性能;
内置的基于 POJO 企业会话管理, 适用于 Web 以及非 Web 的环境
不跟任何的框架或者容器捆绑, 可以独立运行
简述 Shiro 的3个核心组件
1.Subject
正与系统进行交互的人, 或某一个第三方服务。
所有 Subject 实例都被绑定到一个SecurityManager 上。
2.SecurityManager
Shiro 架构的心脏, 用来协调内部各安全组件, 管理内部组件实例, 并通过它来提供安全管理的各种服务.
当 Shiro 与一个 Subject 进行交互时, 实质上是幕后的 SecurityManager 处理所有繁重的 Subject 安全操作。
3.Realms
本质上是一个特定安全的 DAO. 当配置 Shiro 时, 必须指定至少一个 Realm 用来进行身份验证和授权.
Shiro 提供了多种可用的 Realms 来获取安全相关的数据. 例如关系数据库(JDBC), INI 及属性文件等.
可以定义自己 Realm 实现来代表自定义的数据源。
如何配置在 Spring 中配置使用 Shiro
1、在 web.xml 中配置 Shiro 的 Filter
2、在 Spring 的配置文件中配置 Shiro
3、配置自定义 Realm:实现自定义认证和授权
4、配置 Shiro 实体类使用的缓存策略
5、配置 SecurityManager
6、配置保证 Shiro 内部 Bean 声明周期都得到执行的 Lifecycle Bean 后置处理器
7、配置AOP 式方法级权限检查
8、配置 Shiro Filter
MyCat是一个开源的分布式数据库系统,是一个实现了MySQL协议的服务器,前端用户可以把它看作是一个数据库代理,用MySQL客户端工具和命令行访问,而其后端可以用MySQL原生协议与多个MySQL服务器通信,也可以用JDBC协议与大多数主流数据库服务器通信,其核心功能是分表分库,即将一个大表水平分割为N个小表,存储在后端MySQL服务器里或者其他数据库里。
所以可以这样理解:数据库是对底层存储文件的抽象,而Mycat是对数据库的抽象。
Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,
不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。
Vue的优点?
Vue 可以实现前后台分离开发,节约开发成本
并且Vue是中国人开发的,官方文档是中文,学习理解更轻松
Vue.js 的核心是一个允许采用简洁的模板语法来声明式的将数据渲染进 DOM,初始化根实例,vue自动将数据绑定在DOM模板上
声明式渲染与命令式渲染区别?
声明式渲染:所谓声明式渲染只需要声明在哪里,做什么,而无需关心如何实现
命令式渲染:需要具体代码表达在哪里,做什么,如何实践
API就是应用程序编程接口,在不同场合,这个编程接口的含义不同。
是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节
说得更加通俗易懂一些,别人写好的代码,或者编译好的程序,提供给你使用,就叫做API。你使用了别人代码(或者程序)中的某个函数、类、对象,就叫做使用了某个API。
各种编程语言自带的标准库其实也是API。这些API由编程语言的开发者们编写,安全、高效、健壮,为我们实现了常见的功能,让我们不用再重复造轮子。
1)运行在客户端浏览器中的,每一个浏览器都有javascript的解析引擎
2)脚本语言:不需要编译,直接就可以被浏览器解析执行
功能:可以用来增强用户和html页面的交互过程,可以来控制html元素,让页面有一些动态的效果,增强用户体验。
javascript:一门客户端脚本语言
JavaScript 是一种轻量级的编程语言。
JavaScript 是可插入 HTML 页面的编程代码。
JavaScript 插入 HTML 页面后,可由所有的现代浏览器执行。
JavaScript 被数百万计的网页用来改进设计、验证表单、检测浏览器、创建cookies,以及更多的应用。
这门语言可用于 HTML 和 web,更可广泛用于服务器、PC、笔记本电脑、平板电脑和智能手机等设备。
函数是由事件驱动的或者当它被调用时执行的可重复使用的代码块。
Jscript 支持两种函数:一类是语言内部的函数,另一类是自己创建的。
JavaScript 函数允许没有参数(但包含参数的小括号不能省略),也可以向函数传递参数供函数使用。
单点登录SSO(Single Sign On)就是在一个多系统共存的环境下,用户在一处登录后,就不用在其他系统中登录,也就是用户的一次登录能得到其他所有系统的信任。,包括单点登录与单点注销两部分
实现方法是哪三种?
1.以Cookie作为凭证媒介
最简单的单点登录实现方式,是使用cookie作为媒介,存放用户凭证。
用户登录父应用之后,应用返回一个加密的cookie,当用户访问子应用的时候,携带上这个cookie,授权应用解密cookie并进行校验,校验通过则登录当前用户。
坏处?
***Cookie不安全
***不能跨域实现免登
2.通过JSONP实现
对于跨域问题,可以使用JSONP实现。
用户在父应用中登录后,跟Session匹配的Cookie会存到客户端中,当用户需要登录子应用的时候,授权应用访问父应用提供的JSONP接口,并在请求中带上父应用域名下的Cookie,父应用接收到请求,验证用户的登录状态,返回加密的信息,子应用通过解析返回来的加密信息来验证用户,如果通过验证则登录用户。
坏处?
***Cookie不安全
3.通过页面重定向的方式
最后一种介绍的方式,是通过父应用和子应用来回重定向中进行通信,实现信息的安全传递。
父应用提供一个GET方式的登录接口,用户通过子应用重定向连接的方式访问这个接口,如果用户还没有登录,则返回一个的登录页面,用户输入账号密码进行登录。如果用户已经登录了,则生成加密的Token,并且重定向到子应用提供的验证Token的接口,通过解密和校验之后,子应用登录当前用户。
好处是:
这种方式比较前面两种方式,解决了上面两种方法暴露出来的安全性问题和跨域的问题,但是并没有前面两种方式方便。
安全与方便,本来就是一对矛盾。
背景:
为安全考虑,浏览器会对脚本中的请求进行同源策略检查,跨域XHR 请求时,被请求服务的请求头必须设置Access-Control-Allow-Origin 头等。但对于css、script 文件的引用等,是允许跨域的,也正如此,平常的开发中可在html 头部通过或