JAVA复习
1.面向对象和面向过程的区别
面向过程
优点:性能高、耗资源
面向对象
优点:易维护、易复用、易扩展
面向过程将一个问题分解为若干小问题,再将这些小问题一一解决,面向对象:冰箱,可以自己把门打开,自己把大象装进去,自己把门关上。
人们不需要了解这一过程是如何实现的,只要在需要把大象装进冰箱的时候,跟冰箱说一句:“嘿,你把大象装进去吧。”
2.Java的四个基本特性(抽象、封装、继承,多态)
抽象:把某一类东西提取出来
封装:封装隐藏
继承:是对有着共同特性的多类事物,进行再抽象成一个类
多态:方法的重载、类的覆盖
3.重载和重写的区别
重载:发生在同一个类中,方法名必须相同,参数类型不同、个数不同、顺序不同,方法返回值和访问修饰符可以不同,发生在编译时。
重写:发生在父子类中,方法名、参数列表必须相同,返回值小于等于父类,抛出的异常小于等于父类,访问修饰符大于等于父类;如果父类方法访问修饰符为private则子类中就不是重写。
4.构造器Constructor是否可被override
构造器不能被重写,不能用static修饰构造器,只能用public
private protected这三个权限修饰符,且不能有返回语句。
5.访问控制符public,protected,private,以及默认的区别
private只有在本类中才能访问;
public在任何地方都能访问;
protected在同包内的类及包外的子类能访问;
默认不写在同包内能访问。
6.是否可以继承String类
String类是final类故不可以继承,一切由final修饰过的都不能继承。
7.String和StringBuffer、StringBuilder的区别
可变性
String对象是不可变的。StringBuilder与StringBuffer都继承自AbstractStringBuilder类,都是使用字符数组保存字符串
线程安全性
String中的对象是不可变的,线程安全。
StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全(同步)的。
StringBuilder并没有对方法进行加同步锁,所以是非线程安全的(异步)。
性能
每次对String 类型进行改变的时候,都会生成一个新的String 对象,然后将指针指向新的String 对象。StringBuffer每次都会对StringBuffer 对象本身进行操作,而不是生成新的对象并改变对象引用。相同情况下使用StirngBuilder 相比使用,StringBuffer 仅能获得10%~15% 左右的性能提升,但却要冒多线程不安全的风险。
8.hashCode和equals方法的关系
equals相等,hashcode必相等;hashcode相等,equals可能不相等。
equals:是否同一个对象实例。
等号(==):对比对象实例的内存地址
hashcode方法返回该对象的哈希码值。两个对象的hashCode相同,并不一定表示两个对象就相同,也就是不一定适用于equals(java.lang.Object) 方法,只能够说明这两个对象在散列存储结构中,如Hashtable,他们“存放在同一个篮子里”。(有可能在一个链表)
9.抽象类和接口的区别
相同点
1.都不能实例化。
2.都必须要实现已经声明的抽象方法。
不同点
1. interface需要实现,要用implements,而abstract class需要继承,要用extends。
2. 一个类可以实现多个interface,但一个类只能继承一个abstract class。
3. interface强调特定功能的实现,而abstract class强调所属关系。
4. interface中的每一个方法都是抽象方法,都只是声明的没有方法体,实现类必须要实现。而abstract class的子类可以有选择地实现。
5. 抽象类是对类抽象,而接口是对行为的抽象。抽象类是自底向上抽象而来的,接口是自顶向下设计出来的。
10.自动装箱与拆箱
装箱:将基本类型用转换为包装类型 valueOf()
拆箱:将包装类型转换为基本数据类型 intValue()
Java使用自动装箱和拆箱机制,节省了常用数值的内存开销和创建对象的开销,提高了效率,由编译器来完成,编译器会在编译期根据语法决定是否进行装箱和拆箱动作。
11.什么是泛型、为什么要使用以及泛型擦除
泛型,即“参数化类型”。
创建集合时就指定集合元素的类型,该集合只能保存其指定类型的元素,避免使用强制类型转换。
Java编译器生成的字节码是不包涵泛型信息的,泛型类型信息将在编译处理时被擦除,这个过程即类型擦除。泛型擦除可以简单的理解为将泛型java代码转换为普通java代码,只不过编译器更直接点,将泛型java代码直接转换成普通java字节码。
12.Java中的集合类及关系图
List和Set继承自Collection接口。
List有序且允许元素重复。ArrayList、LinkedList和Vector是三个主要的实现类。
Set无序不允许元素重复。HashSet和TreeSet是两个主要的实现类。
hashSet的实现原理:
往Haset添加元素的时候,HashSet会先调用元素的hashCode方法得到元素的哈希值 ,
然后通过元素 的哈希值经过移位等运算,就可以算出该元素在哈希表中 的存储位置。
情况1: 如果算出元素存储的位置目前没有任何元素存储,那么该元素可以直接存储到该位置上。
情况2: 如果算出该元素的存储位置目前已经存在有其他的元素了,那么会调用该元素的equals方法与该位置的元素再比较一次
,如果equals返回的是true,那么该元素与这个位置上的元素就视为重复元素,不允许添加,如果equals方法返回的是false,那么该元素运行 添加。
TreeSet
存储的特点
以二叉树的方式进行存储的,存入的数据是按照一定的顺序进行排列的
存储原理 :
如果想把对象存入到TreeSet集合当中需要让对象实现Comparable接口,目的是进行存储的时候让对象有一个比较的顺序,重写ComparaTo方法根据返回值进行数据的存储以及排序 如果返回负数则是倒叙排列 如果返回正数则是正序排列,如果为0 则认为两个对象相同
Map也属于集合系统,但和Collection接口没关系。Map是key对value的映射集合,其中key列就是一个集合。key不能重复,但是value可以重复。HashMap、TreeMap和Hashtable是三个主要的实现类。
去除List集合中的重复值
实现List集合中数据的逆向排序
Collections.reverse(list); 实现list集合逆序排列
Map三种遍历方式
1.KeySet 2.entrySet 3.values
迭代器遍历
set keys = map.keySet();
if(keys != null){Iterator iterator = map.iterator();
while(iterator.hasNext()){Object key = iterator.next();Object value = map.get(key)}}
SortedSet和SortedMap接口对元素按指定规则排序,SortedMap是对key列进行排序。
13.HashMap实现原理
HashMap基于hashing原理,我们通过put()和get()方法储存和获取对象。当我们将键值对传递给put()方法时,它调用键对象的hashCode()方法来计算hashcode,让后找到bucket位置来储存值对象。当获取对象时,通过键对象的equals()方法找到正确的键值对,然后返回值对象。HashMap使用LinkedList来解决碰撞问题,当发生碰撞了,对象将会储存在LinkedList的下一个节点中。 HashMap在每个LinkedList节点中储存键值对对象。
当两个不同的键对象的hashcode相同时会发生什么? 它们会储存在同一个bucket位置的LinkedList中。键对象的equals()方法用来找到键值对。
散列法(Hashing)或哈希法是一种将字符组成的字符串转换为固定长度(一般是更短长度)的数值或索引值的方法,称为散列法,也叫哈希法。
你知道HashMap的工作原理吗?你知道HashMap的get()方法的工作原理吗?
HashMap是基于hashing的原理,我们使用put(key, value)存储对象到HashMap中,使用get(key)从HashMap中获取对象。当我们给put()方法传递键和值时,我们先对键调用hashCode()方法,返回的hashCode用于找到bucket位置来储存Entry(键值对对象)对象。
当两个对象的hashcode相同会发生什么?
因为hashcode相同,所以它们的bucket位置相同,‘碰撞’会发生。因为HashMap使用LinkedList存储对象,这个Entry(包含有键值对的Map.Entry对象)会存储在LinkedList中。
如果两个键的hashcode相同,你如何获取值对象?
当我们调用get()方法,HashMap会使用键对象的hashcode找到bucket位置,然后会调用keys.equals()方法去找到LinkedList中正确的节点,最终找到要找的值对象
在java编程语言中,最基本的结构就是两种,一个是数组,另外一个是模拟指针(引用),所有的数据结构都可以用这两个基本结构来构造的
HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体。
从上图中可以看出,HashMap底层就是一个数组结构,数组中的每一项又是一个链表。当新建一个HashMap的时候,就会初始化一个数组。
http://zhangshixi.iteye.com/blog/672697
http://www.admin10000.com/document/3322.html
14.HashTable实现原理
http://www.cnblogs.com/skywang12345/p/3310887.html
http://blog.csdn.net/chdjj/article/details/38581035
15.HashMap和HashTable区别
1).HashTable的方法前面都有synchronized来同步,是线程安全的;HashMap未经同步,是非线程安全的。
2).HashTable不允许null值(key和value都不可以) ;HashMap允许null值(key和value都可以)。
3).HashTable使用Enumeration进行遍历;HashMap使用Iterator进行遍历。
16.ArrayList和vector区别
ArrayList和Vector都实现了List接口,都是通过数组实现的。
Vector是线程安全的,而ArrayList是非线程安全的。
List第一次创建的时候,会有一个初始大小,随着不断向List中增加元素,当List 认为容量不够的时候就会进行扩容。Vector缺省情况下自动增长原来一倍的数组长度,ArrayList增长原来的50%。
17.ArrayList和LinkedList区别及使用场景
区别
ArrayList底层是用数组实现的,是一个可改变大小的数组。容量动态增加
LinkedList底层是通过双向链表实现的, LinkedList和ArrayList相比,增删的速度较快。但是查询和修改值的速度较慢。
使用场景
LinkedList更适合从中间插入或者删除(链表的特性)。
ArrayList更适合检索和在末尾插入或删除(数组的特性)。
18.Collection和Collections的区别
java.util.Collection 是一个集合接口。提供了对集合对象进行基本操作的通用接口方法。
java.util.Collections 是一个包装类。它包含有各种有关集合操作的静态多态方法。此类不能实例化,就像一个工具类,服务于Java的Collection框架。
19.Error、Exception区别
Error类和Exception类的父类都是throwable类,他们的区别是:
Error类一般是指与虚拟机相关的问题,如系统崩溃,虚拟机错误,内存空间不足,方法调用栈溢等。对于这类错误的导致的应用程序中断,仅靠程序本身无法恢复和和预防,遇到这样的错误,建议让程序终止。
Exception类表示程序可以处理的异常,可以捕获且可能恢复。遇到这类异常,应该尽可能处理异常,使程序恢复运行,而不应该随意终止异常。
常见异常:
IndexOutOfBoundsException
NumberFormatException
ArithmeticException
NullPointerException
ClassCastException 类型转换错误
finally是为了保证一定能回收try块中打开的物理资源
throw语句抛出的是一个异常实例
用户自定义异常都继承父类,定义异常类时要提供两种构造器:一个是无参数的构造器;另一个是带一个字符串的构造器,这个字符串将作为该异常对象的详细说明(getMessage()的返回值)
20.Java中如何实现代理机制(JDK、CGLIB)
JDK动态代理:代理类和目标类实现了共同的接口,用到InvocationHandler接口。
CGLIB动态代理:代理类是目标类的子类,用到MethodInterceptor接口。
21.多线程的实现方式
继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程。
Thread类的setPriority()和getPriority()方法分别用来设置和获取线程的优先级。
进程通讯:创建同步仓库QA
22.线程的状态转换
23.如何停止一个线程
停止一个线程可以用Thread.stop()方法,但最好不要用它,过时。
使用interrupt[ɪntəˈrʌpt]方法中断线程,调用interrupt方法是在当前线程中打了一个停止标志,并不是真的停止线程。
http://www.cnblogs.com/greta/p/5624839.html
24.什么是线程安全
线程安全就是多线程访问同一代码,不会产生不确定的结果。
25.如何保证线程安全
对非安全的代码进行加锁控制;
使用线程安全的类;
多线程并发情况下,线程共享的变量改为方法级的局部变量。
26.synchronized如何使用
synchronized是Java中的关键字,是一种同步锁。它修饰的对象有以下几种:
1). 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;
2). 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;
3). 修饰一个静态方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;
4). 修饰一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。
27.synchronized和Lock的区别
主要相同点:Lock能完成synchronized所实现的所有功能
主要不同点:Lock有比synchronized更精确的线程语义和更好的性能。Lock的锁定是通过代码实现的,而synchronized是在JVM层面上实现的,synchronized会自动释放锁,而Lock一定要求程序员手工释放,并且必须在finally从句中释放。
void notify() 唤醒在此对象监视器上等待的单个线程。
void notifyAll() 唤醒在此对象监视器上等待的所有线程。
void wait() 导致当前的线程等待,直到其他线程调用此对象的notify()方法或notifyAll()方法。
28.sleep和wait的区别(考察的方向是是否会释放锁)
sleep()方法是Thread类中方法,而wait()方法是Object类中的方法。
sleep()方法导致了程序暂停执行指定的时间,让出cpu该其他线程,但是他的监控状态依然保持者,当指定的时间到了又会自动恢复运行状态,在调用sleep()方法的过程中,线程不会释放对象锁。而当调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备。
29.多线程与死锁
死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。
产生死锁的原因:
一.因为系统资源不足。
二.进程运行推进的顺序不合适。
三.资源分配不当。
生产消费者模型
简单的死锁程序
public class DeadLockTest implements Runnable {
public boolean flag = true;
private static Object res1 = new Object();
private static Object res2 = new Object();
public void run() {
if (flag) {
/* 锁定资源res1 */
synchronized (res1) {
System.out.println("锁定资源1,等待资源2...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) { }
/* 锁定资源res2 */
synchronized (res2) {
System.out.println("Complete.");
}
}
} else {
/* 锁定资源res2 */
synchronized (res2) {
System.out.println("锁定资源2,等待资源1***");
try {
Thread.sleep(1000);
} catch (InterruptedException e) { }
/* 锁定资源res1 */
synchronized (res1) {
System.out.println("Complete.");
}
}
}
}
public static void main(String[] args) {
TestDeadLock r1 = new TestDeadLock();
TestDeadLock r2 = new TestDeadLock();
r2.flag = false;
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
t2.start();
}
}
30.如何才能产生死锁
产生死锁的四个必要条件:
一.互斥条件:所谓互斥就是进程在某一时间内独占资源。
二.请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
三.不剥夺条件:进程已获得资源,在末使用完之前,不能强行剥夺。
四.循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
31.死锁的预防
打破产生死锁的四个必要条件中的一个或几个,保证系统不会进入死锁状态。
一.打破互斥条件。即允许进程同时访问某些资源。但是,有的资源是不允许被同时访问的,像打印机等等,这是由资源本身的属性所决定的。所以,这种办法并无实用价值。
二.打破不可抢占条件。即允许进程强行从占有者那里夺取某些资源。就是说,当一个进程已占有了某些资源,它又申请新的资源,但不能立即被满足时,它必须释放所占有的全部资源,以后再重新申请。它所释放的资源可以分配给其它进程。这就相当于该进程占有的资源被隐蔽地强占了。这种预防死锁的方法实现起来困难,会降低系统性能。
三.打破占有且申请条件。可以实行资源预先分配策略。即进程在运行前一次性地向系统申请它所需要的全部资源。如果某个进程所需的全部资源得不到满足,则不分配任何资源,此进程暂不运行。只有当系统能够满足当前进程的全部资源需求时,才一次性地将所申请的资源全部分配给该进程。由于运行的进程已占有了它所需的全部资源,所以不会发生占有资源又申请资源的现象,因此不会发生死锁。
四.打破循环等待条件,实行资源有序分配策略。采用这种策略,即把资源事先分类编号,按号分配,使进程在申请,占用资源时不会形成环路。所有进程对资源的请求必须严格按资源序号递增的顺序提出。进程占用了小号资源,才能申请大号资源,就不会产生环路,从而预防了死锁。
32.什么叫守护线程,用什么方法实现守护线程
守护线程是为其他线程的运行提供服务的线程,后台运行的线程一般称为守护线程,比如JVM的垃圾回收、内存管理等线程。
setDaemon(boolean on)方法可以方便的设置线程的Daemon模式,true为守护模式,false为用户模式。在start方法调用之前使用,只有在当前jvm中所有的线程都为守护线程时,jvm才会退出。
33.Java线程池技术及原理
出现的原因:频繁创建线程和销毁线程需要时间
作用: 使线程可以复用,执行完一个任务,并不被销毁,可以继续执行其他的任务
核心类:ThreadPoolExecutor
DBCP
配置文件
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///mydata
username=root
password=123456
private static DataSource ds=null;
private static Properties pro=new Properties();
static{
InputStream in=JDBCTools.class.getClassLoader().getResourceAsStream("db.properties");
try {
pro.load(in);
ds=BasicDataSourceFactory.createDataSource(pro);
System.out.println(ds);
} catch (Exception e) {
e.printStackTrace();
}
}
C3P0
c3p0-config.xml
static{
ds=new ComboPooledDataSource("zwc");
}
http://www.importnew.com/19011.html
http://www.cnblogs.com/dolphin0520/p/3932921.html
34.volatile关键字
用volatile修饰的变量,线程在每次使用变量的时候,都会读取变量修改的最后的值。volatile很容易被误用,用来进行原子性操作。
Java语言中的volatile变量可以被看作是一种“程度较轻的synchronized”
35.IO和NIO区别
IO是面向流的,NIO是面向缓冲区的。
IO的各种流是阻塞的,NIO是非阻塞模式。
36.序列化与反序列化
把对象转换为字节序列的过程称为对象的序列化。
把字节序列恢复为对象的过程称为对象的反序列化。
对象的序列化主要有两种用途:
把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中
在网络上传送对象的字节序列。
当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个Java对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为Java对象。
37.内存溢出和内存泄漏的区别
内存溢出是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory。
内存泄漏是指分配出去的内存不再使用,但是无法回收。
38.JVM
栈:Java栈是线程私有的。
堆:存储Java程序创建的类实例。
方法区:class文件中的类型信息(类信息、常量、静态变量)存储位置
http://hllvm.group.iteye.com/group/wiki/2857-JVM
39.xml解析方式
DOM(JAXP Crimson解析器) SAX JDOM DOM4J
40.Statement和PreparedStatement之间的区别
1.PreparedStatement是预编译的,对于批量处理可以大大提高效率. 也叫JDBC存储过程
2.使用Statement 对象。在对数据库只执行一次性存取的时侯,用Statement 对象进行处理,效率比PreparedStatement好。
3.statement每次执行sql语句,相关数据库都要执行sql语句的编译,preparedstatement是预编译的
4.PreparedStatement安全性好,有效防止Sql注入等问题。
5. 对于多次重复执行的语句,使用PreparedStament效率会更高一点,并且在这种情况下也比较适合使用batch,preparedstatement支持批处理。
创建:
Statement stm=con.createStatement();
PreparedStatement pstm=con.prepareStatement(sql);
执行的时候:
stm.execute(sql);
pstm.execute();
批量操作
addBatch 添加到缓冲区
executeBatch 清空缓冲区,把数据写入到数据库
Connection conn = JDBCTools.getConnection();
String sql = "INSERT INTO t_user VALUES(?,?,?)";
PreparedStatement ps = conn.prepareStatement(sql);
for(int i = 0; i < 100; i++){
ps.setInt(1, i + 2);
ps.setString(2, "hehe"+ i);
ps.setString(3, "haha" + i);
ps.addBatch();//存入缓冲区
if(i % 8 == 0){
ps.executeBatch();//清空缓冲区,把数据写入到数据库
}}
if(100 % 8 != 0){
ps.executeBatch();
}
http://blog.csdn.net/yuekunge/article/details/8473718##1
41.Servlet生命周期及各个方法
Servlet 生命周期:Servlet 加载--->实例化--->服务--->销毁
init():在Servlet的生命周期中,仅执行一次init()方法。它是在服务器装入Servlet时执行的,负责初始化Servlet对象。可以配置服务器,以在启动服务器或客户机首次访问Servlet时装入Servlet。无论有多少客户机访问Servlet,都不会重复执行init()。
service():它是Servlet的核心,负责响应客户的请求。每当一个客户请求一个HttpServlet对象,该对象的Service()方法就要调用,而且传递给这个方法一个“请求”(ServletRequest)对象和一个“响应”(ServletResponse)对象作为参数。在HttpServlet中已存在Service()方法。默认的服务功能是调用与HTTP请求的方法相应的do功能。
destroy(): 仅执行一次,在服务器端停止且卸载Servlet时执行该方法。当Servlet对象退出生命周期时,负责释放占用的资源。一个Servlet在运行service()方法时可能会产生其他的线程,因此需要确认在调用destroy()方法时,这些线程已经终止或完成。
实现servet的三种方式
1.实现javax.servlet.Servlet的接口
2.继承javax.servlet.GeneriServlet
3.继承javax.servlet.HttpServlet
创建Servlet对象的时机:
1.Servlet容器启动时:读取web.xml配置文件中的信息,构造指定的Servlet对象,创建 ServletConfig对象,同时将ServletConfig对象作为参数来调用Servlet对象的init方法。
2.在Servlet容器启动后:客户首次向Servlet发出请求,Servlet容器会判断内存中是否存在指定的Servlet对象,如果没有则创建它,然后根据客户的请求创建HttpRequest、HttpResponse对象,从而调用Servlet 对象的service方法。
3.Servlet Servlet容器在启动时自动创建Servlet,这是由在web.xml文件中为Servlet设置的
load-on-startup元素标记容器是否在启动的时候就加载这个servlet,
匹配方式
1.精确匹配 2.通配符匹配 3.后缀匹配
优先级:精确匹配>通配符匹配>后缀匹配>页面地址
http://www.cnblogs.com/xuekyo/archive/2013/02/24/2924072.html
42.servlet中如何自定义filter
作用:对访问的请求和响应进行拦截
步骤:
Filter的生命周期
(1)init(FilterConfig filterConfig)throws ServletException:
Filter的创建和销毁由Web服务器负责。 web 应用程序启动时,web 服务器将创建Filter 的实例对象,并调用其init方法进行初始化(filter对象只会创建一次,init方法也只会执行一次。通过init方法的参数,可获得代表当前filter配置信息的FilterConfig对象)
(2)doFilter(ServletRequest,ServletResponse,FilterChain)
每次filter进行拦截都会执行
方法中参数request和response通常转换为HttpServletRequest和HttpServletResponse类型进行操作
(3)destroy():在Web容器卸载 Filter 对象之前被调用。
public class Filter1 implements Filter {
public Filter1() {
System.out.println("Filter被创建出来了。。。");
}
public void destroy() {
System.out.println("destory......");
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("dofilter....");
chain.doFilter(request, response);
}
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("init.....");
String value1 = filterConfig.getInitParameter("param1");
System.out.println(value1);
Enumeration enumeration =filterConfig.getInitParameterNames();
while(enumeration.hasMoreElements()){
String name = (String) enumeration.nextElement();
String value = filterConfig.getInitParameter(name);
System.out.println(name+":"+value);
}
filterConfig.getServletContext();
}
}
处理请求post乱码代码
request.setCharacterEncoding("utf-8");
设置响应编码集代码
response.setContentType("text/html;charset=utf-8");
详细:http://www.cnblogs.com/javawebsoa/archive/2013/07/31/3228858.html
43.JSP原理
JSP执行过程:
1)客户端发出请求(request ),请求访问JSP网页
2)JSP Container将要访问的.JSP文件 转译成Servlet的源代码(.java文件)
3)将产生的Servlet的源代码(.java文件)经过编译,生成.class文件,并加载到内存执行
4)最后把结果响应(response )给客户端
执行JSP网页文件时,需要经过两个时期:转译时期(TranslationTime)和请求时期(RequestTime)。
转译时期:JSP转译成Servlet类(.class文件)。
请求时期:Servlet类(.class文件)执行后,响应结果至客户端。
转译期间主要做了两件事情:
(1)将JSP网页转译为Servlet源代码(.java),此段称为转译时期(Translation time);
(2)将Servlet源代码(.java)编译成Servlet类(.class),此阶段称为编译时期(Compilation time)。
其实,JSP就是一个Servlet。
JSP页面中的指令
page:用来导入jar包以及设置属性
include:静态include只包含其内容,动态include包含的是整个页面
taglib:引入标签指令
http://blog.csdn.net/hanxuemin12345/article/details/23831645
44.四大作用域九大内置对象
pageContext 当前页面 request 一次请求
session 一次会话 application 整个web应用
45.Session、Cookie
会话:当向服务器发送请求的时候,服务器会给客户端响应一小段文本,之后该段文本再客户端于服务端进行来回传递的过程就称为一个会话在一个会话过程当中。客户端使用cookie来保存数据,服务端使用session来保存数据
如果将数据存储在服务器端,并且为这组数据标识一个编号,只将标号发回给客户端。当客户端向服务器发送请求时只需要将这个编号发过来,服务器端按照这个编号找到对应的数据进行管理的这种模式叫做Session
getSession()获取session对象
getAttribute(name)获取绑定数据
setAttribute(name,value)设置绑定数据
removeAttribute(name)清除绑定数据
Invalidate() 删除session对象
如果将数据存储在客户端,每次向服务器端发送请求时都将存在客户端的数据随着请求发送到服务器端,修改后在发回到客户端保存的这种模式叫做Cookie
//创建Cookie
Cookie cookie = new Cookie("name","xiaowang");
resp.addCookie(cookie); //把该cookie添加到response对象上
//删除Cookie
Cookie[] cookies = request.getCookies();
for(Cookie c : cookies){
//设置cookie生存时间,为0是即为删除
c.setMaxAge(70);
response.addCookie(c); }
//修改Cookie
Cookie[] cookies = request.getCookies();
for(Cookie c : cookies){
if(c.getName().equals("name")){
c.setValue("xiaohua");
response.addCookie(c);}}
//查找
Cookie[] cookies = request.getCookies();
for(Cookie c : cookies){
System.out.println(c.getName() + " " + c.getValue());}
编码:Cookie cookie = new Cookie("name",URLEncoder.encode(name));
解码:URLDecoder.decode(value, "utf-8")
url重写:解决cookie禁用的问题
Cookie的路径问题:只有符合路径规范的请求才会发送Cookie到服务器端,只有当访问的地址是Cookie的路径或者其子路径时,浏览器才发送Cookie到服务器端。
Cookie的特点
1.不安全
2.保存的数据量小,最多能保存4kb的数据
46.状态管理(Session、Cookie)
将客户端与服务器之间多次交互当做一个整体来看待,并且将多次交互中涉及的数据保存下来,提供给后续的交互进行数据的管理及状态管理
需要服务器端能够区分不同的客户端以及记录与客户端相关的一些数据,所以状态管理能够做到不同客户端的身份识别
47.JSP和Servlet的区别
48.JSTL标签库
选择标签
循环的数量:${vs.count}
循环的索引:${vs.index }
循环标签
49.EL表达式
${用于输出的数据} ${绑定名} ${绑定名.属性名}
50.JSP的动态include和静态include
动态include用jsp:include动作实现,如
静态include用include伪码实现,不会检查所含文件的变化,适用于包含静态页面,如<%@include file="qq.htm" %>,不会提前解析所要包含的页面,先把要显示的页面包含进来,然后统一编译,即先包含后编译。
51.Struts中请求处理过程
Servlet(控制层)中写html标签代码
ServletEm
p.zip
1.14MB
Servlet与html标签分离,加入jsp
ServletEmp_
1.zip
1.83MB
http://www.cnblogs.com/liuling/p/2013-8-10-01.html
Struts处理请求的步骤
1.客户端初始化一个指向Servlet容器的请求
2.这个请求经过一系列的过滤器(其中有一个ActionContextCleanUp的可选过滤器,有助于Struts2和其他框架的集成)
3.然后StructsPrepareAndExecuteFilter被调用,StrutsPrepareAndExecuteFilter询问ActionMapper来决定这个请求是否需要调用某个Action
4.如果ActionMapper决定需要某个Action,FilterDispatcher把请求的处理交给ActionProxy
5.ActionProxy通过ConfigurationManager来询问框架的配置文件,找到需要的Action类
6.ActionProxy创建一个ActionInvocation的实例
7.ActionInvocation实例使用命名模式来调用,在调用Action的过程前后,涉及到相关拦截器的调用。
8.当Action执行完毕,ActionInvocation负责根据struts.xml中的配置找到对应的返回结果
52.MVC概念
http://www.cnblogs.com/scwyh/articles/1436802.html
53.SpringMVC与Struts区别
http://blog.csdn.net/tch918/article/details/38305395
http://blog.csdn.net/chenleixing/article/details/44570681
54.Hibernate/Ibatis两者的区别
1.hibernate是全自动,mybatis是半自动。hibernate可以完全通过对象关系模型实现对数据库的操作,拥有完整的JavaBean对象与数据库的映射结构来自动生成sql,mybatis仅有基本字段映射,对象数据以及对象实际关系仍然需要通过手写sql
2.hibernate数据库移植性远大于mybatis。hibernate通过它强大的映射结构和hql语言,大大降低了对象与数据库的耦合性。mybatis手写的sql语句在不同的数据库中可能不通用。
3.hibernate拥有完整的日志系统,Mybatis本身不带日志统计,使用Log4j进行日志记录。
4.sql优化,mybatis要比hibernate方便很多。
http://blog.csdn.net/firejuly/article/details/8190229
55.Hibernate一级和二级缓存
缓存是介于物理数据源与应用程序之间,是对数据库中的数据复制一份临时放在内存中的容器,其作用是为了减少应用程序对物理数据源访问的次数,从而提高了应用程序的运行性能。
在同一个Session里面,第一次调用get()方法, Hibernate先检索缓存中是否有该查找对象,发现没有,Hibernate发送SELECT语句到数据库中取出相应的对象,然后将该对象放入缓存中,以便下次使用,第二次调用get()方法,Hibernate先检索缓存中是否有该查找对象,发现正好有该查找对象,就从缓存中取出来,不再去数据库中检索,没有再次发送select语句。
适合放到二级缓存中:
1.经常被访问 2.改动不大 3.数量有限 4.不是很重要的数据,允许出现偶尔并发的数据。
http://blog.csdn.net/windrui/article/details/23165845
56.简述Hibernate常见优化策略
http://blog.csdn.net/shimiso/article/details/8819114
57.Springbean的加载过程(推荐看Spring的源码)
Web项目使用Spring是通过在web.xml里面配置
org.springframework.web.context.ContextLoaderListener初始化IOC容器的。
http://geeekr.com/read-spring-source-1-how-to-load-bean/
58.Springbean的实例化(推荐看Spring的源码)
通过JDK反射特性,直接set值的
http://geeekr.com/read-spring-source-two-beans-initialization/
59.Spring如何实现AOP和IOC(推荐看Spring的源码)
1.IOC是指容器控制程序对象之间的关系,传统实现是由代码直接操控,控制权由应用代码中转到了外部容器,控制权的转移叫做控制反转(依赖注入)。即组件之间的依赖关系,由容器在运行期决定,由容器动态的将某种依赖关系注入到组件中。
2.在Spring的工作方式中,所有的类都会在Spring容器中登记,告诉Spring这是个什么东西,你需要什么东西,然后Spring会在系统运行到合适的时候,把你想要的东西主动给你,同时也把你需要的其他东西交给你。所有的类的创建、销毁都由Spring来控制,这种方式叫做控制反转。
3.在系统运行中,动态的向某个对象提供他所需要的其他对象。
4.依赖注入的思想是通过反射机制实现的,在实例化一个类时,他通过调用类中的set方法将事先保存在HashMap中的类属性注入到类中。
技术支撑点:XML解析+反射
注入方式
1.属性注入2.构造注入3.依赖注入
id:在IOC容器中对象的唯一标识 ctx.getBean(id)获取对象
class:Spring框架需要通过反射机制生成实例化对象
技术支撑点:XML解析+反射
好处:降低了组件之间的耦合和业务对象之间替换的复杂性
AOP面向切面编程
实现技术:日志+事务+校验+代理模式
1.面向切面编程提供声明式事务管理
2.Spring支持用户自定义的切面
http://www.360doc.com/content/15/0116/21/12385684_441408260.shtml
60.Springbean注入方式
http://blessht.iteye.com/blog/1162131
61.Spring的事务管理
事务有四个特性:ACID
Spring不直接管理事务,提供事务管理器,将事务管理的职责委托给Hibernate或者JPA等持久化机制所提供的相关平台框架的事务来实现。
持久化把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘)。持久化的主要应用是将内存中的对象存储在关系型的数据库中。
JDBC事务
通过DataSourceTransactionManager调用java.sql.Connection来管理事务,而后者是通过DataSource获取到的。通过调用连接的commit()方法来提交事务,同样,事务失败则通过调用rollback()方法进行回滚。
Hibernate事务
通过HibernateTransactionManager将事务管理的职责委托给org.hibernate.Transaction对象,而后者是从Hibernate Session中获取到的。当事务成功完成时,会调用Transaction对象的commit()方法,反之,将会调用rollback()方法。
Java持久化API事务(JPA)
使用Spring的JpaTransactionManager来处理事务
http://blog.csdn.net/trigl/article/details/50968079
62.Spring事务的传播特性
http://blog.csdn.net/lfsf802/article/details/9417095
63.SpringMVC原理
3-4.DispatcherServlet根据HandlerMapping找到对应的Handler,将处理权交给Handler(Handler将具体的处理进行封装),再由 具体的HandlerAdapter对Handler进行具体的调用
5.Handler对数据处理完后将返回一个ModelAndView()对象给DispatcherServlet。
6.Handler返回的ModelView()只是一个逻辑视图,DispatcherServlet通过ViewResolver将逻辑视图转化为真正的视图View。
7.Dispatcher通过model解析出ModelAndView()中的参数进行解释最终展现出完整的view并返回给客户端
SpringMVC框架配置文件的4项基本项:
1-组件扫描
2-动态资源请求(支持注解)
3-静态资源请求
4-视图解析器
@DateTimeFormat(pattern="yyyy-MM-dd")
http://blog.sina.com.cn/s/blog_7ef0a3fb0101po57.html
64.springmvc用过哪些注解
1. @Controller
定义控制器,允许自动检测定义在类路径下的组件并自动注册。
2. @RequestMapping
将URL映射到整个类或特定的处理方法上
3. @PathVariable
注解方法参数并将其绑定到URI模板变量的值上
4. @RequestParam
方法参数应该被绑定到HTTP请求Body上
将请求的参数绑定到方法中的参数上,即使不配置该参数,注解也会默认使用该参数。如果想自定义指定参数的话,如果将@RequestParam的 required 属性设置为false(@RequestParam(value="id",required=false))
5. @RequestBody
方法参数应该被绑定到HTTP请求Body上
6. @ResponseBody
将返回类型直接输入到HTTP response body中
65.Restful有几种请求
HTTP协议中规定的四种操作方式: POST DELETE PUT GET
对应JAVA服务程序提供的四种服务: 增 删 改 查
http://www.infoq.com/cn/articles/designing-restful-http-apps-roth
66.json和xml区别
XML:应用广泛、可扩展性强读取、可读性强、可描述复杂结构
JSON:结构简单、读取、解析速度快、传输数据量小、描述复杂结构能力较弱
67.设计模式的六大原则
http://www.uml.org.cn/sjms/201211023.asp
68.数据库范式
第一范式(1NF)无重复的列
第二范式(2NF)属性完全依赖于主键
第三范式(3NF)属性不依赖于其它非主属性
http://www.360doc.com/content/12/0712/20/5287961_223855037.shtml
69.数据库事务隔离级别
Serializable(串行化):一个事务在执行过程中完全看不到其他事务对数据库所做的更新。
Repeatable Read(可重复读):一个事务在执行过程中可以看到其他事务已经提交的新插入的记录,但是不能看到其他事务对已有记录的更新。
Read Commited(读已提交数据):一个事务在执行过程中可以看到其他事务已经提交的新插入的记录,而且能看到其他事务已经提交的对已有记录的更新
Read Uncomitted(读未提交数据):一个事务在执行过程中可以拷打其他事务没有提交的新插入的记录,而且能看到其他事务没有提交的对已有记录的更新。
隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。
http://blog.csdn.net/fg2006/article/details/6937413
70.数据库连接池的原理
http://blog.csdn.net/shuaihj/article/details/14223015
71.乐观锁和悲观锁
http://www.open-open.com/lib/view/open1452046967245.html
72.如何实现不同数据库的数据查询分页
http://blog.csdn.net/yztezhl/article/details/20489387
73.SQL注入的原理,如何预防
https://www.aliyun.com/zixun/content/3_15_245099.html
74.数据库索引的实现(B+树介绍、和B树、R树区别)
http://blog.csdn.net/kennyrose/article/details/7532032
http://www.xuebuyuan.com/2216918.html
75.SQL性能优化
http://database.51cto.com/art/200904/118526.htm
http://www.cnblogs.com/rootq/archive/2008/11/17/1334727.html
76.数据库索引的优缺点以及什么时候数据库索引失效
http://www.cnblogs.com/mxmbk/articles/5226344.html
http://www.cnblogs.com/simplefrog/archive/2012/07/15/2592527.html
http://www.open-open.com/lib/view/open1418476492792.html
http://blog.csdn.net/colin_liu2009/article/details/7301089
http://www.cnblogs.com/hongfei/archive/2012/10/20/2732589.html
77.Redis的数据类型
http://blog.csdn.net/hechurui/article/details/49508735
78.HTTP和HTTPS区别
http://blog.csdn.net/mingli198611/article/details/8055261
http://www.mahaixiang.cn/internet/1233.html
79.get提交和post提交的区别
http://www.cnblogs.com/hyddd/archive/2009/03/31/1426026.html
http://www.jellythink.com/archives/806
80.get提交是否有字节限制,如果有是在哪限制的
http://www.jellythink.com/archives/806
81.TCP的三次握手和四次挥手
http://www.jianshu.com/p/f7d1010fa603
82.session和cookie的区别
http://www.cnblogs.com/shiyangxt/archive/2008/10/07/1305506.html
83.HTTP请求中Session实现原理
http://blog.csdn.net/zhq426/article/details/2992488
84.redirect与forward区别
http://www.cnblogs.com/wxgblogs/p/5602849.html
85.TCP和UDP区别
TCP:不允许产生哪怕一个字节的损失,数据必须全部抵达。
网络绅士 ---JAVA:Socket套接字 IO流
UDP:空投(允许损失,特别快)
网络土匪 视频通话 --JAVA:DatagramSocket DatagramPacket
参考http://www.cnblogs.com/bizhu/archive/2012/05/12/2497493.html
86.Linux
87.this的作用
1.this可以区别成员变量与局部变量
2.用来指代当前对象
3.this可以作为参数进行传递
4.在本类中调用属性和方法
5.this()可以调用其他构造方法(必须放在第一行)
88.static
static修饰的变量成为静态变量(类变量),存在与方法区中(类名.变量),方法去中保存了类的信息,静态方法随着类加载就加载到内存当中。
注意:静态放法不能调用非静态变量,static不能修饰类可以修饰内部类
89.内部类
1.成员内部类 2.局部内部类 3.静态内部类 4.匿名内部类
90.排序
冒泡: for(int i=0;i for(int j=0;j if(a[ j ]>a[ j+1]){ temp=a[ j ]; a[ j ]=a[ j+1]; a[ j+1]=temp; }}} 快速:for(int i=0;i for(int j=i+1;j if(a[ i ]>a[ j ]){ temp=a[ i ]; a[ i ]=a[ j ]; a[ j ]=temp; } } } 插入:for(int i=1;i for(int j=i;j>0;j--){ if(a[ j-1]>a[ j ]){ temp=a[ j -1]; a[ j-1]=a[ j ]; a[ j ]=temp; } } } 91.二分查找 public static int binarySearch(int[] arr,int num) { int min = 0; int max = arr.length - 1; int middle = (min + max) / 2; while(true) { if(arr[middle] > num){ max = middle - 1; }else if(arr[middle] < num){ min = middle + 1; }else{ return middle; } middle = (max + min) / 2; if(max < min){ break;} } return -1; } 92.递归 兔子繁殖问题 public static int f(int a){ if(a==1||a==2) return 2; else return f(a-1)+f(a-2); } 93.IO流 按照IO流方向:输入流,输出流 按照IO流:字节流(byte) 字符流(char) 节点流:直接与资源交互的流 处理流:不直接与资源交互,直接与其它的流进行交互 字节流和字符流的相互转化 byte[] result2 = msg.getBytes("utf-8") new String(result2,"GBK"); 94.File类 delete() 删除此抽象路径名表示的文件或目录 exists() 测试此抽象路径名表示的文件或目录是否存在 createNewFile() 当且仅当不存在具有此抽象路径名指定名称的文件时,不可分地创建一个新的空文件 isDirectory() 测试此抽象路径名表示的文件是否是一个目录 getName() 返回由此抽象路径名表示的文件或目录的名称 length() 返回由此抽象路径名表示的文件的长度 mkdir() 创建此抽象路径名指定的目录 遍历文件夹下的所有文件 public void traverseFolder2(String path) { File file = new File(path); if (file.exists()) { File[] files = file.listFiles(); if (files.length == 0) { System.out.println("文件夹是空的!"); return; } else { for (File file2 : files) { if (file2.isDirectory()) { System.out.println("文件夹:" + file2.getAbsolutePath()); traverseFolder2(file2.getAbsolutePath()); } else { System.out.println("文件:" + file2.getAbsolutePath()); } } } } else { System.out.println("文件不存在!"); } } 遍历文件夹下的所有avi文件 public static List 95.Socket通讯 96.反射 实现在运行时可以知道任意一个类的属性和方法 获得Class对象三种方式 类名.class 对象.getClass() Class.forName() Method[] methods = class1.getDeclaredMethods();//获取class对象的所有声明方法 Field[] allFields = class1.getDeclaredFields();//获取class对象的所有属性 97.类装载器 把类装载进JVM的 启动类装载器和用户自定义装载器 JVM在运行时会产生3个类加载器组成的初始化加载器层次结构 引导类加载器 扩展类加载器 系统类加载器 98.MySQL 查询语句书写顺序:select – from- where- group by- having- order by-limit 查询语句执行顺序:from - where -group by - having - select - order by-limit having与where的区别: 1.having是在分组后对数据进行过滤 where是在分组前对数据进行过滤 2.having后面可以使用分组函数 where后面不可以使用分组函数 SELECT *,sal+IFNULL(comm,0) FROM emp; 完整性的分类:实体完整性、域完整性、引用完整性 约束类型: 主键约束(primary key) 唯一约束(unique) 自动增长列(auto_increment) 域完整性约束:数据类型 非空约束(not null) 默认值约束(default) 外键列的数据类型一定要与主键的类型一致 MySQL数据库引擎: Innodb引擎(提供了对数据库ACID事务的支持实现了SQL标准的四种隔离级别) MyIASM引擎(没有提供对数据库事务的支持) 99.工作流 员工请假申请——上级口头同意——上级将请假记录下来——月底将请假记录上交公司——公司将请假录入电脑 采用工作流技术的公司的请假流程是这样的 员工使用账户登录系统——点击请假——上级登录系统点击允许 JBPM和Activity是两个主流的工作流系统 100.Hibernate框架 核心:ORM(对象关系映射) clas类——>表 property属性——>字段 方法——>SQL语句 //在单例模式下,session只有唯一的一个,可以通过ThreadLocal实现session的"线程私有" //也就是说,进程中每启动一个线程,就生成一个新的session(满足并发操作要求) private static final ThreadLocal openSession方法: 必须对session进行手动关闭,并且需要用到ThreadLocal实现线程私有. getCurrentSession方法:创建的session会自动绑定到当前线程,并在在事务提交或者回滚后自动关闭session. 配置文件配置内容: 1.方言(Hibernate框架不依赖任何数据库需要用过dialect确认匹配何种数据库)* 2.数据库连接配置信息,配置连接池信息 3.提高性能的两个配置(读取记录数,批量操作数) 4.打印排版sql * 5.配置正向工程创建数据库中的表 * 6.注册ORM映射配置信息 7.如果数据库是MySQL要配置事务隔离级别为2(读已提交) 8.设置getCurrentSession方法的context上下文信息(取决于有没有配置Spring事务管理器) 持久化:把对象永久保存到数据库并进行各种操作 ORM框架是对JDBC的封装 clear方法(清空缓存) evict方法(从缓存中清除指定持久化对象) get()立即检索 load()延迟检索(如果get与load所要检索的对象不存在,则get方法返回null,而load方法会抛出异常) con1:是否获得了与数据库现存记录相对应的oid[ObjectId] 主键--带没带牌 con2:是否存在于Session缓存中---是否在公司上班 主流的教材认为有三种: 临时状态(transient):不带工牌,不在公司 持久化状态(persistent)带工牌,在公司 游离状态(detached)带工牌,不在公司 无论对象状态是Transient还是Detached,通过saveOrUpdate方法都能够转变为persistent持久化状态 delete方法,存在oid对应的记录,则删除,否则,抛出异常(配置文件配置实现Session执行了delete方法后,将处于删除状态的对象的oid置空,使其成为临时对象) assign:适合于由程序员维护主键 日期设置成Hibernate数据类型 date(日期) time(时间) timestamp(日期+时间) 两个POJO类对象,映射一张表,使用了component组件标签 101.Mybatis三剑客 generator:根据数据库自动生成pojo、dao、xml文件 1.引入generatorConfig.xml(需要在pom.xml里配制 2.新建dataSource.properties配置数据库连接信息(mysql-connector-java-5.1.6-bin.jar) plugin:配置能够追踪dao接口和mapper文件里xml的一个插件,支持参数自动补全(基于@Param注解识别参数) pageHelper:开源的分页插件,通过spring的AOP来实现的,能在执行sql的时候,把相关的数据再执行一次 mybatis配置文件:别名、缓存、插件、数据库连接环境、配置事务管理(事务管理器、事务管理、aop) SELECT * FROM POST P WHERE ID in #{item} 102.Shiro 认证、授权、会话管理、加密 Token令牌 Base64双向 加密:Base64.encodeToString(str.getBytes()) 解密:Base64.decodeToString(str) MD5单向 public class ShiroFirst { public static final Logger log = LoggerFactory.getLogger(ShiroFirst.class);//获取Logger日志对象 public static void main(String[] args) { //1-创建SecurityManager安全管理器对象,读取shiro配置文件信息 SecurityManager securityManager = new IniSecurityManagerFactory("classpath:shiro.ini").getInstance(); SecurityUtils.setSecurityManager(securityManager);//2-配置安全管理工具SecurityUtil Subject authenSubject = SecurityUtils.getSubject();//3-获得Subject对象 //4-获取Token令牌 AuthenticationToken successToken = new UsernamePasswordToken("scott", "tiger");//成功 AuthenticationToken errorToken = new UsernamePasswordToken("scott", "sdjfls");//失败 try { //5-Subject对象验证Token令牌,成功继续执行,失败抛出异常 // authenSubject.login(successToken); authenSubject.login(errorToken); log.info("login success!"); } catch (Exception e) { e.printStackTrace(); log.error("login error!"); } //6-注销登录信息 authenSubject.logout(); } } Token机制与Cookie机制 1.支持跨域访问:Cookie是不允许 2.无状态:Token机制在服务端不需要存储session信息,因为Token 自身包含了所有登录用户的信息,只需要在客户端的cookie或本地介质存储状态信息. 3.更适用CDN 4.去耦: 不需要绑定到一个特定的身份验证方案 Shiro 从 Realm 中获取验证数据,实际项目中我们使用jdbc realm较多,提升保密级别 权限认证 角色role:权限的集合,一种角色可以被很多个用户拥有,一种角色可以包含多种权限 用户user:访问系统的用户,被封装成 安全主体Subject对象 权限permission:操作资源的权利 public class ShiroAuthorization { public static void main(String[] args) { //admin=123456,role1,role2,role3,获取认证身份 Subject currentUser = ShiroUtils.login("authorization_shiro.ini","admin","123456"); System.out.println("principal:"+currentUser.getPrincipal()); //判断是否拥有某一个角色 System.out.println("***hasRole***:"); System.out.println("role1:"+currentUser.hasRole("role1")); //遍历集合中的每一个角色,判断用户是否拥有,有返回true,没有返回false,返回值是boolean数组 System.out.println("***hasRoles***"); List boolean[] results = currentUser.hasRoles(roles); for(int i=0;i System.out.println(roles.get(i)+":" +results[i]); } //判断用户是否拥有集合中的所有角色,拥有所有返回true,否则返回false System.out.println("***hasAllRoles***"); System.out.println("hasAllRoles:"+currentUser.hasAllRoles(Arrays.asList("role2","role3"))); currentUser.logout(); } } System.out.println(currentUser.isPermitted("user.delete")?"has delete permission!":"has no delete permission"); 实际开发中,需要自定义Realm来从数据库中查询数据并返回结果实现对角色、用户、权限的匹配,MyRealm类需要继承AuthorizingRealm类 103.REST风格 在web.xml中对HiddenHttpMethodFilter进行设置 修改页面请求提交方式 修改Handler处理器 多个参数问题 @RequestMapping(value="/{username}/{a}/{b}/update",method=RequestMethod.GET) public String update(@PathVariable String username,@PathVariable String a,@PathVariable String b, Model model){ System.out.println("获取到传入的参数值为:" + username); model.addAttribute(users.get(username)); return "user/update"; } "redirect:"指向当前链接位置 "redirect:/"指向当前项目位置 104.Freemaker 静态化页面,被用来生成html页面 <#标签名称>命名 ${value} 表示输出变量名的内容 <#list nameList as names> ${names} #list>