个人纯手工打造,大佬多多关照,谢谢了!
java面试重点(二)
目录
https://blog.csdn.net/eaphyy/article/details/71190441 Mybatis地址............................... 50
面试关隘
- 会写不会说
- 同样一个问题,换个问法就不会。
- 越简单越不会
- Html是什么 超文本标记语言 HyperText Markup Language
- Css是什么 层叠样式表 Cascading Style Sheets
- …
Java SE部分:
- 面向对象与面向过程的区别?
面向过程的语言(c)是把问题分解为一个一个的步骤,然后使用函数来封装每一个步骤的功能,最后用一个一个函数的调用的过程来解决问题。
面向对象会先从问题领域中抽象出实体,然后使用封装、继承、多态这些特性来提高代码的重用性,扩展性等等特性…., 对象和对象之间是通过调用方法来运作的。
- 面向对象思想的特点?
封装:
·对外隐藏复杂,暴露简单的使用方法;
·提高代码重用性;
·隔离变化(下层代码变了,上层不影响);
·保护数据
继承: 提高代码重用性;是多态的前提
多态:
·多态的前提--继承
·多态的体现--向上转型(任何向上转型都体现了多态)
·多态的好处--提高代码扩展性
·多态的限制--向上转型发生时,子类独有的方法无法使用(唯一限制)
============================================================
方法重载: 在同一个类中,有多个方法同名,参数列表不同,构成方法重载。
参数列表的不同,指的是:数量 类型 顺序的不同!
方法重写: 在子类和父类中,出现了具有相同返回类型、相同方法名、相同参数列表的方法时,构成方法重写! 比父类抛出的异常范围小,方法修饰词范围大于等于父类。
- final、finalize、finally的区别?
final修饰变量,必须初始化,初始化后不能被修改;
修饰方法,方法不能被重写;
修饰类,类不能被继承。
finalize(不是垃圾回收机制)当一个对象的引用次数为0时,该对象成为垃圾,gc(Java垃圾回收期)会在一个不确定时间将该对象回收,在即将回收之前,gc调用finalize方法,该方法用于释放该对象占的其他内存。
finally 用于try或者try catch 之后,finally中的代码都会执行(例外:守护线程中的try块的finally未必执行)
守护线程:举例:唐僧师徒--一旦唐僧死了,徒弟们就散伙了
main方法是主线程,一旦主线程main方法执行完毕,只剩守护线程了,守护线程就会停止。
- short s=1; s = s + 1; 对不对,如果错,错在哪里?
错 1默认是int型,int型和short型相加是int,不能放入short
Short s=1; s+=1; 这个没错,会强转
- 描述你对抽象类的认识。
·Abstract修饰;
·不能被实例化;
·可以有抽象方法和普通方法;
·抽象方法就是被abstract修饰的方法,并且没有方法体,只能存在于抽象类中;
·抽象类的抽象方法在非抽象子类中必须得以实现
·final不能修饰抽象类
·final、static不能修饰抽象方法
·抽象类的作用就是为了被子类继承,提高代码重用性
- 描述你对接口的认识。
语法角度:
·接口的所有属性默认被public static final修饰;
·所有方法默认被public abstract修饰(也都是必须的);
·接口没有构造器;
·没有构造代码块;
·不能被实例化
作用角度
·完全解耦:任何一个实现A接口的类都能实现接口的方法,任何一个类都能实现A接口;
·统一访问:接口的任何一个实现类都统一访问接口的所有方法;
·提高代码扩展性:可以给接口增加任意多个实现类
- 抽象类与接口的区别?
语法角度:
- 抽象类受到单继承的限制,接口不受单继承的限制。
- 抽象类中既可以有抽象方法,又可以有普通方法; 接口中的方法只能是抽象方法。
- 抽象类可以有构造器,也能有构造代码块,接口没有构造器,没有构造代码块。
- 接口的属性必须public static final,抽象类不用
- 接口的方法必须abstract ,抽象类不用
设计角度:
抽象类就是为了被子类继承,从而提高代码的重用性,比如模板方法设计模式。
接口主要用于设计,主要的作用有:
·完全解耦
·统一访问
·提高程序扩展性。
- 4种访问修饰符的作用?
|
private |
默认 |
protected |
public |
同一类内 |
ok |
ok |
ok |
ok |
同一包内 |
|
ok |
ok |
ok |
不同包的子类 |
|
|
ok |
ok |
处处可用 |
|
|
|
ok |
- String和StringBuffer的区别?
string长度不可变 ,每次修改都会产生新的空间;
StringBuffer 长度可变,每次修改都是在原空间修改
- StringBuffer和StringBuilder的区别?
线程安全 不安全 都是长度可变字符串
- error和exception的区别。
Err:程序错误,程序员不用处理;
exception:异常,可以处理恢复正常;
有共同父类throwable
- 运行时异常和检查型异常的区别。
Run: 运行时异常不用处理 :在运行时才会报错,编译不报错
Check:编译时异常必须处理,throws抛出异常和try-catch捕获异常
- 写出你见过的运行时异常(*)
NullPointerException - 空指针引用异常
ClassNotFoundException 类不存在异常
NoSuchMethodException 方法未找到异常
ClassCastException - 类型强制转换异常。
IllegalArgumentException - 传递非法参数异常。
SQLException - SQL异常
IndexOutOfBoundsException - 下标越界异常
IOException - 输入输出流IO异常
NumberFormatException - 数字格式异常
- java如何进行异常处理?关键字throws,throw,try,catch,finally分别代表什么意义?
Throws向上抛出异常、try-catch就地捕获异常
Throws用在方法上,后面可跟多个异常用逗号隔开;
Throw用在方法内,后面跟异常对象,只能跟一个;
Try后面可以跟多个catch,跟多个catch时,父类异常必须在子类异常之后,
finally中的代码肯定会执行,例外:守护线程中的try-catch-finally不一定
- 创建一个线程的方法。3种
·继承Thread类并重写run方法;
·实现runnable接口并重写run方法;
·线程池:
固定数量3个线程工作,第其他的不会执行。
cache这种你有多少线程执行多少
线程执行完会把线程归还到池子,过一段时间池子会把线程释放。
如何处理高并发。(*)
使用群集nginx,负载均衡,多服务器。
比如售票多开窗口,多台电脑分散服务器的压力。
线程五状态:新建、就绪、运行、阻塞、死亡
新建:新建一个线程,线程not alive
就绪:start()方法创建线程运行的系统资源,并调度线程运行run()方法。但是线程处于有资格运行,但没有获得执行权限的等待状态。线程 alive
运行:调用run()方法,线程alive
阻塞:如sleep()、wait() 等,线程alive
死亡:如stop()、线程run()方法执行完毕,线程not alive
JVM原理:
JVM是一个标准,一套规范, 规定了.class文件在其内部运行的相关标准和规范。 及其相关的内部构成。 所有的JVM都是基于栈结构的运行方式。
java类的生命周期:
加载 、连接(验证、准备、解析)、初始化,使用(对象初始化、垃圾回收、对象终结),卸载。
加载-- 获取类的二进制字节流,将类中所代表的静态存储结构转换为运行时数据结构, 最后,生成一个代表加载的类的java.lang.Class对象,
验证-- 其目的就是保证加载进来的.class文件不会危害到虚拟机本身, 且内容符合当前虚拟机规范要求, 其目的就是保证加载进来的.class文件不会危害到虚拟机本身, 且内容符合当前虚拟机规范要求
准备-- 正式为类变量分配内存,并设置类变量的初始值。这些变量都会在方法区中进行分配。
解析--将常量池内的符号引用替换为直接引用的过程。主要针对类或接口、字段、类方法、接口方法等。
初始化--加载的最后阶段, 程序真正运行的开始。
使用--
(1)对象实例化:就是执行类中构造函数的内容,如果该类存在父类JVM会通过显示或者隐示的方式先执行父类的构造函数,在堆内存中为父类的实例变量开辟空间,并赋予默认的初始值,然后在根据构造函数的代码内容将真正的值赋予实例变量本身,然后,引用变量获取对象的首地址,通过操作对象来调用实例变量和方法。
(2)垃圾收集:当对象不再被引用的时候,就会被虚拟机标上特别的垃圾记号,在堆中等待GC回收。
(3)对象的终结:对象被GC回收后,对象就不再存在,对象的生命也就走到了尽头
类卸载 -- 最后一步,程序中不再有该类的引用,该类也就会被JVM执行垃圾回收,生命结束。
一个对象的创建大概需要经过以下几步:
1`检查对应的类是否已经被加载、解析和初始化;
2`类加载后,为新生对象分配内存;
3`将分配到的内存空间初始为0;
4`设置对象的关键信息,比如对象的哈希码等;
5`然后执行 init 方法初始化对象。
线程池:
管理线程,避免创建大量的线程增加开销(降低开销);提高响应速度;
1
提交任务到线程池;
会先判断当前线程数量是否小于corePoolSize,如果小于则创建线程来执行提交的任务;否则将任务放入workQueue队列,如果workQueue没满则任务加入workQueue等待;
否则判断当前线程数量是否小于maximumPoolSize ,如果小于则创建线程执行任务;
否则就会调用handler,以表示线程池拒绝接收任务。
- sleep()和wait()的区别是什么
sleep()是thread的静态方法;wait()是Object的方法,每个对象都有;
sleep()可用在任何地方;wait()只能用在同步块中
sleep()只能释放CPU,wait()能释放CPU和占的那个锁
- 启动一个线程是用run()还是start()? .
Run()不叫启动,此方法是一个单线程
Start()启动线程
- 你对java集合框架的理解?(介绍Collection框架的结构)
Collection |--List 有顺序,能重复 |--ArrayList |--LinkedList |--Vector |--Stack 堆栈结构,先进后出,后进先出
|--Set 没顺序,不能重复 |--HashSet |--TreeSet |--LinkedHashSet 继承自hashset |
Map |--HashMap 是HashSet的底层实现 |--TreeMap 是TreeSet的底层实现
|--LinkedHashMap 是LinkedHashSet的底层实现 |
去掉一个Vector集合中重复的元素
- 通过Vector.contains()方法判断是否包含该元素,如果没有包含就添加到新的集合Vector当中,用于数据较小的情况。
- 使用HashSet协助去重,把Vector存入HashSet.
- ArrayList和Vector的区别是什么?
两者底层都是数组实现,数组在内存连续存放,因为连续,查询效率高,增删效率低;
区别:ArrayList是线程不安全的; Vectort是线程安全的;
ArrayList每次放满时增长为原来的一半;Vectort放满时增长为原来的一倍
- ArrayList和LinkedList的区别是什么?
ArrayList底层数组实现,数组在内存连续存放,因为连续,查询效率高,增删效率低;
LinkedList底层链表实现,链表在内存中是不连续,因为不连续,查询效率低,增删效率高
- Collection和Collections的区别是什么?
Collection集合框架的父接口,其下有list和set
Collections集合框架的一个工具类,里面都是静态方法,sort()排序升序()list、reverse()翻转集合元素、shuffle()随机打乱集合元素。
- HashMap和Hashtable的区别是什么?
HashMap:线程不安全;效率高;可用null作为键值和值;自JDK1.2引入的map实现;
Hashtable:线程安全;效率低;不能用null作为键值和值;继承了陈旧的dictionary类(过时了),自jdk诞生就有
- List, Set, Map是否继承自Collection接口
Map不是,map和collection并列关系,三者都是接口。
- List、Map、Set三个接口,存取元素时,各有什么特点
List:能重复,有顺序; list.add(); list.get();
Map(key value) 键值不能重复(键重复就会后盖前),值可重复;
Set :不能重复,没顺序
25.HashSet和 TreeSet 的区别?
首先都是不能重复,无顺序。
HashSet:
底层是HashMap哈希表结构;
通过重写HashCode()和 equals()方法保证元素的唯一性;
无序;
TreeSet:
底层是TreeMap 树结构存储;
通过实现Compareable接口并重写其compareTo()方法来保证元素的唯一性;
有序;
25.HashMap和 TreeMap的区别?
线程都不安全
HashMap:底层结构散列表;适用于插入、删除、查找元素;速度快
TreeMap:底层结构红黑树;适用于自然排序、或自定义顺序比遍历键key;
25.Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用==还是equals()? 它们有何区别?
Set里,先调contains()方法,看里面是否包含该元素,在比较
==是比地址,equals()是调元素的比较方法,要保证这个类重写equals()方法
- 字节流与字符流的区别
字节流:一次最少读取一个字节;字节流能操作任何文件;
字符流:一次最少读取一个字符;只能操作文本文件;把读到的字符编码解码;
不同码表字符占的字节不同,不能说以字符流一次至少读取2个字节。
- GC是什么? 为什么要有GC?
垃圾回收机制
没有GC的话程序员得自己开辟空间,用完以后还得自己手动释放空间,难免会造成内存泄漏,GC会帮助程序员在一个不确定时间回收掉闲置空间,减轻程序员负担。
- 写一个SingleTon出来 懒汉式 双重检查机制。
public class SingleTon{ private SingleTon(){ } //私有构造器 private static SingleTon st = null; // 私有静态属性 public static SingleTon getInstance(){ // 共有静态方法获得实例 if(st == null){ st=new SingleTon(); return st; } } } |
28.0 什么是锁synchronized
在java中,每一个对象都有一个内部锁,如果以方法或代码块用 synchronized 进行声明,那么对象的锁将保护整个方法或代码块,要调用这个方法或者执行这个代码块,必须获得这个对象的锁。而且,任何时候都只能有一个线程对象执行被保护的代码.
- 写一个可会产生的死锁程序出来。 synchronized嵌套。
在以下代码中,在线程th1启动后,他就获得了a的锁,同时当其休眠完毕,会申请获得b的锁,而此时,他的a锁没有放弃。
在线程th2启动后,他就获得了b的锁,同时当其休眠完毕,会申请获得a的锁,而此时,他的b锁没有放弃。
两方都握有自己的锁不放弃,而同时申请另一方的锁,所以,此时就造成了死锁。
同步:同步的就是线程和对象,将线程和对象进行绑定,获取对象的锁。
package com.edu; //死锁的实现 synchronized嵌套 // A类 class A { public void get() { System.out.println("A说:我开始启动了,B,把你的资源给我,在线等。。。"); } public void say() { System.out.println("A获得资源"); } } // ---------------------------- // B类 class B { public void get() { System.out.println("B说:我开始启动了,A,把你的资源给我,在线等。。。"); } public void say() { System.out.println("B获得资源"); } }
// 创建线程类--实现Runnable接口,重写run方法 class MyThread implements Runnable { public static A a = new A(); public static B b = new B(); public boolean flag = false;
public void run() { if (flag) { synchronized (a) { a.get(); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); }
// a锁没有释放,就获得b锁 synchronized (b) { // 此同步代码块在另一同步代码块里 a.say(); } } } else { synchronized (b) { b.get(); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); }
// b锁没有释放,就获得a锁 synchronized (a) { // 此同步代码块在另一同步代码块里 b.say(); } } } } }
class Test { public static void main(String args[]) { MyThread t1 = new MyThread(); MyThread t2 = new MyThread();
t1.flag = true; t2.flag = false;
Thread th1 = new Thread(t1); Thread th2 = new Thread(t2); th1.start(); th2.start(); } }
|
- 什么是套接字,套接字的工作原理是什么?
- 创建服务器
- 创建一个客户端去连接服务器
- 双方连接上之后,打开数据流(输出流 输入流)
- 双方通过数据流交换数据
- 关闭流
- 关闭套接字
- HTTP底层原理?
超文本传输协议,可以传递各种类型的文件,是使用最广泛的协议模式.
- 连接:Web浏览器与Web服务器建立连接,打开一个称为socket(套接字)的虚拟文件,此文件的建立标志着连接建立成功。
- 请求:Web浏览器通过socket向Web服务器提交请求。GET或POST
- 响应:Web浏览器提交请求后,通过HTTP协议传送给Web服务器。Web服务器接到后,进行事务处理,处理结果又通过HTTP传回给Web浏览器
- 关闭连接 :当应答结束后,Web浏览器与Web服务器必须断开,以保证其他Web浏览器能够与Web服务器建立连接。
31、http、https 等 常用默认端口号
HTTP服务器,默认的端口号为80/tcp(木马Executor开放此端口);
HTTPS(securely transferring web pages)服务器,默认的端口号为443/tcp 443/udp;
⑴. HTTP协议代理服务器常用端口号:80/8080/3128/8081/9080
⑵. SOCKS代理协议服务器常用端口号:1080
⑶. FTP(文件传输)协议代理服务器常用端口号:21
⑷. Telnet(远程登录)协议代理服务器常用端口:23
SQL部分
0、添加外键:
- 事务:恢复和并发控制的基本单位
4大特性:
·原子性 :事务是数据库逻辑工作单元,事务包括的所有操作,要么都做,要么都不做。
·一致性 :事务执行的结果是使数据库从一个一致性状态变成另一个一致性状态。一致性与原子性是密切相关的。
·持久性 :一个事务一旦提交,它对数据库中数据的改变应该是永久性的
·隔离性 :一个事务的执行不能被其他事务干扰。
事务的四种隔离级别:
Read uncommitted(未授权读取、读未提交)
Read committed(授权读取、读已提交)
Repeatable read(可重复读)
Serializable(序列化)
- 高级查询
- 分组查询
- 内链接
- 外连接
- 子查询
- 触发器的作用?
监听增删改动作,不能监听查询,监听时分为监听前和监听后。
- 什么是视图?
简化复杂的sql语句(封装sql语句)
权限问题(只查某几个列的权限)
- 什么是游标?
游标专门一行一行地操作结果集的!
(按条件修改:必须用游标)
修改员工的工资,工资低于1000的加500,工资高于3000的减100,其余的不变。这类问题必须用游标。
- 什么是存储过程?
封装PL代码
- NULL表示什么?如何以NULL作为条件?
不知道, where sex is NOT NULL / IS NULL
- 什么是主键?什么是外键?
主键:唯一标致表中每行数据(不能重复,非空 一张表可以有一个主键)。
外键:外键列依赖于外表的主键(一张表可以有无数个外键)。
- 什么是相关子查询? 0 子查询的条件使用到了外表的列的值
- 什么是索引,索引有什么作用?
索引就是一种排序结构。
索引的作用:就是为了提高查询速度。
- 联合主键的作用是什么?
把一个主键同时加在多个列上,还是一个主键。
作用:确定一条记录的唯一性。
12.手写ajax原生代码
流程:
1.创建XMLHttpRequest对象
2.指定响应函数
3.打开连接(指定请求)
4.发送请求
5.创建响应函数
var req= XMlHttpRequest( ); //声明一个变量,用来实例化XMLHttpRequest对象
req.open(“get”,”….”); // 打开连接(指定请求)
req.onreadystatechange=function() { // 指定-创建响应函数StateChange
if(req.status == 200 && req.readyState==4) {
//… 修改dom树
}
}
req.send(); // 发送请求
var req = XMLHttpRequest(); req.open(“get”,”请求地址”); req.onreadystatechange = function(){ //… 修改dom树 } } req.send(); |
- 手写jdbc
public static void main(String[] args) throws Exception { Class.forName("com.mysql.jdbc.Driver"); Connection conn = null; try { conn = DriverManager.getConnection( "jdbc:mysql://@localhost:3306/test?characterEncoding=utf8", "root", "123456"); String sql = "insert into users values (null,?)"; PreparedStatement ps = conn.prepareStatement(sql); ps.setString(1, "admin"); ps.executeUpdate(); } catch (Exception e) { throw new RuntimeException(e); } finally { try { conn.close(); } catch (Exception e2) { throw new RuntimeException(e2); } } } |
http部分:
MVC部分:
- MVC是什么?
M: model 模型, 用于封装数据,处理数据
V: view 视图,用于收集和展示数据。
C: controller控制器, 用于接受数据,并且使用模型来处理数据,根据处理数据的结果的不同,跳转到不同的视图。
在B/S架构中,模型就是service+dao+javabean
在C/S架构中,模型就是javabean,javabean除了封装数据以外,还提供了操作数据的方法!
- Servlet的生命周期: 运行特点:单例、多线程-线程不安全
|
如果为Servlet配置添加了load-on-startup,就会在web服务器启动的时候,就实例化Servlet
- 过滤器的生命周期
3.在过滤器每次拦截到一个请求的时候,都会调用Filter的doFilter方法。 4. 在即将卸载web应用的时候,会先调用Filter的destroy方法,该方法在整个Filter 生命周期之间,只执行一次。 |
四、九大内置对象是什么,以及他们的作用?
pageContext request session application 四大范围+ out response exception page config |
pageContext:
-
-
- 页面范围,在该范围中设置的数据,只能在同一个页面中获取
- 通过该内置对象,可以获取其他8个内置对象。
-
request
- 请求范围,从客户端向服务器发起请求开始,到服务器对客户端进行响应为止,算一次请求范围! 只有转发才能延长请求范围。
- 封装客户端发送给数据库的所有数据。
Session
- 会话范围。从客户端打开一个网站的任何一个页面开始,到关闭了该网站的所有页面为止,算一个会话范围。在会话范围中一般存储登录信息!
Application
- 应用范围,从部署一个web应用开始,到卸载该web应用为止,算一次应用范围。
- 一般很少在应用范围中存放数据! 因为应用范围与整个web应用生命周期想用,但凡给application中存入什么数据,该数据都会一直驻留在内存中,直到web应用被卸载! 这样太伤内存了!
- 在ssh或ssm项目中,Application中往往储放spring ioc容器。
Out:
- 是一个字符输出流,起点:服务器,终点:客户端。
- 负责把html字符串发送给客户端浏览器。
response: 服务器端响应容器
- 封装服务器发送给浏览器的所有数据。
- 经常使用该对象的redirect进行重定向 response.sendRedirect( ) ;
Exception:
- 默认情况下,无法使用该对象,必须加入<%@ page isErrorPage=”true” %>
- 该对象中存放了上一个页面中的异常信息!
page:
- 代表当前servlet本身,就是把this赋值给了page
config:
- 用于获取在web.xml中配置的初始化参数。config.getInitParameter(“param”);
五、静态包含与动态包含的区别?
1. 静态包含是先包含,后编译(只有一个字节码生成),
动态包含是先编译,后包含(有多个字节码生成)所以静态包含速度快,动态包含速度慢。
2. 静态包含不能以变量作为路径,动态包含就可以!
3. 静态包含不能给被包含的jsp页面传递参数, 动态包含就可以!
4. 在一个jsp页面中如果静态包含了多个页面,这些页面之间变量不能重名,动态包含就可以!
六、4大范围是什么?(页面间传递数据的方法?)
pageContext:
-
-
- 页面范围,在该范围中设置的数据,只能在同一个页面中获取
- 通过该内置对象,可以获取其他8个内置对象。
-
request
- 请求范围,从客户端向服务器发起请求开始,到服务器对客户端进行响应为止,算一次请求范围! 只有转发才能延长请求范围。
- 客户端发送给数据库的所有数据,统统都被封装在request对象之中。
Session
- 会话范围。从客户端打开一个网站的任何一个页面开始,到关闭了该网站的所有页面为止,算一个会话范围。在会话范围中一般存储登录信息!
Application
- 应用范围,从部署一个web应用开始,到卸载该web应用为止,算一次应用范围。
- 一般很少在应用范围中存放数据! 应为应用范围与整个web应用生命周期想用,但凡给application中存入什么数据,该数据都会一直驻留在内存中,直到web应用被卸载! 这样太伤内存了!
- 在ssh或ssm项目中,Application中往往厨房spring ioc容器。
在页面之间传递数据的方式有:request session application,使用原则是,能用小的就别用大的,这样就能节省内存空间。
七、会话追踪的4种方式?
因为http是无状态的连接协议,每次客户端请求之后,一旦服务器响应完毕,就会断开拦截,服务器为了区分哪些请求都是来自于哪些客户端的,就必须会话追踪!
- Cookie
- 有一个名字叫做jsessionid的cookie, 是由服务器自动发送给客户端的,只要客户端的请求中没有携带jsessionid这个cookie,服务器就会创建出该cookie,并且一式两份,一份留在web服务器内存中,一份发给客户端浏览器。同一个会话中客户端以后再访问服务器时。就会自动携带jsessionid这个cookie
- url
- 当客户端禁用cookie时,就需要url重写,就是在每一个超链接之后,都“挂上”jsessionid的值,意图利用连接在同一个会话中的各个页面之间传递jsessionid。
- 这需要使用response.encodeURL(“/a.jsp”); à a.jsp;jsessionid=12321321321321
- 隐藏域
- 在表单提交时,input标签属性使用hidden隐藏,通过隐藏域也传递jsessionid
- session
使用 setAttribute(String str,Object obj)方法将对象捆绑到一个会话
Session是依赖Cookie的,如果Cookie被禁用,那么session也将失效
此时可以考虑URL重写和表单隐藏域。
session默认的会话时长为30分钟
八、转发和重定向的区别是什么?
转发:服务器端跳转;浏览器地址栏不变;延长了request请求范围;转发后两页面request相同。
重定向:与转发相反
当一个控制器需要给视图传递数据时,一般是把数据存入去请求范围中,然后再转发!
如果没有任何数据需要带给视图,再控制器中就应该使用重定向。
注意,在java源文件中,转发的写法是:
<% RequestDispatcher rd = request.getRequestDispatcher("/a.jsp"); rd.forward(request, response); %> |
- get和post的区别是什么?
1. get会将请求参数显示在url后面;post会把请求参数放在请求体中
2.get方式只能传递少量数据;post能够传递大量数据,当需要做文件上传功能时,只能使用post提交方式!
3.在http协议中,get请求方式的本意是用来查询数据的;post的本意是用来增加数据的.
十、JSP运行原理?
常见的服务器响应码:
200 : 表示响应成功!
404: 表示访问的资源不存在
302: 表示让客户端去请求别的资源(必须要搭配响应头中的location)
500: 表示服务器内部有错误(往往是程序有错!)
304: 表示告诉浏览器,使用缓存。
405:服务器不支持该请求的方式: 请求方式有get 有post,
如果请求方式是xyz,abc.. 服务器就会响应401
十一、写出5个session的方法(写出5个request的方法)
session.setAttribute("aa", "123"); session.getAttribute("aa"); session.removeAttribute("aa"); session.getId(); session.isNew(); session.getServletContext(); session.invalidate(); session.getCreationTime(); session.getLastAccessedTime(); |
request.setAttribute("aa", "123"); request.getAttribute("aa"); request.removeAttribute("aa"); request.getParameter("aa"); request.getParameterValues("hobby"); request.getParameterNames(); request.getSession(); request.getRequestURI(); request.getRequestURL(); request.getRealPath("/upload"); |
十二、如何现实servlet的单线程模式? (这个问题应该这样问,如果保证servlet中service的同步) (servlet默认是单实例,多线程,线程不安全)
先回顾Servlet运行原理。
我们开发了很多web应用程序,发现从来没有管理过线程的问题。其实这是因为web服务器已经帮我们管理线程了! 怎么管理的呢?? 如下图所示!!
那么就有一个问题: 如果两个客户端同一时刻请求同一个servlet,那么就有2个线程,同时要执行同一个servlet的service。 而这2个线程之间是抢占cpu的,也就是说2个线程会互相从中间打断对方(这叫做线程不安全)!
问题:
现实servlet的单线程模式?
答: 为了让多个线程,在同时执行service时,保证线程安全,需要添加同步块! 同步块的锁使用的就是当前servlet实例的锁。只需要给我们希望保证同步的那一段代码添加同步即可!
十三、你是如何解决web应用中的中文乱码的?
造成乱码的原因,一定是编码时采用的码表,与解码时采用的码表不一致。
- 当请求方式为get时:
String username = request.getParameter("username"); String password = request.getParameter("password");
username = new String(username.getBytes("iso-8859-1"),"utf-8"); password = new String(password.getBytes("iso-8859-1"),"utf-8"); |
- 当请求方式为post时:
此时请求参数会被存入请求体中,而request使用的默认编码表为iso-8859-1, 我们需要设置为与表单编码一致的编码表:
request.setCharacterEncoding("utf-8"); 这行代码仅仅只能控制请求体中的请求参数!
所以这种方式无法处理get请求方式提交的参数!!
因为get提交方式会把请求参数存入URL中,不会存入请求体中。
- 为了保证一站式解决全站的乱码问题,我们要保证每个表单,以及每个ajax请求的提交方式都是post,且制作一个过滤器,拦截所有请求,在该过滤器中先设置request的编码方式,然后在无条件放行。
response.setContentType("text/html;charset=utf-8");
十四、javabean有什么特点?
Javabean就是一个普通的java对象(POJO), 只不过该对象所属的类要符合以下规则:
- 属性私有化
- 提供公共的getter和setter方法
- 提供公共的无参构造器
- 实现序列化接口serializable
public class Student implements serializable { public Student ( ){ }
private String name;
public string getName(){ return name; } public void setName(String name){ This.name = name; } } |
- 你对数据库连接池的理解?
- 没有数据库连接池的时候
- 每次需要一个数据库连接时,都需要立刻创建数据库连接
- 每次需要关闭一个数据库连接时,都会立刻将连接释放
- 因为创建和释放数据库连接是需要很大的时间性能代价的,所以没有数据库连接池将会拖慢整个web应用的速度!
- 有了数据库连接池的时候
在web服务器启动的时候,就会提前创建好指定数量的连接到连接池中。
-
- 每次需要一个数据库连接时,都需直接从连接池中取出一个提前创建好的连接
- 每次需要关闭一个数据库连接时,不会释放连接的内存空间,而是把连接归还到连接池中。
- 这样就省去了创建数据库连接与释放数据库连接的时间,提高了web应用的性能!
- JSP与Servlet的区别?
JSP本质上就是一个Servlet。 牵扯出jsp运行原理。原理中生成的class文件就是servlet。
- JSP就是一个草稿文件,所有JSP中的语法,最终都会被解析为java的语法格式。
- 在MVC架构中,JSP充当视图,Servlet充当控制器。
因为JSP的强项就是展示和收集数据。而Servlet的强项是处理数据。
Struts2部分:
Struts2流程:
Struts2值栈:
其实就是OgnlValueStack,里面分为两个区,root区和context区
root区继承了ArrayList,所以为list类型。
存放对象:栈顶是每次请求的Action对象,下面是DefaultText。
context区是map类型,key-value形式存放数据
存放对象:map类型web资源(request,session,application,parameters,attr)、原生web资源、值栈本身、与action运行相关。
值栈取值方式:
root区取值方式:[索引].属性-----表示从该索引开始往下找,第一个数组里没找到该属性就到下一个数组去找。
Eg: <s:property value="[0].username"/>
context区取值方式:#key.key/属性
Eg: <s:property value="#session.sessionMap"/>
- 简述 Struts2 的工作流程(struts2的工作原理, 谈谈struts2)
1. 客户端发起一个请求,该请求会先被其他过滤器拦截,最终进入struts2的过滤器中。
2. struts2的过滤器拦截到一个请求,会判断该请求后缀是不是一个struts2要求的后缀,如果不是,就放行。
3.如果是一个struts2的请求,struts2框架就会创建一个ActionProxy对象,该对象读取struts2的主配置文件。
4.struts2的主配置文件主要用来分发请求。如果找不到对应的Action的目标方法,就报错,如果找到了就会先经过层层拦截器(默认18个),最后进入目标方法。
5.目标方法返回一个逻辑视图名。Struts根据逻辑视图名找到真正的物理视图。
6.再出层层拦截器,最后向客户端发送响应数据。
- Struts2的Action生命周期(struts1和struts2 action的区别)多实例、单线程 安全
1. 在客户端每一次请求一个Action的时候,都会实例化Action。
2. 在实例化之后,就直接调用Action的方法。
3. 在服务器向客户端响应的时候,Action就释放了空间。
(request Action 值栈 上下文 :同生共死。)
struts1和struts2 action的区别: struts1中只会实例化一个action的实例; 单例 struts2中针对于每一次请求,都会实例化一个action。 多例 所以struts1的action是线程不安全。 而struts2的action是线程安全的! |
- Struts2 拦截器 和 过滤器 的区别
- 拦截器只能拦截对action的请求,过滤器可以拦截所有请求。 拦截对象
- 在一次Action生命周期中,拦截器可以执行多次,过滤器只能执行一次。 执行次数
- 在拦截器中可以访问ActionContext, 在过滤器中不能访问ActionContext. 访问对象
- 拦截器不依赖于Servlet api, 而过滤器依赖于Servlet api. 依赖对象
- 拦截器是基于反射机制实现的,过滤器是基于函数回调。 实现方式
- 执行顺序:过滤前--拦截前--Action处理--拦截后--过滤后。
Struts2 拦截器:
拦截器使用注意事项
①自定义拦截器的开发,推荐继承AbstractInterceptor父类。体现默认适配器模式。
②局部配置一般很少使用,推荐使用全局配置。
③自定义拦截器栈,注意拦截器的引用顺序。一般情况下,自定义拦截器放置在框架拦截器之后。
④引用了某个拦截器后,默认拦截器栈就不起作用了。
⑤拦截器对象一般是单例的。在服务器启动来创建对象
⑥拦截器只对action进行拦截,对jsp不进行拦截
⑦框架具备高度扩展性:
·扩展性 == 代理 + 拦截器
·多个拦截器执行,形成一个拦截器链。拦截器链中可以增加或减少拦截器,也可以调整拦截器的执行顺序。
⑧正常拦截器都应该调用扩展对象的invoke()方法;只有特殊情况可以不用放行。
- 为什么要使用 Struts2 (Struts2 的优点是什么)
1.基于 MVC 架构,Struts2结构清晰.
2.使用 OGNL, OGNL 可以快捷的访问值栈中的数据、调用值栈中对象的方法
3.拦截器: Struts2 的拦截器是一个 Action 级别的AOP, Struts2 中的许多特性都是通过拦截器来实现的, 例如异常处理,文件上传,验证,token信令等。拦截器是可配置与重用的。
4.支持多种表现层技术. 如:JSP、FreeMarker、Velocity等。
- Struts2 如何访问 HttpServletRequest、HttpSession、ServletContext 三个域对象 ?
1.与 Servlet API 解耦的访问方式
通过 ActionContext 访问域对象对应的 Map 对象
通过实现 Aware 接口使 Struts2 注入对应的Map对象
2.与 Servlet API 耦合的访问方式
通过 ServletActionContext 直接获取 Servlet API 对象
通过实现 ServletXxxAware 接口的方式使 Struts2 注入对应的对象
- Struts2 中的默认包 struts-default 有什么作用?
1. struts-default包是 struts2 内置的,它定义了struts2 内部众多拦截器和 Result 类型,而 Struts2 很多核心的功能都是通过这些内置的拦截器实现,如:从请求中把请求参数封装到action、文件上传和数据验证等等都是通过拦截器实现的。当包继承了struts-default包才能使用struts2为我们提供的这些功能。
2. struts-default 包是在 struts-default.xml 中定义,struts-default.xml 也是 Struts2 默认配置文件。Struts2 每次都会自动加载 struts-default.xml文件。
3. 通常每个包都应该继承 struts-default 包。
七、说出 struts2 中至少 5 个的默认拦截器
1. validation 验证框架
2. fileUpload 文件上传
3. i18n 国际化
4. params 用于将请求参数注入给同名的Action属性。
5. token 信令,防止表单重复提交
八、谈谈 ValueStack(什么是值栈)
1.ValueStack 贯穿整个 Action 的生命周期,保存在 request 域中,所以 ValueStack 和 request 的生命周期一样. 当 Struts2 接受一个请求时,会迅速创建 ActionContext,ValueStack,Action. 然后把 Action 存放进 ValueStack,ValueStack再作为ActionContext的根对象。
2. 值栈中会存入一次请求中,历经的所有Action,并且是先进后出,后进先出。
3.ValueStack 本质上就是一个 ArrayList(查看源代码得到);
4. Action会进入值栈,那么Action的属性,也会随着Action对象一起进入值栈! 我们可以通过OGNL表达式来获取值栈中的内容,不需要#号,而访问 request、session、application、attr 时,需要加#号;
5.Struts2 重写了 request 的 getAttribute 方法,所以可以使用 EL 直接访问值栈中的内容
${a} pageContext à request à 值栈 à session à application
- ActionContext、ServletContext、pageContext的区别?
1.ActionContext 是Struts2中的 API:表示当前的 Action 的上下文环境。
通过该类可以获取上下文ActionContext.getContext();
进一步还能获取值栈ActionContext.getContext().getValueStack();
还能获取与Servlet api无关的web元素。
2.ServletContext 和 PageContext 是 Servlet 的 API
-
- ServletContext就是application的类型。
- PageContext就是pageContext的类型。
十、Struts2 有哪几种结果类型 ?
1. dispatcher 转发到页面
2. redirect 重定向到页面
3. chain 转发到action
4. redirectAction 重定向到action
5. plainText 输出目的地 JSP/HTML 的源代码内容
6. json 将Action中的变量转成JSON 返回到页面,页面没有跳转
7. stream 实现文件的下载功能。
- 拦截器的生命周期与工作流程 ?
- 在每次启动web服务器的时候,都会实例化拦截器对象。
- 在每次实例化拦截器之后,都会调用init方法,该方法在整个拦截器生命周期之间只执行一次。
- 在每次拦截器拦截到请求的时候,都执行intercept方法。
- 在卸载web应用的时候,都会调用destroy 方法,该方法在整个拦截器生命周期之间只执行一次。
- 如何在 Struts2 中使用 Ajax 功能 ?
- 导入struts-json-plugin-x.x.x.jar
- 在struts.xml中配置的package要继承json-default
- 在action的result返回结果类型必须为json
- Action返回的json数据的属性与Action的属性保持一致
- 谈谈你对Struts2的理解(对以上12道题的综合。)
1.Struts2的运行原理。
2. struts2的优点。
Hibernate部分:
- 在 Hibernate 中 Java 对象的状态有哪些 ?
1.临时状态 2.游离状态 3.持久化状态
3种状态区别:
临时状态:
- 没有被session管理
- 在数据库中没有对应的记录
游离状态:
- 没有被session管理
- 在数据库有对应的记录。
持久化状态:
- 被session管理
- 在数据库中有对应的记录。
再说每个状态的对象都具有哪些特点:
临时状态:对该状态的对象属性的任何修改,都不会同步到数据库中。
游离状态:对该状态的对象属性的任何修改,都不会同步到数据库中。但是该状态的对象可以用来delete。毕竟有一个id。
持久化状态:对该状态的对象属性的任何修改,在事务提交时,都会同步到数据库中。
再说3种状态之间如何转换:
clear方法清空一级缓存里的所有对象
evict方法只清空一级缓存里的一个对象
注意,通过get、load、Query的list()、 Query的uniqueResult()获得的对象都直接是持久化状态!
二、Session的清理和清空有什么区别?(Session的flush和clear有什么区别?)
sql的执行时机:
1. 从没有OID到有OID,就会立刻执行。
2. 从有OID到有OID,就会在提交事务的时候才执行。
1.清理缓存调用的是 session.flush() 方法; 而清空调用的是 session.clear() 方法.
2.session.flush是立即执行sql语句,但不会清空一级缓存;clear是把 Session 的一级缓存置空, 但不同步更新数据库;
三、load()和get()的区别
- get是立即加载,一旦执行get方法,就会立即发送sql语句;
load 是类级别延迟加载,只有在访问了对象的非OID属性时,才会发送sql语句。
2.如果获取一个不存在的对象时,get会返回null, load会抛出一个异常: ObjectNotFoundException
3. get获取到的对象,类型就是真实类型;load获取到的对象,是一个代理对象; 该代理对象的类是真实类型的子类。
追问:如何禁用延迟加载:
方法1: 使用final修饰实体类。
方法2: hbm.xml映射文件class元素中,添加一个属性lazy=”false” (推荐)
在需要禁用懒加载的实体对象的配置文件中配置lazy="false";
四、Hibernate 中 getCurrentSession( ) 和 openSession( ) 的区别?
1. openSession()每一次都会创建一个新的session对象。
getCurrnetSession ()只有在获取不到session的时候,才会创建session,一旦创建好session,就会把创建好的session绑定到当前线程中,也就说,在一个线程中,多次getCurrnetSession ()得到的session,是同一个。
2.使用openSession不用添加任何配置,使用getCurrnetSession,必须在hibrenate.cg.xml添加一行配置:
<property name="current_session_context_class">thread</property>
3.如果hibernate与spring集成了,则不用添加任何额外的配置,就能直接使用getCurrnetSession。
- 说说 Hibernate 的缓存(一级缓存和二级缓存的区别?)
1.缓存的作用: 提高读写速度。
2.Hibernate缓存包括两大类:Hibernate一级缓存和Hibernate二级缓存:
Hibernate的Session就是一级缓存。
Hibernate的SessionFactory就是二级缓存。
3.当Hibernate根据ID访问数据对象的时候,首先从Session一级缓存中查;查不到,如果配置了二级缓存,那么从二级缓存中查;如果都查不到,再查询数据库,把结果按照ID放入到二级和一级缓存中。 增删改数据时,同时更新二级缓存。
4. 由于一级缓存只对应一次事务,所以仅仅是在同一次事务期间才能使用一级缓存,所以一级缓存发挥的作用不是很大。
5. 由于二级缓存的生命周期与应用程序的整个过程相同,所以二级缓存可以极大地提升效率,但是经常需要改变的对象不应该存入二级缓存中,因为经常改变的对象除了要同步更新的数据库,还要额外地维护二级缓存中的数据!(查询操作多的适合二级缓存)
6. 二级缓存默认是关闭着的。 要开启二级缓存需要添加配置.
六、你怎么用hibernte分页(描述hibernate的分页)(你如何实现分页)
1. 首先创建一个Page类,其中封装一个分页页面需要的所有数据.
比如: 当前页pages ,总行数rowsNum 总页数pagesNum 上一页prePage 下一页nextPage …..
还需要为Page的构造器传入3个参数:当前页数,总行数,每页显示行数。
因为传入这3个已知量,就能计算出其他的所有值。
针对于hibernate。 2. 然后在dao层添加2个方法 a) 获取总行数的方法。 b) 获取分页数据的方法。接收起始行,每页显示行数. 在该方法中,使用到 Query接口的
hibernate会根据底层连接的数据库的不同,自动生成对应的数据库的分页sql语句。
|
针对于mybatis 2. 然后在dao层添加2个方法 a) 获取总行数的方法。 b) 获取分页数据的方法。接收起始行,每页显示行数. 在该方法中,使用 自定义的sql分页语句。 把起始行和每页显示行数,传入到sql语句中既可以!
|
3. 在业务层添加一个方法,该方法接收当前页数,和每页显示行数。返回一个Page对象。
4. 在控制器中,调用业务层的分页方法,将得到的page对象存入request范围中,再转发到视图,并展示数据。
七、描述你对Hibernate的认识
1.实体和实体之间的关系,以及如何用关系型数据库表示这些关系。
实体和实体之间的关系有3种:
一对一: 使用2张表表示,外键随便在哪一方。
一对多: 使用2张表表示,外键在多方。(降低冗余)
多对多: 使用3张表表示,外键在关系表中。
2.传统的JDBC代码有太多冗余,编写dao层使用jdbc开发效率太慢。尤其是使用jdbc维护一对一,一对多,多对多的关系时。
3. Hibernate是一个ORM框架(对象关系映射。Object Relational Mapping)
类à表
属性à列
关联à关系
使用hibernate框架能够将程序员从复杂的dao层开发中解脱出来(简化dao层开发)。Hibernate能轻松地管理一对一,一对多,多对多的关系。
4. Hibernate的核心类和接口一共有6个,分别为: Configuration、SessionFactory、Session
Transaction、Query、Criteria和。
- hibernte的运行过程:
- 配置好hibernate的主配置文件和与映射文件后。
- 实例化Configeration对象,使用Configeration加载hibernate.cfg.xml文件的配置内容,并根据hbm2ddl的配置,来创建表或者和表建立好映射关系
- 通过实例化的Configeration对象就可以建立SessionFactory实例,进一步,通过SessionFactory实例可以创建session对象
- 得到session之后,便可以对数据库进行增删改查操作了,简单的操作都可以通过hibernate封装好的Session内置方法来实现,复杂的操作可以通过hql来实现。
Session.save(user);
Session.delete(2);
Session.update(user);
Sesssion.get(User.class, 1);
Sesssoin.createQuery(“FROM User where ”)
-
- 在业务层,还可以利用SessionFactory的getCurrentSession来获取与当前线程相关的session。在dao层也要使用getCurrentSession方法获取session,从而保证在业务层和dao获取的session在一个线程中,使用的是同一个session,这样业务层就能控制事务了。
八、一对多、多对多、一对一的配置。
- hibernate中的update()和saveOrUpdate()的区别。
saveOrUpdate(); 如果操作的对象没有OID,就增加,如果有OID,就修改。如果修改的对象不存在,报错!
Update,仅仅只会修改,不会增加。 如果修改的对象不存在,就报错!
都会将对象转变为持久化状态。
Spring部分:
一、开发中主要使用 Spring 的什么技术 ?
1.IOC 容器管理各层的组件
2.使用 AOP 配置声明式事务
3.整合其他框架.
- 简述spring的 AOP 和 IOC
【IOC控制反转:IOC 容器负责实例化、定位、配置应用程序中的对象,及创建这些对象之间的依赖】
IOC底层原理:spring启动时,容器开始初始化时,会先把所有bean实例化,之后把实例化的对象放到一个大的map对象里面去,下次使用的时候直接从map里面get获取就好,就可以实现自动装配。
【AOP面向切面编程:是通过预编译和运行期动态代理实现程序功能的统一维护的一种技术】
------------------------
1. 所谓IOC, 就是控制反转。 把由程序内部实例化对象的过程,交给spring ioc容器来做的过程,就是控制反转。 (实例化时机:spring加载了配置文件就实例化)
2. 所谓AOP,就是面向切面编程。 没有使用切面时,业务层的业务方法中,会有大量的与核心业务无关的代码,导致业务代码急剧膨胀,尤其是要在每个业务方法中都添加无关的代码。在需要修改非业务代码时,工作量是很巨大的。
有了AOP,就会把核心业务关注点,与横切关注点分离,就能提高横切关注点的重用性。修改横切关注点时,只需要修改一个地方即可。
AOP的相关概念:
核心业务关注点: 核心业务。
横切关注点: 非核心业务功能。
1、通知Advice:控制横切关注点何时执行。(就是你想要的功能,也就是上面说的 安全,事物,日志等)
2、连接点JoinPoint:就是地方的全集(就是spring允许你使用通知的地方和方法有关的前前后后(抛出异常),都是连接点)。
3、切入点PointCut:控制何地执行。(连接点的基础上,定义切入点,一个类里,有15个方法,那就有几十个连接点了,但并不想在所有方法附近都使用通知(使用叫织入,以后再说),只想在调用某几个方法之前,之后或者抛出异常时干点什么,那么就用切点来定义这几个方法,让切点来筛选连接点。)
4、切面Aspect: 将横切关注点封装在一起得到的类。这个类就是切面.(通知和切入点的结合)
5、引入introduction:向现有的类添加新方法属性。(就是把切面(也就是新方法属性:通知定义的)用到目标类中)。
6、目标target:把核心业务封装起来的类的对象。(真正的业务逻辑,他可以在毫不知情的情况下,被咱们织入切面。而自己专注于业务本身的逻辑。)
7、代理proxy:就是把核心业务与横切关注点织入在一起以后的类的对象。
8、织入weaving: 将横切关注点与目标对象,组装到一起的过程,就是织入。
注意,我们编写代码的时候,要将核心业务 与 横切关注点 分离开来来写代码!
但是我们从spring ioc容器中,获取目标对象的时候,spring ioc容器会自动帮我们织入。所以从ioc容器中得到的实际上是一个代理对象。
5种通知:前置、返回、异常、后置、环绕
三、在 Spring 中如何配置 Bean ?(配置bean的3种方式)
实体类: public class Person { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Person [name=" + name + "]"; } } 配置: <bean class="com.edu.entity.Person" id="person"> <property name="name" value="zs"></property> </bean>
1.1有参构造器也可以 实体类: public class Person { private String name; public Person(String name) { super(); // 调用无参构造器 this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Person [name=" + name + "]"; } } 配置: <bean class="com.edu.entity.Person" id="person"> <constructor-arg name="name" value="zs"></constructor-arg> </bean>
|
实体:setter方法设置属性 工厂类: public class PersonStaticFactory { public static Person createPerson(){ return new Person(); } /** * 工厂方法带有参数如何处理? * @Title: createPerson * @Description: TODO(这里用一句话描述这个方法的作用) * @param @param name * @param @return * @return Person 返回类型 * @throws */ public static Person createPerson(String name){ return new Person(name); } } 配置: <!--静态的工厂方法核心是class+factory-method --> <bean id="person" class="com.edu.factory.PersonStaticFactory" factory-method="createPerson"></bean>
|
3、用实例工厂方法实例化 实体:setter方法设置属性 工厂类: public class PersonFactory { public Person createInstance() { return new Person(); } } 配置: <!-- 实例工厂方法需要先创建工厂实例,然后创建所需对象的时候,将其赋值给factory-bean --> <bean id="personFactory" class="com.edu.factory.PersonFactory"></bean> <bean id="person2" factory-bean="personFactory" factory-method="createInstance"></bean>
|
四、IOC 容器对 Bean 的生命周期
1. 在spring框架加载spring的主配置文件的时,就实例化bean。
2. 在实例化bean之后,就立刻调用bean元素的init-method属性指定的方法,该方法在整个bean的生命周期之间只执行一次
( 3. 在每次调用bean的方法时,就调用bean的方法)
3. 在关闭spring容器的时候,就调用destroy-method属性指定的方法,该方法在整个bean的生命周期之间只执行一次。
五、说一下struts2-hibernate-Spring 的工作流程?(谈谈SSH框架基本原理)
1. Struts2 是MVC框架,其中的jsp负责收集数据,展示数据,Action接受数据,把数据封装进javabean中,交给业务层处理。
2. Spring 的 IOC 容器管理各个组件,比如管理Action、业务层组件,dao层组件。 整合 Struts2, Hibernate 和 其他组件,AOP 完成声明式事务。
3. Hibernate 简化了Dao层开发的过程。
struts负责数据的传输和页面展示,hibernate负责数据库持久化,spring就负责管理它们。 典型的J2EE三层结构,分为表现层、中间层(业务逻辑层)和数据服务层。三层体系将业务规则、数据访问及合法性校验等工作放在中间层处理。客户端不直接与数据库交互,而是通过组件与中间层建立连接,再由中间层与数据库交互。
表现层是传统的JSP技术。
中间层采用的是流行的Spring+Hibernate,为了将控制层与业务逻辑层分离,又细分为以下几种。
Web层,就是MVC模式里面的“C”(controller),负责控制业务逻辑层与表现层的交互,调用业务逻辑层,并将业务数据返回给表现层作组织表现,该系统的MVC框架采用Struts。
Service层(就是业务逻辑层),负责实现业务逻辑。业务逻辑层以DAO层为基础,通过对DAO组件的正面模式包装,完成系统所要求的业务逻辑。
DAO层,负责与持久化对象交互。该层封装了数据的增、删、查、改的操作。
PO,持久化对象。通过实体关系映射工具将关系型数据库的数据映射成对象,很方便地实现以面向对象方式操作数据库,该系统采用Hibernate作为ORM框架。 |
- Spring 如何整合 Struts2 ?
整合 Struts2, 即由 IOC 容器管理 Struts2 的 Action:
1.安装 Spring 插件: 把struts2-spring-plugin-2.2.1.jar 复制到当前 WEB 应用的 WEB-INF/lib 目录下
2. 在web.xml配置文件中,添加一个监听器
<listener>
<listener-class>xxx.xxx.xxx. ContextLoaderListener</listener-class>
</listener>
该监听器的作用是:创建spring ioc容器。创建容器的时候,需要知道spring主配置文件的路径。 该监听器会自动读取一个名字叫做contextConfigLocation的初始化参数,使用该参数的值作为spring配置文件的路径。
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
ContextLoaderListener监听器创建好spring ioc容器之后,会自动把容器存入application范围中。
3.由spring管理struts2中的Action,管理方式有2种
a. 在spring的配置文件中,使用<bean>元素。
b. 在Action类上添加@Controller注解,还要保证Action是多例的,这需要加@Scope(“prototype”)
4.在 Struts 配置文件中配置 action, 在<action>元素中,class的取值不再是Action类的全名,而是直接写出首字母小写的类名。
- Spring 如何整合 Hibernate ?
1. spring管理Hibernate的SessionFactory
a. 先管理一个数据源(ds)
b. 再由容器管理一个LocalSessionFactoryBean,把数据源注入给该对象。
还要指明hibernate子配置文件的位置(mappingLocations)和主配置文件的位置(configLocation)
2.使用spring中的声明式事务。
a. 由容器管理事务管理器, HibernateTransactionManager.
b. 启用事务注解 <tx:annotation-driven ></ tx:annotation-driven> 还需要把工厂sessionFactory注入给事务管理器。
- 你对spring的理解(谈谈spring)
一定要说出IOC AOP, 一定要提到工厂,因为Spring ioc容器本身就是一个巨大的动态工厂! 动态工厂 = 抽象工厂 + 配置文件 + 反射机制。
1.Spring的两个核心技术是IOC和AOP 2.所谓IOC是…. 底层使用的是java反射机制。 3.所谓AOP是… 底层使用的是动态代理。 4.利用IOC可以实现动态工厂,利用工厂可以让客户端代码不用感知接口的具体实现类是什么,并且当要替换产品的时候,只需要向工厂传入不同的参数即可,从而达到使用产品的客户端代码与产生产品的代码完全解耦。 5.利用AOP可以实现声明式事务。添加日志,权限判断等等…… |
九、Spring 的依赖注入是什么意思? 给一个 Bean 的 message 属性, 字符串类型, 注入值为 "Hello" 的 XML 配置文件该怎么写?
<bean id=”aa” class=”com.Foo”>
<property name=” message” value=” Hello” />
</bean>
十、Springmvc:?
- springmvc架构: (谈谈springmvc , 什么是springmvc)
- 前端控制器(DispatcherServlet):负责在其他各个组件之间协调
- 映射器:接受url,根据url找到具体的controller,不负责执行controller,会把controller给前端控制器,前端控制器再交给适配器
- 适配器: 不同的适配器,要求controller要实现不同的接口(依赖倒置)。适配器执行controller之后,得到一个ModelAndView, 再交给给前端控制器,前端控制器再交给视图解析器。
- 视图解析器,接受ModelAndView,从ModelAndView对象中,获取出逻辑视图名,在逻辑视图名上加上前缀、后缀,得到物理视图,物理视图又交给前端控制器,最终由前段控制器做出响应。
优点好处:映射器和适配器和视图解析器之间,没有直接的关系,这样就能达到完全解耦,从而能提高组件重用性,扩展性。
问到适配器。也牵扯出springmvc的架构来回答。
- Springmvc如何给controller的方法传递参数(5种方式)。
一:直接将请求参数名作为Controller中方法的形参 public String login (String username,String password){ } 解释:括号中的参数必须与页面Form 表单中的 name 名字相同
二:使用@RequestParam 绑定请求参数参数值 public String login(RequestParam ("username") String name) { } 解释:双引号中username 必须与页面 name 名字相同,String name 中name可以随意。
三:用注解@RequestMapping接收参数的方法 @RequestMapping(value="/login/{username}/{password}") public String login(@PathVariable("username") String name,@PathVariable("password") String name){ }
解释:上面的 @RequestMapping(value="/login/{username}/{password}") 是以注解的方式写在方法上的。注解上的usernname和 password 必须和页面上name相同
四:使用Pojo对象(就是封装类,类中封装的字段作为参数)绑定请求参数值,原理是利用Set的页面反射机制找到User对象中的属性。 @ReauestMapping(value=/login”) public String login(User user){ }
解释:就是把封装的一个类当成一个参数放在方法中,封装类中的属性就是就是参数。
五:使用原生的Servlet API 作为Controller 方法的参数 public String login(HttpServletRequest request){ String username=Request.getParameter("username"); } 解释:使用request 请求页面参数的方式获取从页面传过来的参数 |
- 自定义类型转换器,必须要实现Converter接口,在springMVC.xml配置转换器.
- springmvc验证框架,使用的是hibernate的验证框架.
- springmvc拦截器
- 文件上传。
十一、设计模式6大原则:
- 开闭原则:
- 对修改关闭
- 对扩展开发 (保留原功能,扩展新功能)
- 依赖倒置
- 上层不依赖于下层,下层依赖于上层。上层是面向接口编程的。
- 单一职责
- 一个类的功能必须尽可能地单一!
- 这样就能提高功能的重用性。当替换某一个功能的时候,对其他功能没有影响。
- 里氏替换原则
- 向上转型。在任何一个使用父类的地方,都能透明地直接替换为其子类。
- 迪米特法则(封装, 隔离上下层)
- 最少知道,上层调用下层功能的时候,应该对下层功能的具体实现知道的越少越好。
- 接口隔离原则
- 每一个接口应该承担一种相对独立的角色,不干不该干的事,该干的事都要干。
十二、EL中的11个隐式对象
pageScope
requestScope
sessionScope
applicationScope
header
headerValues
cookie
param
paramValues
initParam
pageContext
1、SpringBoot概念:
Spring Boot是由Pivotal团队提供的全新框架,其设计目的è简化新Spring应用的初始搭建以及开发过程。
该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。
它是一个“微框架”,适合快速搭建项目,通过近乎零配置的方式达到快速开发的目的。当然,由于默认的设置太多,如果有特殊需求依然会涉及一系列配置文件。
Spring Boot是一个基于Spring的衍生框架,其主要目的è快速构建独立、生产级别的Spring的应用,其崇尚的理念是“约定优于配置”。
-------------------------------------------------------------------
2、Spring Boot核心功能(主要有如下的特点):
1.独立运行的Spring项目
Spring Boot可以以jar的形式独立运行,只需要通过java -jar **.jar即可。
2.内嵌Servlet容器
Spring Boot可以选择内嵌Tomcat、Jetty等容器,这样可以无须以war包形式部署项目。
3.提供Starter简化Maven配置
Spring Boot提供可一系列的starter pom场景启动器来简化Maven的依赖加载和版本管理。
4.自动配置Spring
Spring Boot会根据在类路径中的jar包、类,为jar包里的类自动配置Bean,这样极大减少我们需要去做的配置项,并且,如果在实际开发中,需要我们手动配置Bean,可以自定义自动配置。
5.准生产的应用监控
Spring Boot提供基于http、ssh、telnet对运行时的项目进行监控。
6.无代码生成和xml配置
Spring Boot不是借助于代码生成来实现的,而是通过条件注解实现的,这是Spring 4.X提供的新特性。
Sping 4.X提倡使用Java配置和注解配置组合,而Spring Boot不需要任何xml配置即可实现Spring的全部配置。
----------------------------------------------------------------------------------------------
3、SpringBoot自动配置的原理:
得益于“习惯优于配置”这个理念,再也没有繁琐的配置、难以集成的内容(大多数流行第三方技术都被集成在内)。
那么背后实现的核心原理是spring 4.x提供的基于条件配置bean的能力。Spring boot关于自动配置的源码在spring-boot-autoconfigure-x.x.x.x.jar中
---------------------------------------------------------------------------------------------
4、Spring Boot的优点:
(1) 快速构建项目;
(2) 对主流开发框架的无配置集成;
(3) 项目可独立运行,无须外部依赖Servlet容器;
(4) 提供运行时的应用监控;
(5) 极大的提高了开发,部署效率;
(6) 与云计算天然集成。
Mybatis部分:
https://blog.csdn.net/eaphyy/article/details/71190441 Mybatis地址
1、#{}和${}的区别是什么?
#{}
是预编译处理,${}是字符串替换。
Mybatis
在处理#{}时,会将sql中的#{}替换为
?
号,调用PreparedStatement的set方法来赋值;
Mybatis
在处理${}时,就是把${}替换成变量的值。
使用
#{}
可以有效的防止SQL注入
,提高系统安全性。
2、当实体类中的属性名和表中的字段名不一样 ,怎么办 ?
第1种: 通过在
查询的sql语句中定义字段名的别名
,让字段名的
别名和实体类的属性名一致
- 1
- 2
<
selectid=”selectorder” parametertype=”int” resultetype=”
me.gacl.domain.
order”>
select
order_id id, order_no orderno ,order_price price form orders
whereorder_id=
#{id};
</
select>
第2种: 通过<resultMap>来映射字段名和实体类属性名的一一对应的关系
<select id="getOrder" parameterType="int" resultMap="orderresultmap">
select * from orders where order_id=#{id}
</select>
<resultMap type=”me.gacl.domain.order” id=”orderresultmap”>
<!–用id属性来映射主键字段–>
<id property=”id” column=”order_id”>
<!–用result属性来映射非主键字段,property为实体类属性名,column为数据表中的属性–>
<result property = “orderno” column =”order_no”/>
<result property=”price” column=”order_price” />
</reslutMap>
3、 模糊查询like语句该怎么写?
第1种:在Java代码中添加sql通配符。
string
wildcardname = “%smi%”;
list<name> names = mapper.selectlike(wildcardname);
<
selectid=”selectlike”>
select
*
fromfoo
wherebar
like#{value}
</
select>
第2种:在sql语句中拼接通配符,会引起sql注入
string
wildcardname = “smi”;
list<name> names = mapper.selectlike(wildcardname);
<
selectid=”selectlike”>
select
*
fromfoo
wherebar
like"%"#{value}"%"
</
select>
4、通常一个Xml映射文件,都会写一个Dao接口与之对应,请问,这个Dao接口的工作原理是什么?Dao接口里的方法,参数不同时,方法能重载吗?
Dao
接口,就是人们常说的Mapper接口,接口的全限名,就是映射文件中的namespace的值,接口的方法名,就是映射文件中MappedStatement的id值,接口方法内的参数,就是传递给sql的参数。Mapper接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符串作为key值,可唯一定位一个MappedStatement,举例:com.mybatis3.mappers.StudentDao.findStudentById,可以唯一找到namespace为com.mybatis3.mappers.StudentDao下面id = findStudentById的MappedStatement。在Mybatis中,每一个<select>、<insert>、<update>、<delete>标签,都会被解析为一个MappedStatement对象。
Dao
接口里的方法,是不能重载
的,因为是全限名+方法名的保存和寻找策略。
Dao
接口的工作原理
是JDK动态代理,Mybatis运行时会使用JDK动态代理为Dao接口生成代理proxy对象,代理对象proxy会拦截接口方法,转而执行MappedStatement所代表的sql,然后将sql执行结果返回。
5、Mybatis是如何进行分页的?分页插件的原理是什么?
Mybatis
使用
RowBounds
对象进行分页
,它是针对ResultSet结果集执行的
内存分页
,而非物理分页,可以在sql内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页。
分页插件的基本原理
是使用Mybatis提供的插件接口,
实现自定义插件
,在插件的
拦截方法内拦截待执行的sql
,然后
重写sql
,根
据dialect
方言,
添加对应的物理分页语句
和
物理分页参数
。
6、Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式?
答:
第一种
是使用
<resultMap>
标签
,逐一定义列名和对象属性名之间的映射关系。
第二种
是使用
sql
列的别名
功能,将列别名
书写为对象属性名
,比如T_NAME AS NAME,对象属性名一般是name,小写,但是列名不区分大小写,Mybatis会忽略列名大小写,智能找到与之对应对象属性名,你甚至可以写成T_NAME AS NaMe,Mybatis一样可以正常工作。
有了列名与属性名的映射关系后,Mybatis通过反射创建对象,同时使用反射给对象的属性逐一赋值并返回,那些找不到映射关系的属性,是无法完成赋值的。
- 1
- 2
- 3
- 4
7、如何执行批量插入?
首先,创建一个简单的insert语句:
- 1
- 2
<insert
id=”insertname”>
insert
intonames (
name) values (
#{value})
</insert>
- 1
- 2
- 3
然后在java代码中像下面这样执行批处理插入:
- 1
- 2
list<string>
names =
newarraylist();
names.add(“fred”);
names.add(“barney”);
names.add(“betty”);
names.add(“wilma”);
// 注意这里 executortype.batch
sqlsession sqlsession = sqlsessionfactory.opensession(executortype.batch);
try
{
namemapper mapper = sqlsession.getmapper(namemapper.
class);
for
(
stringname : names) {
mapper.insertname(name);
}
sqlsession.commit();
} finally {
sqlsession.close();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
8、如何获取自动生成的(主)键值?
insert
方法总是返回一个int值 - 这个值代表的是插入的行数。
而自动生成的键值在 insert 方法执行完后可以被设置到传入的参数对象中。
示例:
- 1
- 2
- 3
- 4
<insert id=”insertname” usegeneratedkeys=”
true” keyproperty=”id”>
insert
intonames (name) values (
#{name})
</insert>
name name =
newname();
name.setname(“fred”);
int
rows = mapper.insertname(name);
// 完成后,id已经被设置到对象中
system.
out.println(“rows inserted = ” + rows);
system.
out.println(“generated key
value= ” + name.getid());
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
9、在mapper中如何传递多个参数?
第1种:
- 1
- 2
//DAO层的函数
PublicUserselectUser(
Stringname,
Stringarea);
- 1
- 2
- 3
//对应的xml,#{0}代表接收的是dao层中的第一个参数,#{1}代表dao层中第二参数,更多参数一致往后加即可。
<
selectid=
"selectUser"resultMap=
"BaseResultMap">
select
* fromuser_user_t whereuser_name =
#{0} anduser_area=#{1}
</
select>
- 1
- 2
- 3
- 4
- 5
第2种: 使用 @param 注解:
- 1
- 2
import org.apache.ibatis.annotations.param;
public
interface
usermapper {
user selectuser(@param(“username”)
stringusername,
@param(“hashedpassword”)
stringhashedpassword);
}
- 1
- 2
- 3
- 4
- 5
然后,就可以在xml像下面这样使用(推荐封装为一个map,作为单个参数传递给mapper):
- 1
- 2
<
selectid=”selectuser” resulttype=”user”>
select
id, username, hashedpassword
from
some_table
where
username =
#{username}
and
hashedpassword =
#{hashedpassword}
</
select>
- 1
- 2
- 3
- 4
- 5
- 6
10、Mybatis动态sql是做什么的?都有哪些动态sql?能简述一下动态sql的执行原理不?
Mybatis
动态sql可以让我们在Xml映射文件内,以标签的形式编写动态sql,完成逻辑判断和动态拼接sql的功能。
Mybatis
提供了9种动态sql标签:trim|where|set|foreach|if|choose|when|otherwise|bind。
其执行原理为,使用OGNL从sql参数对象中计算表达式的值,根据表达式的值动态拼接sql,以此来完成动态sql的功能。
- 1
- 2
- 3
- 4
11、Mybatis的Xml映射文件中,不同的Xml映射文件,id是否可以重复?
不同的Xml映射文件,如果配置了namespace,那么id可以重复;如果没有配置namespace,那么id不能重复;毕竟namespace不是必须的,只是最佳实践而已。
原因就是namespace+id是作为Map<String, MappedStatement>的key使用的,如果没有namespace,就剩下id,那么,id重复会导致数据互相覆盖。有了namespace,自然id就可以重复,namespace不同,namespace+id自然也就不同。
- 1
- 2
- 3
- 4
12、为什么说Mybatis是半自动ORM映射工具?它与全自动的区别在哪里?
Hibernate
属于全自动ORM映射工具,使用Hibernate查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取,所以它是全自动的。而Mybatis在查询关联对象或关联集合对象时,需要手动编写sql来完成,所以,称之为半自动ORM映射工具。
- 1
- 2
13、 一对一、一对多的关联查询 ?
<mapper namespace="com.lcb.mapping.userMapper">
<!--association 一对一关联查询 -->
<select id="getClass" parameterType="int" resultMap="ClassesResultMap">
select * from class c,teacher t where c.teacher_id=t.t_id and c.c_id=#{id}
</select>
<resultMap type="com.lcb.user.Classes" id="ClassesResultMap">
<!-- 实体类的字段名和数据表的字段名映射 -->
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
<association property="teacher" javaType="com.lcb.user.Teacher">
<id property="id" column="t_id"/>
<result property="name" column="t_name"/>
</association>
</resultMap>
<!--collection 一对多关联查询 -->
<select id="getClass2" parameterType="int" resultMap="ClassesResultMap2">
select * from class c,teacher t,student s where c.teacher_id=t.t_id and c.c_id=s.class_id and c.c_id=#{id}
</select>
<resultMap type="com.lcb.user.Classes" id="ClassesResultMap2">
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
<association property="teacher" javaType="com.lcb.user.Teacher">
<id property="id" column="t_id"/>
<result property="name" column="t_name"/>
</association>
<collection property="student" ofType="com.lcb.user.Student">
<id property="id" column="s_id"/>
<result property="name" column="s_name"/>
</collection>
</resultMap>
</mapper>
Java开发常用API/类、工具类
1.API
java.lang.Object
java.lang.Math
java.lang.String(StringBuilder线程不安全,StringBuffer线程安全)
java.lang.Class
java.lang.Runnable
java.lang.Thread
java.util.Scanner
java.util.Arrays
java.util.Radom
java.util.Collection<E>
java.util.List<E>
java.util.Map<K,V>
java.util.Iterator<E>
common-httpclient 来实现post请求
2.工具类
MD5工具类
Slicer:将List切割成多个List的工具类。
TimeCounter:一个方便的计时器,不用手动的使用System.nanoTime()去计算程序时间,使用ThreadLocal实现,线程安全且具有可重入特性。
Json(字符串)与js对象互相转换:
1、Josnàjs对象:2种方法
1)JS自带的eval( )函数;不建议
2)JSON.parse(str); //str为变量,即json字符串; 常用
2、js对象àjson
1)JSON.stringify(obj)
3、JS对象转JSON :Object.toJSONString( )
JSON转JS对象:String.parseJSON( )
SpringMVC返回json数据的三种方式:
1、第一种方式是spring2时代的产物,也就是每个json视图controller配置一个Jsoniew。
如:<bean id="defaultJsonView" class="org.springframework.web.servlet.view.json.MappingJacksonJsonView"/>
或者<bean id="defaultJsonView" class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/>
同样要用jackson的jar包。
2、第二种使用JSON工具将对象序列化成json,常用工具Jackson,fastjson,gson。
利用HttpServletResponse,然后获取response.getOutputStream()或response.getWriter()
直接输出。
示例:
[java] view plain copy
- public class JsonUtil
- {
- private static Gson gson=new Gson();
- /**
- * @MethodName : toJson
- * @Description : 将对象转为JSON串,此方法能够满足大部分需求
- * @param src
- * :将要被转化的对象
- * @return :转化后的JSON串
- */
- public static String toJson(Object src) {
- if (src == null) {
- return gson.toJson(JsonNull.INSTANCE);
- }
- return gson.toJson(src);
- }
- }
3、第三种利用spring mvc3的注解 @ResponseBody
例如:
@ResponseBody
- @RequestMapping("/list")
- public List<String> list(ModelMap modelMap) {
- String hql = "select c from Clothing c ";
- Page<Clothing> page = new Page<Clothing>();
- page.setPageSize(6);
- page = clothingServiceImpl.queryForPageByHql(page, hql);
- return page.getResult();
- }
然后使用spring mvc的默认配置就可以返回json了,不过需要jackson的jar包
注意:当springMVC-servlet.xml中使用<mvc:annotation-driven />时,如果是3.1之前已经默认注入AnnotationMethodHandlerAdapter,3.1之后默认注入RequestMappingHandlerAdapter只需加上上面提及的jar包即可!
如果是手动注入RequestMappingHandlerAdapter 可以这样设置
配置如下:
[html] view plain copy
- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"
- p:ignoreDefaultModelOnRedirect="true" >
- <property name="messageConverters">
- <list>
- <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>
- </list>
- </property>
- </bean>
添加包
jackson-mapper-asl-*.jar
jackson-core-asl-*.jar
Ajax:
异步数据请求方式,做局部刷新 Asynchronized JavaScript And Xml
同步异步区别:
同步:发出一个请求后,要等服务器端响应后才能继续执行后面的代码;
异步:多线程的,可同时发多个请求,不用等服务器响应。
jQuery:
选择器:
#id Id选择器
.class 类选择器
标签 元素选择器
$("#txt1").attr("value");
事件函数:
ready(fn): 在DOM载入就绪能够读取并操纵时立即调用你所绑定的函数.
bind( type, [data], fn) : 为每一个匹配元素的特定事件(像click)绑定一个事件处理器函数。起到事件监听的作用。