读书笔记--Java核心技术--高级特征
第一章--流与文件----------------------------------------------
流
读写字节
java.io.InputStream 1.0
abstractint read()//从数据中读入一个字节,并返回该字节,在碰到流的结尾时返回-1int read(byte[] b)//读入一个字节数组,并返回实际读入的字节数,或者在碰到流的结尾时返回-1int read(byte[] b,int off,int len)//读入一个字节数组。这个read方法返回实际读入的字节数,或者在碰到流的结尾时返回-1long skip(long n)//在输入流中跳过n个字节,返回实际跳过的字节数(如果碰到流的结尾,则可能小于n)int available()//返回在不阻塞的情况下可用的字节数void close()//关闭这个输入流void mark(int readLimit)//在输入流的当前位置打一个标记,如果输入流中已经读入的字节多于readLimit个,则这个流允许忽略这个标记void reset()//返回到最后的标记,随后对read的调用将重新读入这些字节boolean markSupported()//如果这个流支持打标记,则返回true
java.io.OutputStream 1.0
abstractvoid write(int n)//写出一个字节的数据void write(byte[] b)void write(byte[] b,int off,int len)//写出所有字节或者某个范围的字节到数组b中void close()//清空并关闭输出流void flush()//清空输出流,也就是将所有缓冲的数据发送到目的地
流家族
InputStream和OutputStream为基础
DataInputStream和DataOutputStream可以以二进制格式读写所有的基本Java类型
ZipInputStream和ZipOutputStream可以以常见的ZIP压缩格式读写文件
4个附加接口:Closeable、Flushable、Readable和Appendable
java.io.Closeable 5.0
void close()//关闭这个Closeable,可能会抛出IOException
java.io.Flushable 5.0
void flush()//清空这个Flushable
java.lang.Readable 5.0
int read(CharBuffer cb)//尝试读入cb可以持有的数量的char值。返回读入的char值的数量
java.lang.Appendable 5.0
Appendable append(char c)Appendable append(CharSequence cs)//向这个Appendable中追加给定的码元或者给定的序列中的所有码元,返回this
java.lang.CharSequence 1.4
char charAt(int index)//返回给定索引处的码元int length()//返回这个序列中的码元的数量CharSequence subSequence(int startIndex,int endIndex)//返回由存储在startIndex到endIndex - 1处的所有码元构成的CharSequenceString toString()//返回这个序列中所有码元构成的字符串
组合流过滤器
FileInputStream fin =newFileInputStream("employee.dat");DataInputStream din =newDataInputStream(fin);double s = din.readDouble();
使用缓冲机制
DataInputStream din =newDataInputStream(newBufferedInputStream(newFileInputStream("employee.dat")));
从一个ZIP压缩文件中读入数字
ZipInputStream zin =newZipInputStream(newFileInputStream("employee.zip"));DataInputStream din =newDataInputStream(zin);
java.io.FileInputStream 1.0
FileInputStream(String name)FileInputStream(File file)//使用由name字符串或file对象指定路径名的文件创建一个新的文件输入流
java.io.FileOutputStream 1.0
FileOutputStream(String name)FileOutputStream(String name,boolean append)FileOutputStream(File file)FileOutputStream(File file,boolean append) //使用由name字符串或file对象指定路径名的文件创建一个新的文件输出流
java.io.BufferedInputStream 1.0
BufferedInputStream(InputStream in)//创建一个带缓冲区的流
java.io.BufferdOutputStream 1.0
BufferedOutputStream(OutputStream out)//创建一个带缓冲区的流
java.io.PushbackInputStream 1.0
PushbackInputStream(InputStream in)PushbackInputStream(InputStream in,int size)//构建一个可以预览一个字节或者具有指定尺寸的回推缓冲区的流- void unread(int b)//回推一个字节,它可以在下次调用read时被再次获取,b:要再次读入的字节
文本输入与输出
InputStreamReader in =newInputStreamReader(newFileInputStream("input.txt"),"ISO8859_5");- 等价于
FileReader in =newFileReader("input.txt"):
以文本格式打印字符串和数字
PrintWriter out =newPrintWriter("employee.txt"):等同于PrintWriter out =newPrintWriter(newFileWriter("employee.txt"));
System.out是PrintStream类,在内部采用与PrintWriter相同的方式将Unicode字符转换成了默认的主机编码方式。与PrintWriter不同的是,它们允许我们用write(int)和write(byte[])方法输出原生字节
java.io.PrintWriter 1.1
PrintWriter(Writer out)PrintWriter(Writer out,boolean autoFlush)//创建一个新的PrintWriterPrintWriter(OutputStream out)PrintWriter(OutputStream out,boolean autoflush)//通过创建必需的中介OutputStreamWriter,从已有的OutputStream中创建一个新的PrintWriterPrintWriter(String filename)PrintWriter(File file)//通过创建必需的中介FileWriter,创建一个想给定的文件写出的新的PrintWritervoid print(Object obj)//通过打印从toString产生的字符串来打印一个对象void print(String s)//打印一个Unicode字符串void println(String s)//打印一个字符串,后面紧跟一个行终止符void print(char[] s)//打印给定的字符串中的所有Unicode字符void print(char c)//打印一个Unicode字符void print(int i)void print(long l)void print(float f)void print(double d)void print(boolean b)//以文本格式打印给定的值void printf(String format,Object... args)//按照格式化字符串指定的方式打印给定的值boolean checkError()//如果产生格式化或输出错误,返回true
使用Scanner读入文本输入
Java SE 5.0之前,处理文本的唯一方式就是BufferedReader类,它拥有一个readLine方法,可以读入一行文本
BufferedReader in =newBufferedReader(newFileReader("employee.txt"));
字符集
//编码Unicode字符串Charset cset =Charset.forName("ISO-8859-1"):String str =...;ByteBuffer buffer = cset.encode(str);byte[] bytes = buffer.array();//解码字节序列byte[] bytes =...;ByteBuffer bbuf =ByteBuffer.wrap(bytes, offset, length);CharBuffer cbuf = cset.decode(bbuf);String str = cbuf.toString();
java.nio.charset.Charset 1.4
staticSortedMap availableCharsets()//获取这个虚拟机可用的所有字符集。返回一个映射表,它的键是字符集的名字,值是字符集staticCharset forName(String name)//获取给定名字的字符集Set aliases()//返回这个字符集的别名集ByteBuffer encode(String str)//将给定的字符串编码为字节序列CharBuffer decode(ByteBuffer buffer)//解码给定的字节序列,无法识别的输入将被转换成Unicode的“替代字符”(’\uFFFD')
java.nio.ByteBuffer 1.4
byte[] array()//返回这个缓冲区所管理的字节数组staticByteBuffer wrap(byte[] bytes)staticByteBuffer wrap(byte[] bytes,int offset,int length)//返回管理给定的字节数组或给定字节数组的某个范围的字节缓冲区
java.nio.CharBuffer
char[] array()//返回这个缓冲区所管理的码元数组char charAt(int index)//返回给定索引处的码元String toString()//返回由这个缓冲区所管理的码元构成的字符串
读写二进制数据
DataInputStream类实现了DataInput接口
java.io.DataInput 1.0
boolean readBoolean()byte readByte()char readChar()double readDouble()float readFloat()int readInt()long readLong()short readShort()//读入一个给定类型的值void readFully(byte[] b)//将字节读入到数组b中,其间阻塞直至所有字节都读入void readFully(byte[] b,int off,int len)//将字节读入到数组b中,其间阻塞直至所有字节都读入String readUTF()//读入由“修订过的UTF-8”格式的字符构成的字符串int skipBytes(int n)//跳过n个字节,其间阻塞直至所有字节都被跳过
java.io.DataOutput 1.0
void writeBoolean(boolean b)void writeByte(int b)void writeChar(int c)void writeDouble(double d)void writeFloat(float f)void writeInt(int i)void writeLong(long l)void writeShort(int s)//写出一个给定类型的值void writeChars(String s)//写出字符串中的所有字符void writeUTF(String s)//写出由“修订过的UTF-8”格式的字符构成的字符串
随机访问文件
RandomAccessFile类可以在文件中的任何位置查找或写入数据,通过“r"或"rw"来指定。同时实现了DataInput和DataOutput接口
java.io.RandomAccessFile 1.0
RandomAccessFile(String file,String mode)RandomAccessFile(File file,String mode)//file:要打开的文件,mode:"r"表示只读模式,"rw"表示读/写模式long getFilePointer()//返回文件指针的当前位置void seek(long pos)//将文件指针从文件的开始设置到pos个字节处long length()//返回文件按照字节来度量的长度
ZIP文档
通读ZIP文件代码:
ZipInputStream zin =newZipInputStream(newFileInputStream(zipname));ZipEntry entry;while((entry = zin.getNextEntry())!=null){analyze entry;read the contents of zin;zin.closeEntry();}zin.close();
写出ZIP文件代码:
FileOutputStream fout =newFileOutputStream("test.zip");ZipOutputStream zout =newZipOutputStream(fout);for all files{ZipEntry ze =newZipEntry(filename);zout.putNextEntry(ze);send data to zout;zout.closeEntry();}zout.close();
java.util.zip.ZipInputStream 1.1
ZipInputStream(InputStream in)//创建一个ZipInputStreamZipEntry getNextEntry()//为下一项返回ZipEntry对象,否则没有更多的项时返回nullvoid closeEntry()//关闭这个ZIP文件中当前打开的项
java.util.zip.ZipOutputStream 1.1
ZipOutputStream(OutputStream out)//创建一个将压缩数据写出到指定的OutputStream的ZipOutputStreamvoid putNextEntry(ZipEntry ze)//将给定的ZipEntry中的信息写出到流中,并定为用于写出数据的流,然后这些数据可以通过write()写出到这个流中void closeEntry()//关闭这个ZIP文件中当前打开的项void setLevel(int level)//设置后续的各个DEFAULTED项的默认压缩级别。void setMethod(int method)//设置用于这个ZipOutputStream的默认压缩方法,压缩方法:DEFLATED或STORED
java.util.zip.ZipEntry 1.1
ZipEntry(String name)//这一项的名字long getCrc()//返回用于这个ZipEntry的CRC32校验和的值String getName()//返回这一项的名字long getSize()//返回这一项不被压缩的大小boolean isDirectory()//当这一项是目录时返回truevoid setSize(long size)//设置这一项的大小,当压缩方法是STORED时才必需void setCrc(long crc)//给这一项设置CRC32校验和,这个校验和是使用CRC32类计算的,STORED时必需
java.util.zip.ZipFile 1.1
ZipFile(String name)ZipFile(File file)//创建一个ZipFile,用于从给定的字符串或File对象中读入数据Enumeration entries()//返回一个Enumeration对象,它枚举了描述这个ZipFile中各个项的ZipEntry对象ZipEntry getEntry(String name)//返回给定名字所对应的项,或者在没有对应项的时候返回nullInputStream getInputStream(ZipEntry ze)//返回用于给定项的InputStreamString getName()//返回这个ZIP文件的路径
对象流与序列化
对象序列化(object serialization)
ObjectInputStream和ObjectOutputStream类,readObject和writeObject方法
在对象流中存储或恢复的所有类都需要实现Serializable接口
java.io.ObjectOutputStream 1.1
ObjectOutputStream(OutputStream out)//创建一个ObjectOutputStream使得你可以将对象写出到指定的OutputStreamvoid writeObject(Object obj)//写出指定的对象到ObjectOutputStream,这个方法将存储指定对象的类、类的签名以及这个类及其超类中所有非静态和非瞬时的域的值
java.io.ObjectInputStream 1.1
ObjectInputStream(InputStream in)//创建一个ObjectInputStream用于从指定的InputSream中读回对象信息Object readObject()//从ObjectInputStream中读入一个对象
对象流输出中包含所有对象的类型和数据域
每个对象都被赋予一个序列号
相同对象的重复出现将被存储为对这个对象的序列号的引用
修改默认的序列化机制
防止不应该被序列化的域被序列化,标记成transient
可序列化的类可以定义下列方法:
privatevoid readObject(ObjectInputStream in)throwsIOException,ClassNotFoundException;privatevoid writeObject(ObjectOutputStream out)throwsIOException;
之后,数据域就不再自动序列化,而是调用这些方法
类还可以定义它自己的机制,必须实现Externalizable接口,定义两个方法:
publicvoid readExternal(ObjectInputStream in)throwsIOException,ClassNotFoundException;publicvoid writeExternal(ObjectOutputStream out)throwsIOException;
序列化单例和类型安全的枚举
请记住向遗留代码中所有类型安全的枚举以及向所有支持单例设计模式的类中添加readResolve方法
版本管理
运行JDK中的单机程序serialver
serialver Employee
这个类的所有版本都需要定义
public static final long serialVersionUID = -184528436328947893L;
文件管理
File类
可以用FileNameFilter对象作为list方法的参数来减小列表长度,一个实现FileNameFilter接口的类需要定义accept方法
使用File类中存储在名为separator的静态实例域中的有关当前目录分隔符的信息可以得到系统恰当的分隔符
java.io.File 1.0
boolean canRead()boolean canWrite()boolean canExecute()//表明文件是否可读、可写或可执行boolean setReadable(boolean state,boolean ownerOnly)boolean setWritable(boolean state,boolean ownerOnly)boolean setExecutable(boolean state,boolean ownerOnly)//设置这个文件的可读、可写或可执行状态。如果ownerOnly为true,状态设置只对文件拥有者有效,否则,对所有人有效。这些方法在设置状态成功后返回truestaticboolean createTempFile(String prefix,String suffix)staticboolean createTempFile(String prefix,String suffix,File directory)//在系统的默认临时目录或给定目录中创建一个临时文件,并使用给定的前缀或后缀来生成文件名booleandelete()//尝试删除这个文件void deleteOnExit()//请求在虚拟机关闭时将文件删除boolean exists()//如果目录存在则返回trueString getAbsolutePath()//返回包含绝对路径名的字符串,应该用getCanonicalPath代替它File getCanonicalFile()//返回包含这个文件的规范路径名的File对象String getCanonicalPath()//返回包含这个文件的规范路径名的字符串String getName()//返回包含这个File对象的文件名的字符串(不包含路径)String getParent()//返回这个File对象的父亲名字的字符串File getParentFile()//返回这个File目录的父目录的File对象String getPath()//返回包含这个文件的路径名的字符串boolean isDirectory()//如果这个File对象表示一个文件而不是一个目录或一个设备,则返回trueboolean isFile()//如果这个File对象表示一个文件而不是一个目录或一个设备,则返回trueboolean isHidden()//如果这个File对象表示的是一个隐藏文件或目录,则返回truelong lastModified()//返回这个文件最后被修改的时间(毫秒数)String[] list()String[] list(FilenameFilter filter)//返回由这个File对象包含的满足过滤器条件的文件名和目录名构成的字符串数组File[] listFiles()File[] listFiles(FilenameFilter filter)//返回由这个File对象包含的文件和目录所对应的File对象构成的数组staticFile[] listRoots()//返回由所有可获得的文件根对应的File对象构成的数组boolean createNewFile()//自动创建一个由File对象给定名字的新文件boolean mkdir()//创建一个由这个File对象给定名字的子目录boolean mkdirs()//与mkdir不同,这个方法在必要时将创建父目录boolean renameTo(File newName)//如果文件名被修改,则返回trueboolean setLastModified(long time)//设置这个文件的最后修改时间boolean setReadOnly()//将这个文件设置成只读URL toURL()//将这个File对象转换成一个文件的URLlong getTotalSpace()long getFreeSpace()long getUsableSpace()//获得由File对象所描述的分区的总大小、未分配字节的数量和可用字节的数量
java.io.FilenameFilter 1.0
boolean accept(File dir,String name)//应该定义为在文件能够匹配过滤器标准时返回true
新IO
内存映射文件
java.io.FileInputStream 1.0
FileChannel getChannel()//返回用于访问这个流的通道
java.io.FileOutputStream 1.0
FileChannel getChannel()//返回用于访问这个流的通道
java.io.RandomAccessFile 1.0
FileChannel getChannel()//返回用于访问这个流的通道
java.nio.channels.FileChannel 1.4
MappedByteBuffer map(FileChannel.MapMode mode,long position,long size)//将文件的一个区域映射到内存中
java.nio.Buffer 1.4
boolean hasRemaining()//如果当前的缓冲区位置没有达到这个缓冲区的界限位置则返回trueint limit()//返回这个缓冲区的界限位置
java.nio.ByteBuffer 1.4
byte get()//从当前位置获得一个字节,并将当前位置推到下一个字节byte get(int index)//从指定索引处获得一个字节ByteBuffer put(byte b)//向当前位置推入一个字节,并将当前位置推到下一个字节,返回对这个缓冲区的引用ByteBuffer put(int index,byte b)//向指定索引处推入一个字节,返回对这个缓冲区的引用ByteBuffer get(byte[] destination)ByteBuffer get(byte[] destination,int offset,int length)//用缓冲区的字节来填充字节数组,或者字节数组的某个区域,并将当前位置向前推读入的字节数个位置,如果缓冲区不够,不会读入任何字节,并抛出BufferUnderflowExceptionByteBuffer put(byte[] source)ByteBuffer put(byte[] source,int offset,int length)//将字节数组中的所有字节或者给定区域的字节都推入缓冲区,并将当前位置向前推写出的字节数个位置Xxx getXxx()Xxx getXxx(int index)ByteBuffer putXxx(xxx value)ByteBuffer putXxx(int index, xxx value)//获得或放置一个二进制数ByteBuffer order(ByteOrder order)ByteOrder order()//设置或获得字节顺序,order的值是ByteOrder类的常量BIG_ENDIAN或LITTLE_ENDIAN中的一个
缓冲区数据结构
java.nio.Buffer 1.4
Buffer clear()//通过将位置复位到0,并将界限复位到容量,使这个缓冲区为写出做好准备。返回thisBuffer flip()//通过将界限设置为位置,并将位置复位到0,使这个缓冲区为读入做好准备,返回thisBuffer rewind()//通过将读写位置复位到0,并保持极限不变,使这个缓冲区为重新读入相同的值做好准备,返回thisBuffer mark()//将这个缓冲区的标记设置到读写位置,返回thisBuffer reset()//将这个缓冲区的位置设置到标记,从而允许被标记的部分可以再次被读入或写出,返回thisint remaining()//返回剩余可读入或可写出的值的数量,即界限与位置之间的差异int position()//返回这个缓冲区的位置int capacity()//返回这个缓冲区的容量
java.nio.CharBuffer 1.4
char get()CharBuffer get(char[] destination)CharBuffer get(char[] destination,int offset,int length)//从这个缓冲区的位置处开始,获得一个char值,或者某个范围的char值,然后将位置向前推过所读入的字符,最后两个方法返回thisCharBuffer put(char c)CharBuffer put(char[] source)CharBuffer put(char[] source,int offset,int length)CharBuffer put(String source)CharBuffer put(CharBuffer source)//从这个缓冲区的位置处开始,推入一个char值,或者某个范围的char值,然后将位置向前推过所写出的字符CharBuffer read(CharBuffer destination)//从这个缓冲区中获得char值,然后将它们推入目标缓冲区,直至达到目标缓冲区的界限
文件加锁机制
文件加锁机制是依赖于操作系统的
文件锁是由整个Java虚拟机持有的。如果有两个程序是由同一个虚拟机启动的,那么它们不可能每一个都获得一个在同一个文件上的锁,当调用lock和tryLock方法时,如果虚拟机已经在同一个文件上持有了另一个重叠的锁,那么这两个方法将抛出OverlappingFileLockException
java.nio.channels.FileChannel 1.4
FileLock lock()//在整个文件上获得一个独占的锁,这个方法将阻塞直至获得锁FileLock tryLock()//在整个文件上获得一个独占的锁,或者在无法获得锁的情况下返回nullFileLock lock(long position,long size,boolean shared)FileLock tryLock(long position,long size,boolean shared)//在文件的一个区域上获得锁
java.nio.channels.FileLock 1.4
void release()//释放这个锁
正则表达式
语法
String patternString ="<a\\s+href\\s*=\\s*(\"[^\"]*\"|[^\\s>]*)\\s*>"
用法
Pattern pattern =Pattern.compile(patternString);Matcher matcher = pattern.matcher(input);if(matcher.matches())...
java.util.regex.Pattern 1.4
staticPattern compile(String expression)staticPattern compile(String expression,int flags)//把正则表达式字符串编译到一个用于快速处理匹配的模式对象中Matcher matcher(CharSequence input)//返回一个matcher对象,可以用它在输入定位模式的匹配String[] split(CharSequence input)String[] split(CharSequence input,int limit)//将输入分割成标号,其中模式指定了分隔符的形式
java.util.regex.Matcher 1.4
boolean matches()//如果输入匹配模式,则返回trueboolean lookingAt()//如果输入的开头匹配模式,则返回trueboolean find()boolean find(int start)//尝试查找下一个匹配,找到返回trueint start()int end()//返回当前匹配的开始索引和结尾之后的索引String group()//返回当前的匹配int groupCount()//返回输入模式中的群组数量int start(int groupIndex)int end(int groupIndex)//返回当前匹配中给定群组的开始和结尾之后的位置String group(int groupIndex)//返回匹配给定群组的字符串String replaceAll(String replacement)String replaceFirst(String replacement)//返回从匹配器输入获得的通过将所有匹配或第一个匹配用替换字符串替换之后的字符串Matcher reset()Matcher reset(CharSequence input)//复位匹配器的状态。第二个方法将使匹配器作用于另一个不同的输入,两个方法都返回this
第二章--XML----------------------------------------------
XML文档
文档头
<?xml version="1.0" encoding="UTF-8"?>
文档类型定义(DTD,Document Type Definition)
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN" "http:java.sun.com/j2ee/dtds/web-app_2_2.dtd">
通常属性只应该在修改值的解释时使用,而不是在指定值时使用
字符引用:é (十进制); Ù(十六进制)
实体引用:
< 小于> 大于& &" 引号' 省略号
CDATA部分: 用<![CDATA[和]]>来限定其界限,可用来包含含有<、>、&之类字符的字符串
处理指令:用<?和?>限定界限
注释:用<!-和-->限定界限
解析XML文档
DOM(Document Object Model,文档对象模型)解析器:树型解析器
用于XML的简单API(Simple API for XML, SAX)解析器:流机制解析器
读入一个XML文档
DocumentBuilderFactory factory =DocumentBuilderFactory.newInstance();DocumentBuilder builder = factory.newDocumentBuilder();File f =...Document doc = builder.parse(f);
javax.xml.parsers.DocumentBuilderFactory 1.4
staticDocumentBuilderFactory newInstance()//返回DocumentBuilderFactory类的一个实例DocumentBuilder newDocumentBuilder()//返回DocumentBuilder类的一个实例
javax.xml.parsers.DocumentBuilder 1.4
Document parse(File f)Document parse(String url)Document parse(InputStream in)//解析来自给定文件、URL或输入流的XML文档,返回解析后的文档
org.w3c.dom.Document 1.4
Element getDocumentElement()//返回文档的根元素
org.w3c.dom.Element 1.4
String getTagName()//返回元素的名字String getAttribute(String name)//返回给定名字的属性值,没有该属性时返回空字符串
org.w3c.dom.Node 1.4
NodeList getChildNodes()//返回包含所有子元素节点的节点列表Node getFirstChild()Node getLastChild()//获取该节点的第一个或最后一个子节点,在该节点没有子节点时返回nullNode getNextSibling()Node getPreviousSibling()//获取该节点的下一个或上一个兄弟节点,在该节点没有兄弟节点时返回nullNode getParentNode()//获取该节点的父结点,在该节点是文档节点时返回nullNamedNodeMap getAttributes()//返回含有描述该节点所有属性的Attr节点的映射表String getNodeName()//返回该节点的名字,当该结点是Attr节点时,该名字就是属性名String getNodeValue()//返回该节点的值,当该节点是Attr节点时,该值就是属性值
org.w3c.dom.CharacterData 1.4
String getData()//返回存储在节点中的文本
org.w3c.dom.NodeList 1.4
int getLength()//返回列表中的节点数Node item(int index)//返回给定索引号的节点
org.w3c.dom.NamedNodeMap 1.4
int getLength()//返回该节点映射表中的节点数Node item(int index)//返回给定索引号的节点
验证XML文档
DTD
<!ELEMENT font (name,size)>
XML Schema (xsd文件)
<xsd:elementname="font"><xsd:sequence><xsd:elementname="name"type="xsd:string"/><xsd:elementname="size"type="xsd:int"/></xsd:sequence></xsd:element>
文档类型定义:
将DTD纳入XML文档中
<?xml version="1.0"?><!DOCTYPE configuration [<!ELEMENT configuration ...>more rules...]><configuration>...</configuration>
将DTD存储在外面
<!DOCTYPE configuration SYSTEM "config.dtd">或者<!DOCTYPE configuration SYSTEM "http://myserver.com/config.dtd">
如果使用DTD的相对URL(比如"config.dtd"),需要给解析器一个文件或URL对象,而不是InputStream,如果必须从一个输入流来解析,请提供一个实体渲染器
来源于SGML的用于识别“众所周知的”DTD的机制,如
<!DOCTYPE web-appPUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN" "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">
如果使用的是DOM解析器,想要支持公共标识符,需要调用DocumentBuilder类的setEntityResolver方法来安装EntityResolver接口的某个实现类的一个对象,该接口只有一个方法:resolveEntity
ELEMENT规则
| E* | 0或多个E |
| E+ | 1或多个E |
| E? | 0或1个E |
| E1|E2|...|En | E1, E2, ..., En中的一个 |
| E1, E2, ..., En | E1随后是E2,...,En |
| #PCDATA | 文本 |
| (#PCDATA|E1|E2|...|En)* | 0或多个任意顺序的文本和E1,E2,...,En(混合式内容) |
| ANY | 允许任意子元素 |
| EMPTY | 不允许有子元素 |
元素的规范可以包含嵌套的和复杂的正则表达式,如
<!ELEMENT chapter (intro, (heading, (para | image | table | note)+)+)
描述合法元素属性的语法规则:
<!ATTLIST element attribute type default>
两个属性规范范例:
<!ATTLIST font style (plain|bold|italic|bold-italic) "plain">
<!ATTLIST size unit CDATA #IMPLIED>
使用DTD验证输入
factory.setValidating(true);factory.setIgnoringElementContentWhitespace(true);
在验证时,应该安装一个错误处理器,即一个实现了ErrorHandler接口的对象
javax.xml.parsers.DocumentBuilder 1.4
void setEntityResolver(EntityResolver resolver)//设置解析器,来定位要分析的XML文档中引用的实体void setErrorHandler(ErrorHandler handler)//设置报告解析过程中出现的错误和警告的处理器
org.xml.sax.EntityResolver 1.4
publicInputSource resolveEntity(String publicID,String systemID)//返回包含被指定ID引用数据的一个输入源,或者,当解析器不知道如何解析某个特定名字时,返回null。如果没有提供公共ID,那么参数publicID可以为null
org.xml.sax.InputSource 1.4
InputSource(InputStream in)InputSource(Reader in)InputSource(String systemID)//根据流、读入器、或系统ID(通常是相对或绝对URL)构建输入源
org.xml.sax.ErrorHandler 1.4
void fatalError(SAXParseException exception)void error(SAXParseException exception)void warning(SAXParseException exception)//覆盖这些方法以提供处理器,对致命错误、非致命错误和警告进行处理
org.xml.sax.SAXParseException 1.4
int getLineNumber()int getColumnNumber()//返回引起异常的已处理的输入信息末尾的行号和列号
javax.xml.parsers.DocumentBuilderFactory 1.4
boolean isValidating()void setValidating(boolean value)//获取和设置工厂的validating属性,当设为true时,工厂生成的解析器会验证它们的输入信息boolean isIgnoringElementContentWhiteSpace(boolean value)//获取和设置工厂的ignoringElementContentWhiteSpace属性,当设为true时,工厂生成的解析器会忽略没有混合内容(即元素与#PCDATA混合)的元素节点之间的空白
XML Schema
如果要在文档中引用Schema文件,需要在根元素中加上属性
<?xml version="1.0"?><configurationxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:noNamespaceSchemaLocation="config.xsd">...</configuration>
解析带有Schema的XML文件和解析带有DTD的文件相似,但有3点差别:
//必须打开对命名空间的支持factory.setNamespaceAware(true);//必须执行如下步骤finalString JAXP_SCHEMA_LANGUAGE ="http://java.sun.com/xml/jaxp/properties/schemaLanguage";finalString W3C_XML_SCHEMA ="http://www.w3.org/2001/XMLSchema";factory.setAttribute(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
使用XPath来定位信息
XPath表达式/configuration/database/username
使用@操作符可以得到属性值,如
/gridbag/row[1]/cell[1]/@anchor
javax.xml.xpath.XPathFactory 5.0
staticXPathFactory newInstance()//返回XPathFactory实例来创建XPath对象XPath newXpath()//构建XPath对象来计算XPath表达式
javax.xml.xpath.XPath 5.0
String evaluate(String expression,Object startingPoint)/从给定的起点计算表达式,起点可以是一个节点或节点列表,如果结果是一个节点或节点集,则返回的字符串包含所有文本节点子元素的数据Object evaluate(String expression,Object startingPoint,QName resultType)//从给定的起点计算表达式,起点可以是一个节点或节点列表。ResultType是XPathConstants类的常量STRING, NODE, NODESET, NUMBER或BOOLEAN之一
使用命名空间(URI)
HTTP URL格式最常用
xmlns:alias="namespaceURI" 用于定义命名空间和别名
打开命名空间处理特性
factory.setNamespaceAware(true);
由getNodeName和getTagName等方法返回带有别名前缀的限定名
org.w3c.dom.Node 1.4
String getLocalName()//返回本地名(不带别名前缀),或者在解析器不支持命名空间时返回nullString getNamespaceURI()//返回命名空间URI,或者在解析器不支持命名空间时返回null
javax.xml.parsers.DocumentBuilderFactory 1.4
boolean isNamespaceAware()void setNamespaceAware(boolean value)//获取或设置工厂的namespaceAware属性
流机制解析器
使用SAX解析器(事件回调)
在使用SAX解析器时,需要一个处理器来定义不同的解析器事件的事件动作,ContentHandler接口定义了若干个回调方法,如startElement, endElement, characters, startDocument和endDocument
SAXParserFactory factory =SAXParserFactory.newInstance();SAXParser parser = factory.newSAXParser();parser.parse(source, handler);
处理器属于DefaultHandler的一个子类,DefaultHandler类为4个接口定义了空的方法:ContentHandler, DTDHandler, EntityResolver, ErrorHandler
javax.xml.parsers.SAXParserFactory 1.4
staticSAXParserFactory newInstance()//返回SAXParserFactory类的一个实例SAXParser newSAXParser()//返回SAXParser类的一个实例boolean isNamespaceAware()void setNamespaceAware(boolean value)//获取和设置工厂的namespaceAware属性boolean isValidating()void setValidating(boolean value)//获取和设置工厂的validating属性
javax.xml.parsers.SAXParser 1.4
void parse(File f,DefaultHandler handler)void parse(String url,DefaultHandler handler)void parse(InputStream in,DefaultHandler handler)//解析来自给定文件、URL或输入流的XML文档,并把解析事件报告给指定的处理器
org.xml.sax.ContentHandler 1.4
void startDocument()void endDocument()void startElement(String uri,String lname,String qname,Attributes attr)void endElement(String uri,String lname,String qname)//在元素的起始或结束时被调用void characters(char[] data,int start,int length)//解析器报告字符数据时被调用
org.xml.sax.Attributes 1.4
int getLength()//返回存储在该属性集合中属性数量String getLocalName(int index)//返回给定索引的属性的本地名(无别名前缀),或当不支持命名空间特性时返回空字符串String getURI(int index)//返回给定索引的属性的命名空间URIString getQName(int index)//返回给定索引的属性的限定名String getValue(int index)String getValue(String qname)String getValue(String uri,String lname)//根据给定索引、限定名或命名空间URI+本地名,返回属性值,该值不存在时返回null
使用StAX解析器(提供解析事件的迭代器)
InputStream in = url.openStream();XMLInputFactory factory =XMLInputFactory.newInstance();XMLStreamReader parser = factory.createXMLStreamReader(in);while(parser.hasNext()){int event = parser.next();Call parser methods to obtain event details}
javax.xml.stream.XMLInputFactory 6
staticXMLInputFactory newInstance()//返回XMLInputFactory类的一个实例void setProperty(String name,Object value)//设置这个工厂的属性,或者在要设置的属性不支持设置成给定值时,抛出IllegalArgumentExceptionXMLStreamReader createXMLStreamReader(InputStream in)XMLStreamReader createXMLStreamReader(InputStream in,String characterEncoding)XMLStreamReader createXMLStreamReader(Reader in)XMLStreamReader createXMLStreamReader(Source in)//创建一个从给定的流、阅读器或JAXP源读入的解析器
javax.xml.stream.XMLStreamReader 6
boolean hasNext()//如果有另一个解析事件则返回trueint next()//将解析器的状态设置为下一个解析事件,并返回下列常量之一:START_ELEMENT、CHARACTERS、START_DOCUMENT、END_DOCUMENT、CDATA、COMMENT、SPACE(可忽略的空白字符)、PROCESSING_INSTRUCTION、ENTITY_REFERENCE、DTDboolean isStartElement()boolean isEndElement()boolean isCharacters()boolean isWhiteSpace()//如果当前事件是一个开始元素、结束元素、字符数据或空白字符,返回trueQName getName()String getLocalName()//获取在START_ELEMENT或END_ELEMENT事件中的元素的名字String getText()//返回一个CHARACTERS、COMMENT或CDATA事件,或一个ENTITY_REFERENCE的替换值,或者一个DTD的内部子集所对应的字符int getAttributeCount()QName getAttributeName(int index)String getAttributeLocalName(int index)String getAttributeValue(int index)String getAttributeValue(String namespaceURI,String name)//只要当前事件是START_ELEMENT,则获取给定属性的值,如果namespaceURI为null,则不检查名字空间
生成XML文档
用文档的内容构建一棵DOM树
Document doc = builder.newDocument();Element rootElement = doc.createElement(rootName);Element childElement = doc.createElement(childName);Text textNode = doc.createTextNode(textContents);doc.appendChild(rootElement);rootElement.appendChild(childElement);childElement.appendChild(textNode);rootElement.setAttribute(name, value);
但是DOM API目前还不支持DOM树写到输出流,需要使用可扩展的格式页转换(XSLT) API
//construct the "do nothing" transformationTransformer t =TransformerFactory.newInstance().newTransformer();//set output properties to get a DOCTYPE nodet.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, systemIdentifier);t.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, publicIdentifier);//set indentationt.setOutputProperty(OutputKeys.INDENT,"yes");t.setOutputProperty(OutputKeys.METHOD,"xml");//apply the "do nothing" transformation and send the output to a filet.transform(newDOMSource(doc),newStreamResult(newFileOutputStream(file)));
javax.xml.parsers.DocumentBuilder 1.4
Document newDocument()//返回一个空文档
org.w3c.dom.Document 1.4
Element createElement(String name)//返回具有给定名字的元素Text createTextNode(String data)//返回具有给定数据的文本节点
org.w3c.dom.Node 1.4
Node appendChild(Node child)//将一个节点附加到该节点的子节点列表,返回该节点
org.w3c.dom.Element 1.4
void setAttribute(String name,String value)//将有给定名字的属性设置为指定的值void setAttributeNS(String uri,String qname,String value)//将带有给定命名空间URI和限定名的属性设置为指定的值
javax.xml.transform.TransformerFactory 1.4
staticTransformerFactory newInstance()//返回TransformerFactory类的一个实例transformer newTransformer()//返回Transformer类的一个实例,带有标识符或“无操作”的转换
javax.xml.transform.Transformer 1.4
void setOutputProperty(String name,String value)//设置输出属性void transform(Source from,Result to)//转换一个XML文档
javax.xml.transform.dom.DOMSource 1.4
DOMSource(Node n)//根据指定的节点构建一个源。通常,n是文档节点
javax.xml.transform.stream.StreamResult 1.4
StreamResult(File f)StreamResult(OutputStream out)StreamResult(Writer out)StreamResult(String systemID)根据文件、流、写入程序或系统ID(通常是相对或绝对URL)来构建数据流结果
使用StAX写XML文档
XMLOutputFactory factory =XMLOutputFactory.newInstance();XMLStreamWriter writer = factory.createXMLStreamWriter(out);writer.writeStartDocument();writer.writeStartElement(name);writer.writeAttribute(name, value);writer.writeCharacters(text);writer.writeEndElement();writer.writeEmptyElement(name);writer.writeEndDocument();
javax.xml.stream.XMLOutputFactory 6.
staticXMLOutputFactory newInstance()//返回这个XMLOutputFactory类的一个实例XMLStreamWriter createXMLStreamWriter(OutputStream in)XMLStreamWriter createXMLStreamWriter(OutputStream in,String characterEncoding)XMLStreamWriter createXMLStreamWriter(Writer in)XMLStreamWriter createXMLStreamWriter(Result in)//创建写入给定流、写出器和JAXP结果的写出器
javax.xml.stream.XMLStreamWriter 6
void writeStartDocument()void writeStartDocument(String xmlVersion)void writeStartDocument(String encoding,String xmlVersion)//在文档的顶部写入XML处理指令void setDefaultNamespace(String namespaceURI)void setPrefix(String prefix,String namespaceURI)设置默认的命名空间,或具有前缀的命名空间,作用域仅为当前元素void writeStartElement(String localName)void writeStartElement(String namespaceURI,String localName)//写出一个开始标签,其中namespaceURI将用相关联的前缀来代替void writeEndElement()//关闭当前元素void writeEndDocument()//关闭所有打开的元素void writeEmptyElement(String localName)void writeEmptyElement(String namespaceURI,String localName)//写出一个自闭合的标签void writeAttribute(String localName,String value)void writeAttribute(String namespaceURI,String localName,String value)//写出一个用于当前元素的属性void writeCharacters(String text)//写出字符数据void writeCData(String text)//写出CDATA块void writeDTD(String dtd)//写出dtd字符串,该字串需要包含一个DOCTYPE声明void writeComment(String comment)//写出一个注释void close()//关闭这个写出器
XSL转换(XSLT)
典型模板:
<xsl:templatematch="/staff/employee"><tr><xsl:apply-templates/></tr></xsl:template>
处理属性值:
<xsl:templatematch="/staff/employee/hiredate"><td><xsl:value-ofselect="@year"/>-<xsl:value-ofselect="@month"/>-<xsl:value-ofselect="@day"/></td></xsl:template>
实现XML转换
File styleSheet =newFile(filename);StreamSource styleSource =newStreamSource(styleSheet);Transformer t =TransformerFactory.newInstance().newTransformer(styleSource);t.transform(source, result);
Source接口有3个实现类:DOMSource, SAXSource, StreamSource
Result接口有3个实现类:DOMResult,SAXResult,StreamResult
javax.xml.transform.TransformerFactory 1.4
transformer newTransformer(Source stylesheet)//返回一个transformer类的实例,用来从指定的源中读取样式表
javax.xml.transform.stream.StreamSource 1.4
StreamSource(File f)StreamSource(InputStream in)StreamSource(Reader in)StreamSource(String stystemID)//根据一个文件、流、阅读器或系统ID(通常是相对或绝对URL)来构建一个数据流源
javax.xml.transform.sax.SAXSource 1.4
SAXSource(XMLReader reader,InputSource source)//构建一个SAX数据源,以便从给定输入源获取数据,并使用给定的阅读器来解析输入数据
org.xml.sax.XMLReader 1.4
void setContentHandler(ContentHandler handler)//设置在输入被解析时会被告知解析事件的处理器void parse(InputSource source)//根据给定输入源解析输入数据,并将解析事件发送到内容处理器
javax.xml.transform.dom.DOMResult 1.4
DOMResult(Node n)//根据给定结点构建一个数据源,通常n是一个新文档节点
org.xml.sax.helpers.AttributesImpl 1.4
void addAtrribute(String uri,String lname,String qname,String type,String value)//将一个属性添加到该属性集合void clear()//删除属性集合中的所有属性
第三章--网络----------------------------------------------
套接字Socket
套接字超时设置
java.net.Socket 1.0
Socket(String host,int port)//构建一个套接字,用来连接给定的主机和端口InputStream getInputStream()OutputStream getOutputStream()//获取可以从套接字中读取数据的流,以及可以向套接字写出数据的流Socket()//创建一个还未被连接的套接字void connect(SocketAddress address)//将该套接字连接到给定的地址void connect(SocketAddress address,int timeoutInMilliSeconds)//将套接字连接到给定的地址,如果在给定的时间内没有响应,则返回void setSoTimeout(int timeoutInMilliseconds)//设置该套接字上读请求的阻塞时间,如果超出时间,则抛出一个InterruptedIOException异常boolean isConnected()//如果该套接字已被连接,则返回trueboolean isClosed()//如果该套接字已被关闭,返回true
因特网地址
InetAddress address =InetAddress.getByName("time-A.timefreq.bldrdoc.gov");byte[] addressBytes = address.getAddress();
java.net.InetAddress 1.0
staticInetAddress getByName(String host)staticInetAddress[] getAllByName(String host)//为给定的主机名,创建一个InetAddress对象,或者一个包含了该主机名所对应的所有因特网地址的数组staticInetAddress getLocalHost()//为本地主机创建一个InetAddress对象byte[] getAddress()//返回一个包含数字型地址的字节数组String getHostAddress()//返回一个由十进制数组成的字符串,各数字间用圆点符号隔开String getHostName()//返回主机名
实现服务器
ServerSocket s =newServerSocket(8189);Socket incoming = s.accept();InputStream inStream = incoming.getInputStream();OutputStream outStream = incoming.getOutputStream();Scanner in =newScanner(inStream);PrintWriter out =newPrintWriter(outStream,true/* autoFlush */);out.println("Hello!Enter BYE to exit.“);String line = in.nextLine();out.println("Echo:"+ line);if(line.trim().equals("BYE")) done =true;incoming.close();
java.net.ServerSocket 1.0
ServerSocket(int port)//创建一个监控端口的服务器套接字Socket accept()//等待连接,阻塞当前线程直到建立连接为止void close()//关闭服务器套接字
为多个客户端服务
while(true){Socket incoming = s.accept();Runnable r =newThreadedEchoHandler(incoming);Thread t =newThread(r);t.start();}
半关闭
java.net.Socket 1.0
void shutdownOutput()//将输出流设为“流结束”void shutdownInput()//将输入流设为“流结束”boolean isOutputShutdown()//如果输出已被关闭返回trueboolean isInputShutdown()//如果输入已被关闭,返回true
可中断套接字
java.nio包的特性:SocketChannel类,通道(channel)没有相关联的流,需要调用Buffer对象来实现ReadableByteChannel和WritableByteChannel接口声明的read和write方法
SocketChannel channel =SocketChannel.open(newInetSocketAddress(host, port));Scanner in =newScanner(channel);OutputStream outStream =Channels.newOutputStream(channel);
如果线程发生中断,不会阻塞,而是会抛出异常
java.net.InetSocketAddress 1.4
InetSocketAddress(String hostname,int port)//通过主机和端口参数创建一个地址对象,并在创建过程中解析主机名,如果主机名不能被解析,那么该地址对象的unresolved属性被设为trueboolean isUnresolved()//如果不能解析该地址对象,返回true
java.nio.channels.SocketChannel 1.4
staticSocketChannel open(SocketAddress address)//打开一个套接字通道,并将其连接到远程地址
java.nio.channels.Channels 1.4
staticInputStream newInputStream(ReadableByteChannel channel)//创建一个输入流,用以从指定的通道读取数据staticOutputStream newOutputStream(WritableByteChannel channel)//创建一个输出流,用以向指定的通道写入数据
发送E-mail
Socket s =newSocket("mail.yourserver.com",25);PrintWriter out =newPrintWriter(s.getOutputStream));
信息规范:
HELO sending host
MAIL FROM: <sender e-mail address>
RCPT TO: <recipient e-mail address>
DATA
mail message
(any number of lines)
.
QUIT
SMTP规范规定,每一行都要以\r再紧跟一个\n来结尾
建议URL连接
URL和URI
URL url =new URL(urlString);InputStream inStream = url.openStream();Scanner in =newScanner(inStream);
URI句法:
[scheme:]schemeSpecificPart[#fragment]
一个分层URI的schemeSpecificPart具有以下结构:
[//authority][path][?query]
对基于服务器的URI,authority部分采用以下形式:
[user-info@]host[:port]
relative = base.relativize(combined);combined = base.resolve(relative);
使用URLConnection获取信息
1. 调用URL类中的openConnection方法获得URLConnection对象
URLConnection connection = url.openConnection()
2. 使用以下方法来设置任意的请求属性
setDoInputsetDoOutputsetIfModifiedSincesetUseCachessetAllowUserInteractionsetRequestPropertysetConnectTimeoutsetReadTimeout
3. 调用connect方法连接远程资源
connection.connect();
4. 建立连接后,可以查询头信息
getContentTypegetContentLengthgetContentEncodinggetDategetExpirationgetLastModified
5. 访问资源数据
getInputStream
setRequestProperty方法,设置“名-值”对
String input = username +":"+ password;String encoding = base64Encode(input);connection.setRequestProperty("Authorization","Basic "+ encoding);
java.net.URL 1.0
InputStream openStream()//打开一个用于读取资源数据的输入流URLConnection openConnection()//返回一个URLConnection对象,该对象负责管理与资源之间的连接
java.net.URLConnection 1.0
void setDoInput()//如果doInput为true,那么用户可以接收来自该URLConnection的输入void setDoOutput(boolean doOutput)boolean getDoOutput(boolean doOutput)//如果doOutput为true,那么用户可以将输出发送到该URLConnectionvoid setIfModifiedSince(long time)long getIfModifiedSince()//属性ifModifiedSince用于配置URLConnection对象,使它只获取那些自从某个给定时间以来被修改过的数据void setUseCaches(boolean useCaches)boolean getUseCaches()//如果useCaches为true,那么数据可以从本地缓存中得到,URLConnection本身并不维护这个缓存,缓存必须由浏览器之类的外部程序提供void setAllowUserInteraction(boolean allowUserInteraction)boolean getAllowUserInteraction()//如果为true,那么可以查询用户的口令void setConnectTimeout(int timeout)int getConnectionTimeout()//设置或得到连接超时时限void setRequestProperty(String key,String value)//设置请求头的一个字段Map<String,List<String>> getRequestProperties()//返回请求头属性的一个映射表,相同的键对应的所有值被放置在同一个映射表中void connect()//连接远程资源并获取响应头信息Map<String,List<String>>Map getHeaderFields()//返回响应的一个映射表,相同的键对应的所有值被放置在同一个映射表中String getHeaderFieldKey(int n)//得到响应头第n个字段的键,如果n等于0或大于响应头字段的总数返回null值String getHeaderField(int n)//得到响应头第n个字段的值int getContentLength()//如果知道内容长度,则返回该长度值,否则返回-1String getContentType()//获取内容的类型,比如text/plain或image/gifString getContentEncoding()//获取内容的编码,比如gziplong getDate()long getExpiration()long getLastModified()//获取创建日期、过期日以及最后一次被修改的日期InputStream getInputStream()OutputStream getOutputStream()//返回从资源读取信息或向资源写入信息的流Object getContent()//选择适当的内容处理器,以便读取资源数据并将它转换成对象。该方法不能用于读取诸如text/plain或image/gif之类的标准内容类型,除非安装了自己的内容处理器
提交表单数据
GET和POST命令,向Web服务器发送信息
URL编码模式编码,参数规则:
保留字符A-Z、a-z、0-9以及 . - * _
用+字符替换所有的空格
将其他所有字符编码为UTF-8,并将每个字节都编码为%后面紧跟一个两位的十六进制数字
使用POST命令的方法:
URL url =new URL("http://host/script");URLConnection connection = url.openConnection();connection.setDoOutput(true);PrintWriter out =newPrintWriter(connection.getOutputStream());out.print(name1 +"="+URLEncoder.encode(value1,"UTF-8")+"&");out.print(name2 +"="+URLEncoder.encode(value2,"UTF-8"));out.close();
java.net.HttpURLConnection 1.0
InputStream getErrorStream()//返回一个流,通过这个流可以读取Web服务器的错误信息
java.net.URLEncoder 1.0
staticString encode(String s,String encoding)//采用指定的字符编码模式对字符串s进行编码,并返回它的URL编码形式
java.net.URLDecoder 1.2
staticString decode(String s,String encoding)//采用指定编码模式对已编码字符串s进行解码,并返回结果
第三章--数据库编程----------------------------------------------
JDBC的典型用法
客户端(可视化表示) ---HTTP、RMI---> 中间层(业务逻辑) ---JDBC-数据库协议->数据库服务器
JDBC URL一般语法:
jdbc:subprotocol:other stuff
注册驱动器类
Class.forName("org.postgresql.Driver");
或者
java -Djdbc.drivers=org.postgresql.Driver ProgramName
或者
System.setProperty("jdbc.drivers", "org.postgresql.Driver");
连接到数据库
String url ="jdbc:postgresql:COREJAVA";String username ="dbuser";String password ="scret";Connection conn =DriverManager.getConnection(url, username, password);
java.sql.DriverManager 1.1
staticConnection getConnection(String url,String user,String password)//建立一个到指定数据库的连接,并返回一个Connection对象
执行SQL语句
java.sql.Connection 1.1
Statement createStatement()//创建一个Statement对象,用以执行不带参数的SQL查询和更新void close()//用于立即关闭当前的连接以及释放由它所创建的JDBC资源
java.sql.Statement 1.1
ResultSet executeQuery(String sqlQuery)//执行给定字符串中的SQL语句,并返回一个用于查看查询结果的ResultSet对象int executeUpdate(String sqlStatement)//执行字符串中指定的INSERT、UPDATE或DELETE等SQL语句,也可以执行CREATE TABLE等语句,返回受影响的记录总数boolean execute(String sqlStatement)//执行字符串中指定的SQL语句,可能会产生多个结果集和更新数。如果第一个执行结果是结果集,则返回true,反之返回false。调用getResultSet或getUpdateCount方法可以得到第一个执行结果ResultSet getResultSet()//返回前一条查询语句的结果集,如果前一条语句未产生结果集则返回null值,对于每一条执行过的语句,该方法只能被调用一次void close()//关闭Statement对象以及它所对应的结果集boolean isClosed()//如果语句被关闭返回true
java.sql.ResultSet 1.1
boolean next()//将结果集中的当前行向前移动一行。如果已经到达最后一行的后面,返回false,注意初始情况必须调用该方法才能转到第一行Xxx getXxx(int columnNumber)Xxx getXxx(String columnName)//用给定的列序号或列标签返回该列的值,并将之转换成指定类型int findColumn(String columnName)//根据给定的列名,返回该列的序号void close()//立即关闭当前的结果集boolean isClosed()//如果语句被关闭,则返回true
管理连接、语句和结果集
分析SQL异常
每个SQLException都有一个由多个SQLException对象构成的链,这些对象可以通过getNextException方法获取
java.sql.SQLException 1.1
SQLException getNextException()//返回链接到该SQL异常的下一个SQL异常,或者在到达链尾时返回nullIterator<Throwable> iterator()//获取迭代器,可以迭代链接的SQL异常和它们的成因String getSQLState()//获取“SQL状态”,即标准化的错误代码int getErrorCode()//获取提供商相关的错误代码
java.sql.Warning 1.1
SQLWarning getNextWarning()//返回链接到该警告的下一个警告,或者在到达链尾时返回null
java.sql.Connection 1.1
java.sql.Statement 1.1
java.sql.ResultSet 1.1
QLWarning getWarnings()SQLWarning getWarnings()//返回未处理警告中的第一个,或者在没有未处理警告时返回null
java.sql.DataTruncation 1.1
boolean getParameter()//如果在参数上进行了数据截断,则返回true,如果在列上进行了数据截断返回falseint getIndex()//返回被截断的参数和列的索引int getDataSize()//返回应该被传输的字节数量,或者在该值未知的情况下返回-1int getTransferSize()//返回实际被传输的字节数量,或者在该值未知的情况下返回-1
元数据
ResultSet result = stat.getResultSet();ResultSetMetaData metaData = result.getMetaData();int columnCount = metaData.getColumnCount();metaData.getColumnLabel(i);
预备语句
占位符?
PreparedStatementPublisherQueryStat= conn.prepareStatement(publisherQuery);publisherQueryStat.setString(1, publisher);ResultSet rs = publisherQueryStat.executeQuery();
java.sql.Connection 1.1
PreparedStatement prepareStatement(String sql)//返回一个含预编译语句的PreparedStatement对象
java.sql.PreparedStatement 1.1
void setXxx(int n,Xxx x)//设置第n个参数值为xvoid clearParameters()//清除预备语句中的所有当前参数ResultSet executeQuery()//执行预备SQL查询,并返回一个ResultSet对象int executeUpdate()//执行预备SQL语句INSERT UPDATE或DELETE,返回受影响的记录数,如果执行CREATE TABLE,返回0
读写LOB
二进制大对象称为BLOB,字符型大对象称为CLOB
获取一张图像:
- PreparedStatement stat = conn.preapareStatement("SELECT Cover FROM BookCovers WHERE ISBN=?");
stat.set(1, isbn);ResultSet result = stat.executeQuery();if(result.next()){Blob coverBlob = result.getBlob(1);Image coverImage =ImageIO.read(coverBlob.getInputstream());}
存储一张图像:
Blob coverBlob = connection.createBlob();int offset =0;OutputStream out = coverBlob.setBinaryStream(offset);ImageIO.write(coverImage,"PNG", out);PreparedStatement stat = conn.prepareStatement("INSET INTO Cover VALUES (?, ?)");stat.set(1, isbn);stat.set(2, coverBlob);stat.executeUpdate();
java.sql.ResultSet 1.1
Blob getBlob(int columnIndex)Blob getBlob(String columnLabel)Clob getClob(int columnIndex)Clob getClob(String columnLabel)//获取给定列的BLOB或CLOB
java.sql.Blob 1.2
long length()//获取该BLOB的长度byte[] getBytes(long startPosition,long length)//获取该BLOB中给定范围的数据InputStream getBinaryStream()InputStream getBinaryStream(long startPosition,long length)//返回一个输入流,用于读取该BLOB中全部或给定范围的数据OutputStream setBinaryStream(long startPosition)//返回一个输出流,用于从给定位置开始写入该BLOB
java.sql.Clob 1.4
long length()//获取该CLOB中的字符总数String getSubString(long startPosition,long length)//获取该CLOB中给定范围的字符Reader getCharacterStream()Reader getCharacterStream(long startPosition,long length)//返回一个读入器(而不是流),用于读取CLOB中全部或给定范围的数据Writer setCharacterStream(long startPosition)//返回一个写出器(而不是流),用于从给定位置开始写入该CLOB
java.sql.Connection 1.1
Blob createBlob()Clob createClob()//创建一个空的BLOB或CLOB
SQL转义
转义主要用于下列特性:
日期和时间字面常量
调用标量函数
调用存储过程
外连接
在LIKE子句中的转义字符
多结果集
遍历execute所有结果:
boolean done =false;boolean isResult = stmt.execute(command);while(!done){if(isResult){ResultSet result = stmt.getResultSet();do something with result}else{int updateCount = stmt.getUpdateCount();if(updateCount >=0)do something with updateCountelsedone =true;}isResult = stmt.getMoreResults();}
java.sql.Statement 1.1
boolean getMoreResults()//获取该语句的下一个结果集,如果存在返回true
获取自动生成键
stmt.executeUpdate(insertStatement,Statement.RETURN_GENERATED_KEYS);ResultSet rs = stmt.getGeneratedKeys();if(rs.next()){int key = rs.getInt(1);...}
java.sql.Statement 1.1
boolean execute(String statement,int autogenerated)int executeUpdate(String statement,int autogenerated)//如果autogenerated被设置为Statement.RETURN_GENERATED_KEYS,并且该语句是一条INSERT语句,那么第一列中就是自动生成的键
可滚动和可更新的结果集
Statement stat = conn.createStatement(type, concurrency);PreparedStatement stat = conn.prepareStatement(command, type, concurrency);
ResultSet类的type值
| TYPE_FORWARD_ONLY | 结果集不能滚动 |
| TYPE_SCROLL_INSENSITIVE | 结果集可以滚动,但对数据库变化不敏感 |
| TYPE_SCROLL_SENSITIVE | 结果集可以滚动,且对数据库变化敏感 |
ResultSet类的Concurrency值
| CONCUR_READ_ONLY | 结果集不能用于更新数据库 |
| CONCUR_UPDATE | 结果集可以用于更新数据库 |
需要用getType和getConcurrency方法先检查结果集的功能再使用,否则可能抛出SQLException异常
在结果集上的滚动
if(rs.previous())...
将游标向后或向前移动多行
rs.relative(n);
将游标设置到指定的行号上
rs.absolute(n);int currentRow = rs.getRow();
获得可更新的结果集
Statement stat = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);
迭代遍历所有结果并更新相关内容
String query ="SELECT * FROM Books";ResultSet rs = stat.executeQuery(query);while(rs.next()){if(...){double increase =...double price = rs.getDouble("Price");rs.updateDouble("Price", price + increase);rs.updateRow();}}
添加新行
rs.moveToInsertRow();rs.updateString("Title", title);rs.updateString("ISBN", isbn);rs.updateString("Publisher_Id", pubid);rs.updateDouble("Price", price);rs.insertRow();rs.moveToCurrentRow();
删除行
rs.deleteRow();
java.sql.Connection 1.1
Statement createStatement(int type,int concurrency)PreparedStatement prepareStatement(String command,int type,int concurrency)//创建一个语句或预备语句,且该语句可以产生指定类型和并发模式的结果集
java.sql.ResultSet 1.1
int getType()//返回结果集的类型int getConcurrency()//返回结果集的并发设置boolean previous()//把光标移动到前一行int getRow()//得到当前行的序号boolean absolute(int r)//移动光标到第r行boolean relative(int d)//将光标移动d行,如果d为负数,则光标向后移动,如果光标位于某一行上,返回trueboolean first()boolean last()//移动光标到第一行或最后一行void beforeFirst()void afterLast()//移动光标到第一行之前或最后一行之后的位置boolean isFirst()boolean isLast()//测试光标是否在第一行或最后一行boolean isBeforeFirst()boolean isAfterLast()//测试光标是否在第一行之前或最后一行之后的位置void moveToInsertRow()//移动光标到插入行void moveToCurrentRow()//将光标从插入行移回到调用moveToInsertRow之前所在那一行void insertRow()//将插入行上的内容插入到数据库和结果集中void deleteRow()//从数据库和结果集中删除当前行void updateXxx(int column,Xxx data)void updateXxx(String columnName,Xxx data)//更新结果中当前行上的某个字段值void updateRow()//将当前行的更新信息发送到数据库void cancelRowUpdates()//撤销对当前行的更新
java.sql.DatabaseMetaData 1.1
boolean supportsResultSetType(int type)//如果数据库支持给定类型的结果集,则返回trueboolean supportsResultSetConcurrency(int type,int concurrency)//如果数据库支持给定类型和并发模式的结果集,则返回true
行集
CachedRowSet
WebRowSet
FilteredRowSet
JoinRowSet
JdbcRowSet
被缓存的行集
使用一个结果集来填充CachedRowSet对象
ResultSet result =...;CachedRowSet crs =new com.sun.rowset.CachedRowSetImpl();crs.populate(result);conn.close();
或者可以让CachedRowSet对象自动创建一个数据库连接并将查询结果填充到行集,最后断开连接
crs.setURL("jdbc:derby://localhost:1527/COREJAVA");crs.setUsername("dbuser");crs.setPassword("secret");crs.setCommand("SELECT * FROM Books WHERE PUBLISHER = ?");crs.setString(1, publisherName);crs.execute();
指定每一页尺寸
CachedRowSet crs =...;crs.setCommand(command);crs.setPageSize(20);...crs.execute();crs.nextPage();
将修改写回到数据库中
crs.acceptChanges(conn);或crs.acceptChanges();//这个方法只有设置连接数据库所需信息才有效
javax.sql.RowSet 1.4
String getURL()void setURL(String url)//获取或设置数据库的URLString getUsername()void setUsername(String username)//获取或设置连接数据库所需的用户名String getPassword()void setPassword(String password)//获取或设置连接数据库所需的密码String getCommand()void setCommand(String command)//获取或设置向行集中填充数据时需要执行的命令void execute()//通过执行使用setCommand方法设置的命令集来填充行集。为了使驱动管理器可以获得连接,必须事先设定URL、用户名和密码
javax.sql.rowset.CachedRowSet 5.0
void execute(Connection conn)//通过执行使用setCommand方法设置的命令集来填充行集,该方法使用给定的连接,并负责关闭它void populate(ResultSet result)//将指定的结果集中的数据填充到被缓存的行集中String getTableName()void setTableName(String tableName)//获取或设置数据库表名称,填充被缓存的行集时所需的数据来自于该表int getPageSize()void setPageSize(int size)//获取和设置页的尺寸boolean nextPage()boolean previousPage()//加载下一页或上一页,如果要加载的页存在,返回truevoid acceptChanges()void acceptChanges(Connection conn)//重新连接数据库,并写回行集中修改过的数据,如果因为数据库中的数据已经被修改而导致无法写回行集中的数据,该方法可能会抛出SyncProviderException异常
元数据
描述数据库或其组成部分的数据称为元数据
获取数据库所有表名(第三列是表名)
DatabaseMetaData meta = conn.getMetaData();ResultSet mrs = meta.getTables(null,null,null,newString[]{"TABLE"});while(mrs.next())tableNames.addItem(mrs.getString(3));
通过ResultSetMetaData提供结果集的相关信息,如每一列的名称、类型和字段宽度:
ResultSet mrs = stat.executeQuery("SELECT * FROM "+ tableName);ResultSetMetaData meta = mrs.getMetaData();for(int i =1; i <= meta.getColumnCount(); i++){String columnName = meta.getColumnLabel(i);int columnWidth = meta.getColumnDisplaySize(i);...}
java.sql.Connection 1.1
DatabaseMetaData getMetaData()//返回一个DatabaseMetaData对象,该对象封装了有关数据库连接的元数据
java.sql.DatabaseMetaData 1.1
ResultSet getTables(String catalog,String schemaPattern,String tableNamePattern,String types[])//返回某个目录中的所有表的描述,该目录必须符合给定的模式(schema)、表名字模式以及类型标准int getJDBCMajorVersion()int getJDBCMinorVersion()//返回建立数据库连接的JDBC驱动程序的主版本号和次版本号int getMaxConnections()//返回可同时连接到数据库的最大连接数int getMaxStatements()//返回单个数据库连接允许同时打开的最大语句数
java.sql.ResultSet 1.1
ResultSetMetaData getMetaData()//返回与当前ResultSet对象中的列相关的元数据
java.sql.ResultSetMetaData 1.1
int getColumnCount()//返回当前ResultSet对象中的列数int getColumnDisplaySize(int column)//返回给定列序号的列的最大宽度String getColumnLabel(int column)//返回该列所建议的名称String getColumnName(int column)//返回指定的列序号所对应的列名
事务
回滚(rollback)
默认为自动提交模式(autocommit mode)
conn.setAutoCommit(false);Statement stat = conn.createStatement();stat.executeUpdate(command1);stat.executeUpdate(command2);...conn.commit();如果出现错误,请调用:conn.rollback();
保存点
Statement stat = conn.createStatement();//start transaction; rollback() goes herestat.executeUpdate(command1);Savepoint svpt = conn.setSavepoint();//set savepoint; rollback(svpt) goes herestat.executeUpdate(command2);if(...) conn.rollback(svpt);//undo effect of command2...conn.commit();conn.releaseSavepoint(svpt);
批量更新
使用DatabaseMetaData类中的supportsBatchUpdates方法可以获知数据库是否支持这种特性
可以是INSERT、UPDATE、DELETE等操作,也可以是CREATE TABLE和DROP TABLE,但不可以是SELECT命令,会抛异常
Statement stat = conn.createStatement();String command ="CREATE TABLE ...";stat.addBatch(command);while(...){command ="INSERT INTO ... VALUES ("+...+")";stat.addBatch(command);}int[] counts = stat.executeBatch();
java.sql.Connection 1.1
boolean getAutoCommit()void setAutoCommit(boolean b)//获取该连接中的自动提交模式,或将其设置为bvoid commit()//提交自上次提交以来所有执行过的语句void rollback()//撤销自上次提交以来所有执行过的语句所产生的影响Savepoint setSavepoint()Savepoint setSavepoint(String name)//设置一个匿名或具名的保存点void rollback(Savepoint svpt)//回滚到给定保存点void releaseSavepoint(Savepoint svpt)//释放给定的保存点
java.sql.Savepoint 1.4
int getSavepointId()//获取该匿名保存点的ID号,如果有名字则抛出SQLException异常String getSavepointName()//获取该保存点的名称,如果为匿名保存点则抛出SQLException异常
java.sql.Statement 1.1
void addBatch(String command)//添加命令到当前批量命令中int[] executeBatch()//执行当前批量更新中的所有命令,返回一个记录数的数组
java.sql.DatabaseMetaData 1.1
boolean supportsBatchUpdates()//如果驱动程序支持批量更新,返回true
Web与企业应用中的连接管理
通过目录接口(JNDI)查找
Context jndiContext =newInitialContext();DataSource source =(DataSource) jndiContext.lookup("java:comp/env/jdbc/corejava");Connection conn = source.getConnection();
LDAP介绍
轻量级目录访问协议(Lightweight Directory Access Protocol, LDAP)
通用的LDAP属性
| 属性ID | 意义 |
| dc | 域构件 |
| cn | 通用名 |
| sn | 姓 |
| dn | 专有名称 |
| o | 组织 |
| ou | 组织单元 |
| uid | 唯一标识符 |
Hashtable env =newHashtable();env.put(Context.SECURITY_PRINCIPAL, username);env.put(Context.SECURITY_CREDENTIALS, password);DirContext initial =newInitialDirContext(env);DirContext context =(DirContext) initial.lookup("ldap://localhost:389");
javax.naming.directory.InitialDirContext 1.3
InitialDirContext(Hashtable env)//使用给定的环境设置创建一个目录上下文,散列表包含了Context.SECURITY_PRINCIPAL、Context.SECURITY_CREDENTIALS以及其他键的相关信息
javax.naming.Context 1.3
Object lookup(String name)//使用给定的名称查找对象,返回通常为一棵子树或一个叶对象Context createSubcontext(String name)//使用给定的名字创建一个子上下文void destroySubcontext(String name)//根据给定的名称删除其对应的子上下文void close()//关闭该上下文
javax.naming.directory.DirContext 1.3
Attributes getAttributes(String name)//根据给定的名称,得到其对应条目的属性void modifyAttributes(String name,int flag,Attributes modes)//根据给定的名称,修改其对应条目的属性,flag为以下常量之一:DirContext.ADD_ATTRIBUTE、DirContext.REMOVE_ATTRIBUTE或DirContext.REPLACE_ATTRIBUTE
javax.naming.directory.Attributes 1.3
Attribute get(String id)//根据给定的ID,得到其对应的属性NamingEnumeration<?extendsAttribute> getAll()//返回一个枚举对象,用于迭代遍历该属性的所有值Attribute put(Attribute attr)Attribute put(String id,Object value)//将一个属性添加到属性集合中
javax.naming.directory.BasicAttributes 1.3
BasicAttributes(String id,Object value)//使用给定的ID和值,构造一个属性集合,该集合只包含了单个属性
javax.naming.directory.Attribute 1.3
String getId()//获取该属性的IDObject get()//如果值已排好序,则获取该属性的第一个值,未排序则返回其中任意一个值NamingEnumeration<?> getAll()//返回一个枚举对象,用于迭代遍历该属性的所有值
javax.naming.NamingEnumeration<T> 1.3
boolean hasMore()//如果该对象还包含其他元素,返回trueT next()//返回下一个元素

浙公网安备 33010602011771号