十一,IO流
1.File类
java.io.File
1)File类的使用
1.file类的一个对象,代表一个文件或一个文件目录(俗称:文件夹)
2.File类声明在java.io包下
*相对路径:hello.txt 相较于某个路径下,指明的路径。
绝对路径:D://temp.txt 包含盘符在内的文件或文件目录的路径。
*路径分隔符:window用\,url用/。
2)如何创建File类的实例:
public static void main(String[] args) {
File file=new File("D:\\input\\input.txt.txt");
System.out.println(file);//输出文件路径 D:\input\input.txt.txt
File file1 = new File("jdbc.properties");
System.out.println(file1);jdbc.properties
}
3)常用方法:
public static void main(String[] args) {
File file=new File("D:\\input\\input.txt.txt");
File file1 = new File("jdbc.properties");
String path = file.getAbsolutePath();//获取绝对路径
System.out.println(path);//D:\input\input.txt.txt
System.out.println(file1.getAbsolutePath());//E:\IEDADEMO\jdbc.properties
String filePath = file.getPath();//获取路径
System.out.println(filePath);//D:\input\input.txt.txt
System.out.println(file1.getPath());//jdbc.properties
String name = file.getName();//获取名字
System.out.println(name);//input.txt.txt
String parent = file.getParent();//获取上一层目录
System.out.println(parent);//D:\input
long length = file.length();//长度,字节
System.out.println(length);//292
long modified = file.lastModified();//最近修改时间
System.out.println(modified);//1572326293899
/**
* 仅适用于目录
*/
File file2 = new File("D:\\wokespace");
String[] list = file2.list();//列出其下一级文件目录
for (String s:list){
System.out.println(s);
}
System.out.println("***********************************************");
File[] files = file2.listFiles();//列出其下一级文件目录的绝对路径
for (File f: files){
System.out.println(f);
}
System.out.println("**************************");
boolean b = file1.renameTo(file);//把file1重命名为file的名字
//要想保证成功,file1在硬盘中是真实存在的,file在硬盘中是不存在的
System.out.println(b);
}
public static void main(String[] args) {
File file = new File("jdbc.properties");
//判断功能
System.out.println(file.isDirectory());//判断是不是一个目录 false
System.out.println(file.isFile());//判断是不是一个文件true
System.out.println(file.exists());//判断是否真实存在true
System.out.println(file.canRead());//判断是否可读true
System.out.println(file.canWrite());//判断是否可写true
System.out.println(file.isHidden());//判读是否隐藏 false
}
public static void main(String[] args) {
//File的创建功能和删除功能
File file = new File("jdbc1.properties");
if (!file.exists()){
try {
file.createNewFile();//创建文件
System.out.println("文件创建成功!");
} catch (IOException e) {
e.printStackTrace();
}
}else{
file.delete();//删除文件,不走回收站,直接删除
System.out.println("文件删除成功!");
}
file.mkdir();//创建单层目录
file.mkdirs();//创建多层目录
}
file.delete()删除目录时,要想删除成功,该目录下不能有文件或目录。
4)面试题:
/**
* 创建一个与File同目录下的另外一个文件,文件名为:haha.txt
* @param args
*/
public static void main(String[] args) {
File file = new File("D:\\temp\\temp1.txt");
File file1 = new File(file.getParent() , "haha.txt");
System.out.println(file.getParent());
try {
boolean newFile = file1.createNewFile();
if (newFile){
System.out.println("创建成功!");
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 遍历指定目录下所文件名称,包括子文件目录中的文件
* 1.并计算指定目录占用空间的大小
* 2.删除指定文件下的目录及其下的文件夹
*/
public static void main(String[] args) {
File file = new File("D:\\temp");
int sum=print(file);
System.out.println(sum);
}
//遍历指定目录下所文件名称,包括子文件目录中的文件,并计算指定目录占用空间的大小
public static int print(File file){
File []files=file.listFiles();
int sum=0;
for (File f:files){
if (f.isDirectory()){
print(f);
f.delete();
}else{
System.out.println(f.getAbsolutePath());
sum+=f.length();
f.delete();
}
}
return sum;
}
public static void main(String[] args) {
/**
* 判断指定目录下是否存在后缀名为.jpg的文件,如果就输出该文件名;
*/
File file = new File("D:\\QQ");
Find(file);
}
public static void Find(File file){
File []files=file.listFiles();
for (File f: files){
if (f.isDirectory()){
Find(f);
}else{
if (f.getName().endsWith(".jpg")){
System.out.println(f.getAbsolutePath());
}
}
}
2.IO流
1)概述
IO流原理及流的分类
input/output的缩写,处理设备之间的数据传输。
input:读取外部数据
output:将程序中的数据输出
按照操作数据单位的不同,分为字节流(8bit)和字符流(6bit)适合于文本。
输入流:inputStream,reader
输出流:outputStream,Writer
按照流的角色不同:作用在文件上的:节点流,作用在已经有的流上的:处理流。
按照数据流向:输入流,输出流。
IO流的体系结构
抽象基类 节点流 缓冲流
InputStream FileInputStream BufferedInputStream
OutputStream FileOutputStream BufferedOutputStream
Reader FileReader BufferedReader
Writer FileWriter BufferedWriter
2)节点流-FileReader和FileWriter
FileReader读入数据的基本操作
说明点:
①read()地理解:返回读入的一个字符,如果达到文件末尾,返回-1
②异常的处理:为了保证流资源一定可以执行关闭操作,需要使用try-catch-finally处理。
③读入的文件一定要存在,否则就会报FileNotFoundException
/**
* FileReader读取硬盘文件
* @param args
*/
public static void main(String[] args){
FileReader reader=null;
BufferedReader reader1=null;
try {
reader = new FileReader(new File("jdbc.properties"));//相较于当前工程
reader1 = new BufferedReader(reader);
int data ;//返回读入的一个字符,如果达到文件末尾,返回-1.
while ((data=reader1.read())!=-1){//循环读取数据
System.out.print((char)data);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {//关闭流
if (reader!=null){
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(reader1!=null){
try {
reader1.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
//对read(的升级,使用read的重载方法
FileReader reader=null;
BufferedReader br=null;
try {
reader = new FileReader(new File("jdbc.properties"));
br=new BufferedReader(reader);
char []buf=new char[1024];
int len=0;
while ((len=br.read(buf))!=-1){//返回每次读入buf[]数组中的字符个数,如果达到文件末尾,返回-1
// for(int i=0;i<len;i++){
// System.out.print(buf[i]);
// }
String str=new String(buf,0,len);
System.out.print(str);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally{
if (reader!=null){
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (br!=null){
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
FileWriter写出数据的操作
说明:
①输出操作:对应的File可以不存在,如果不存在,在输出过程中,会自动创建此文件。
②如果存在:如果流使用的构造器是FileWriter(file,false)/FileWriter(file):对原有文件覆盖。
如果流使用FileWriter(file,true):不会对原有文件覆盖。
/**
* 从内存写出数据到硬盘文件
* @param args
*/
public static void main(String[] args) {
FileWriter writer = null;
try {
writer= new FileWriter(new File("hello.txt"),true);
//true时表示对原文件的追加,false或不写表示对原文件的覆盖
writer.write("I have a dream !");//写入文件
} catch (IOException e) {
e.printStackTrace();
}finally{
if (writer!=null){
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
使用FileReader和FileWriter实现文本文件的复制
字符流不能处理图片文件
/**
* 将一个文件写入另一个文件
* @param args
*/
public static void main(String[] args) {
FileReader fr=null;
FileWriter fw=null;
try {
fr=new FileReader(new File("E:\\IEDADEMO\\day07\\src\\com\\atguigu\\IO\\IO.txt"));
fw=new FileWriter(new File("hello.txt"));
//数据的读入和写出操作
char []buf=new char[1024];
int len=0;//记录每次读入到数组的数据多少个
while ((len=fr.read(buf))!=-1){
fw.write(buf,0,len);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
if (fw!=null){
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fr!=null){
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
3)节点流-FileInputStream和FileOutputStream
使用FileInputStream不能读取文本文件的测试:
结论:对于文本文件,使用字符流处理
对于非文本文件,使用字节流处理
/**
* 使用FileInputStream不能读取文本文件的测试
*/
public static void main(String[] args) {
FileInputStream fis=null;
FileOutputStream fos=null;
try {
fis=new FileInputStream(new File("E:\\IEDADEMO\\day07\\src\\com\\atguigu\\IO\\IO.txt"));
fos=new FileOutputStream(new File("hello.txt"));
byte [] bytes=new byte[1024];
int len=0;
while ((len=fis.read(bytes))!=-1){
fos.write(bytes,0,len);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
if (fos!=null){
fos.close();
}
if (fis!=null){
fis.close();
}
}catch (IOException e) {
e.printStackTrace();
}
}
}
FileInputStream和FileOutputStream读写非文本文件
/**
* FileInputStream和FileOutputStream读写非文本文件
* @param args
*/
public static void main(String[] args) {
FileInputStream fis=null;
FileOutputStream fos=null;
try {
fis=new FileInputStream(new File("E:\\IEDADEMO\\day07\\src\\下载.png"));
fos=new FileOutputStream(new File("D:\\test.png"));
byte[] bytes=new byte[1024*1024];
int len=0;
while ((len=fis.read(bytes))!=-1) {
fos.write(bytes,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fos!=null){
fos.close();
}
if (fis!=null){
fis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
写一个复制文件的方法,可以用来直接调用,
public static void main(String[] args) {
File file = new File("hello.txt");
File file1 = new File("D://hello.txt");
Copy(file,file1);
}
public static void Copy(File file,File file1){
FileInputStream fis=null;
FileOutputStream fos=null;
try {
fis=new FileInputStream(file);
fos=new FileOutputStream(file1);
byte [] bytes=new byte [1024];
int len;
while((len=fis.read(bytes))!=-1){
fos.write(bytes,0,len);
}
System.out.println("复制完成!");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fos!=null){
fos.close();
}
if (fis!=null){
fis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
4)处理流之一:缓冲流
缓冲流作用:提高流的读取写入速度
提高读写速度的原因:内部提供了一个缓冲区:1024*8=8192
缓冲流(字节型)实现非文本文件的复制
public static void main(String[] args) {
FileInputStream fis=null;
FileOutputStream fos=null;
BufferedInputStream bis=null;
BufferedOutputStream bos=null;
try {
fis=new FileInputStream(new File("hello.txt"));
fos=new FileOutputStream(new File("D://hello.txt"));
bis=new BufferedInputStream(fis);
bos=new BufferedOutputStream(fos);
byte [] bytes=new byte[1024];
int len;
while ((len=bis.read(bytes))!=-1){
bos.write(bytes,0,len);
}
System.out.println("复制完成!");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (bos!=null){
bos.close();
}
if (bis!=null){
bis.close();
}
if (fos!=null){
fos.close();
}
if (fis!=null){
fis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
缓冲流(字符型)实现文本文件的复制
处理流:就是套接在已有流的基础上
public static void main(String[] args) {
FileReader fr=null;
FileWriter fw=null;
BufferedReader br=null;
BufferedWriter bw=null;
try {
fr=new FileReader(new File("hello.txt"));
fw=new FileWriter(new File("D://hello.txt"));
br=new BufferedReader(fr);
bw=new BufferedWriter(fw);
//方式一:
// char [] chars=new char[1024];
// int len=0;
// while ((len=br.read(chars))!=-1){
// bw.write(chars,0,len);
// }
//方式二:
String data;
while ((data=br.readLine())!=null){
bw.write(data);//一次读取一行
bw.newLine();//换行
}
System.out.println("文本复制完成!");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (bw!=null){
bw.close();
}
if (br!=null){
br.close();
}
if (fw!=null){
fw.close();
}
if (fr!=null){
fr.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
5)面试题
1.图片加密和图片解密
/***
* 图片加密
* @param args
*/
public static void main(String[] args) {
BufferedInputStream bis=null;
BufferedOutputStream bos=null;
try {
bis=new BufferedInputStream(new FileInputStream(new File("D:\\尹会东.jpg")));
bos=new BufferedOutputStream(new FileOutputStream(new File("D:\\copy.jpg")));
int len=0;
byte [] bytes=new byte[1024];
while ((len=bis.read(bytes))!=-1){
for (int i = 0; i <len ; i++) {
bytes[i]= (byte) (bytes[i]^5);//加密操作
}
bos.write(bytes,0,len);
}
System.out.println("加密完成!");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (bis!=null){
bis.close();
}
if (bos!=null){
bos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 图片解密
*/
public static void main(String[] args) {
BufferedInputStream bis=null;
BufferedOutputStream bos=null;
try {
bis=new BufferedInputStream(new FileInputStream(new File("D:\\copy.jpg")));
bos=new BufferedOutputStream(new FileOutputStream(new File("D:\\copy1.jpg")));
int len=0;
byte [] bytes=new byte[1024];
while ((len=bis.read(bytes))!=-1){
for (int i = 0; i <len ; i++) {
bytes[i]= (byte) (bytes[i]^5);//解密操作
}
bos.write(bytes,0,len);
}
System.out.println("解密完成!");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (bis!=null){
bis.close();
}
if (bos!=null){
bos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
2.获取文本上每个字符出现的次数
/**
* 获取文本上每个字符出现的次数
*/
public static void main(String[] args) {
HashMap<Character, Integer> map = new HashMap<>();
BufferedReader br=null;
BufferedWriter bw=null;
try {
br=new BufferedReader(new FileReader(new File("hello.txt")));
bw=new BufferedWriter(new FileWriter(new File("D:\\WorldCount.txt")));
int c=0;
while ((c=br.read())!=-1){
char ch= (char) c;
if (map.get(ch)==null){
map.put(ch,1);
}else{
map.put(ch,map.get(ch)+1);
}
}
Set<Map.Entry<Character, Integer>> set = map.entrySet();
Iterator<Map.Entry<Character, Integer>> iterator = set.iterator();
while (iterator.hasNext()){
bw.write(iterator.next().getKey()+"--------------"+iterator.next().getValue());
bw.newLine();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (bw!=null){
bw.close();
}
if (br!=null){
br.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
3.将一个文件写入另一个文件
/**
* 将一个文件写入另一个文件
* @param args
*/
public static void main(String[] args) {
FileReader fr=null;
FileWriter fw=null;
try {
fr=new FileReader(new File("E:\\IEDADEMO\\day07\\src\\com\\atguigu\\IO\\IO.txt"));
fw=new FileWriter(new File("hello.txt"));
//数据的读入和写出操作
char []buf=new char[1024];
int len=0;//记录每次读入到数组的数据多少个
while ((len=fr.read(buf))!=-1){
fw.write(buf,0,len);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
if (fw!=null){
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fr!=null){
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
6)处理流之二:转换流
1.作用:提供了字节流和字符流的转换
2.转换流属于字符流
InputStreamReader:将一个字节的输入流转换为字符的输入流
OutputStreamWriter:将一个字符的输出流转换为字节的输出流
3.解码:字节,字节数组——->字符数组,字符串
编码:字符数组,字符串——->字节,字节数组
4.字符集
public static void main(String[] args) {
FileInputStream fis=null;
InputStreamReader isr=null;
FileOutputStream fos=null;
OutputStreamWriter osw=null;
try {
fis = new FileInputStream(new File("hello.txt"));
// InputStreamReader isr = new InputStreamReader(fis);//使用系统默认字符集
isr = new InputStreamReader(fis, StandardCharsets.UTF_8);//指定字符集
fos=new FileOutputStream(new File("D:\\Temps.txt"));
osw=new OutputStreamWriter(fos,"utf-8");
char [] chars=new char[1024];
int len;
while ((len=isr.read(chars))!=-1){
osw.write(chars,0,len);
}
// while ((len=isr.read(chars))!=-1){
// String str=new String(chars,0,len);
// System.out.println(str);
// }
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (isr!=null){
isr.close();
}
if (fis!=null){
fis.close();
}
if (osw!=null){
osw.close();
}
if (fos!=null){
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
7)其他流(了解)
其他流(了解)
1.标准的输入输出流
1.1
System.in标准的输入流
System.out标准的输出流
1.2我们可以通过System类的setIn(InputStream)/setOut(OutputStream)方式重新指定输入和输出的流。
1.3练习:IO5
public static void main(String[] args) {
/**
* 键盘输入字符,如果是e或exit程序结束,否则转化为大写输出
*/
InputStreamReader isr=new InputStreamReader(System.in);
BufferedReader br=new BufferedReader(isr);
while (true){
String data= null;
try {
data = br.readLine();
if (data.equalsIgnoreCase("e")||data.equalsIgnoreCase("exit")){
System.out.println("程序结束!");
break;
}else{
System.out.println(data.toUpperCase());
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if (isr!=null){
isr.close();
}
if (br!=null){
br.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
2.打印流
PrintStream
PrintWriter
3.数据流
DataInputStream
DataOutputStream
4.随机存取文件流
RandomAccessFile
既可以读,也可以写。
实现了DataInput和DataOutput接口
java.io下,但是直接继承Object类
如果RandomAccessFile作为输出流时,写出到的文件不存在,会自动创建,
如果写出到的文件存在,会对原有文件进行覆盖,(默认情况下,从头覆盖)
public static void main(String[] args) {
RandomAccessFile file = null;
RandomAccessFile file1 = null;
try {
file=new RandomAccessFile(new File("hello.txt"),"r");
file1=new RandomAccessFile(new File("D:\\object.txt"),"rw");
byte []bytes=new byte[1024];
int len=0;
while ((len=file.read(bytes))!=-1){
file1.write(bytes,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (file!=null){
file.close();
}
if (file1!=null){
file1.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
RandomAccessFile类实现数据插入
public static void main(String[] args) {
RandomAccessFile raf=null;
try {
raf=new RandomAccessFile("hello.txt","rw");
//raf.seek(3);//指定开始覆盖的位置
raf.seek(new File("hello.txt").length());//最后面插入
/**
* 如果想要在中间插入,可以先将后面的内容读取到内存的某个变量,
* 然后写入要插入的数据,再将变量中的内容插入末尾。
*/
raf.write("xyz".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (raf!=null){
raf.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
8)对象流
ObjectInputStream用于存储和读取基本数据类型或对象的流处理。
序列化:用ObjectOutputStream将数据从内存写入硬盘
反序列化:ObjectInputStream将数据从硬盘读入内存。
要求对象所属的类是可序列化的—->实现了Seralizable接口
面试题:如何理解对象序列化机制?
把内存中的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久的保存在硬盘上,或者通过网络,
将这种二进制流传输到另一个网络节点,当其他程序获取了这种二进制流,就可以恢复成原来的Java对象。
序列化的好处在于将任何实现了Seralizable接口的对象转化为字节数据,使其在保存和传输中可被还原。
序列化
public static void main(String[] args) {
//序列化过程:
ObjectOutputStream oos=null;
try {
oos=new ObjectOutputStream(new FileOutputStream(new File("D:\\object.txt")));
oos.writeObject(new String("我爱北京天安门"));
oos.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(oos!=null){
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
反序列化
//反序列化
public static void main(String[] args) {
ObjectInputStream ois =null;
try {
ois=new ObjectInputStream(new FileInputStream(new File("D://object.txt")));
Object object = ois.readObject();
String str= (String) object;
System.out.println(str);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
if (ois!=null){
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
自定义类实现序列化与反序列化操作
1.需要实现java.io.Serializable接口
2. public static final long serialVersionUID= 6080347956336285349L;
3.除了当前Person类需要实现Serializable接口之外,还必须保证其内部所有属性也必须是可序列化的。
(默认情况下基本数据类型是可序列化的)
4.不能序列化static和transient的
public class Person implements java.io.Serializable{
public static final long serialVersionUID= 6080347956336285349L;
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public static void main(String[] args) {
//序列化
ObjectOutputStream oos =null;
ObjectInputStream ois=null;
try {
oos=new ObjectOutputStream(new FileOutputStream(new File("D://object.txt")));
Person person = new Person("张贝贝", 25);
oos.writeObject(person);
//反序列化
ois=new ObjectInputStream(new FileInputStream(new File("D:\\object.txt")));
Object obj=ois.readObject();
Person p1= (Person) obj;
System.out.println(p1.toString());
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
if (ois!=null){
ois.close();
}
if (oos!=null){
oos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
serialVersionUID的理解
如果不手动写,Java会自动生成一个。
如果序列化以后修改了类,serialVersionUID也会被Java修改,
反序列化会失败!
十二,网络编程
网络编程中有两个主要的问题:
1.如何准确的定位到网络上一台或者多台主机:定位主机上的特定应用
2.找到主机后如何可靠高效的进行数据传输
网络编程中的两个要素
1.对应的问题:IP和端口号
2.对应问题二:提供网络通信协议:TCP/IP参考模型
通信要素一:IP和端口号
1.IP:唯一标识Internet上的计算机(通信实体)
2.在Java中使用InetAddress类代表IP
3.IP分类:IPV4和IPV6;万维网和局域网的区别
4.域名:www.baidu.com
5.域名--》NDS--》网络服务器
6.本地回路地址:127.0.0.1 对应着localhost
7.如何实例化InetAddress:两个方法;getByName(String host),getLocalHost();
端口号:表示计算机上运行的程序
不同进程有不同的端口号
Tomcat:8080,mysql:3306,oracle:1521
端口号与IP地址组合得出一个网络套接字,Socket
范围:0-65535
public static void main(String[] args) {
try {
InetAddress name = InetAddress.getByName("127.0.0.1");
System.out.println(name);
InetAddress name1 = InetAddress.getByName("www.baidu.com");
System.out.println(name1);
System.out.println(name.getHostName());
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
TCP:3次握手,UDP:封装数据包
Tcp网络编程
/**
* @author yinhuidong
* @createTime 2020-04-10-21:24
* TCP网络编程1:客户端向服务端发送消息,服务端将消息显示在控制台上
*/
public class Test1 {
//客户端
@Test
public void client()throws Exception{
InetAddress address = InetAddress.getByName("127.0.0.1");
Socket socket = new Socket(address, 3307);
OutputStream os = socket.getOutputStream();
os.write("你好,我是客户端".getBytes());
os.close();
socket.close();
}
//服务端
@Test
public void server()throws Exception{
ServerSocket serverSocket = new ServerSocket(3307);
Socket socket = serverSocket.accept();
InputStream is = socket.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int len;
byte[] buffer = new byte[10];
while ((len=is.read(buffer))!=-1){
baos.write(buffer,0,len);
}
System.out.println(baos.toString());
baos.close();
is.close();
socket.close();
serverSocket.close();
}
}
/**
* @author yinhuidong
* @createTime 2020-04-10-21:40
* 客户端给服务端发送文件,服务端保存文件并告诉客户端自己接收成功
* //如果不关闭资源,会抛出:java.net.SocketException: Connection reset异常
*/
public class Test2 {
//客户端
@Test
public void test1() throws Exception {
//获取IP地址
InetAddress address = InetAddress.getByName("127.0.0.1");
//获取socket对象
Socket socket = new Socket(address, 3308);
//写入本地图片
FileInputStream is = new FileInputStream(new File("E:\\9.jpg"));
byte[] buffer = new byte[1024 * 8];
int len;
//将本地图片写出到服务端
OutputStream os = socket.getOutputStream();
while ((len = is.read(buffer)) != -1) {
os.write(buffer, 0, len);
}
socket.shutdownOutput();
//获取输入流准备接受服务端的消息
InputStream stream = socket.getInputStream();
byte[] buffer2 = new byte[10];
int len2;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while ((len2 = stream.read(buffer2)) != -1) {
baos.write(buffer2, 0, len2);
}
//输出消息到控制台
System.out.println(baos.toString());
baos.close();
stream.close();
os.close();
is.close();
socket.close();
}
@Test
public void test2() throws Exception {
//创建一个服务端ServerSocket
ServerSocket serverSocket = new ServerSocket(3308);
//获取socket
Socket socket = serverSocket.accept();
//获取输入流
InputStream is = socket.getInputStream();
//指定输出流输出文件位置
FileOutputStream fos = new FileOutputStream(new File("E:\\10.jpg"));
int len;
byte[] buffer = new byte[1024 * 8];
while ((len = is.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
//获取输出流
OutputStream stream = socket.getOutputStream();
//输出内容
stream.write("接收文件成功".getBytes());
stream.close();
fos.close();
is.close();
socket.close();
serverSocket.close();
}
}
UDP网络编程
/**
* @author yinhuidong
* @createTime 2020-04-10-23:03
* UDP网络编程
*/
public class Test4 {
//发送端
@Test
public void send()throws Exception{
DatagramSocket socket = new DatagramSocket();
byte []data="我是UDP方式的发送端".getBytes();
InetAddress inet = InetAddress.getLocalHost();
DatagramPacket packet = new DatagramPacket(data, 0, data.length,inet, 8081);
socket.send(packet);
}
//接收端
@Test
public void receiver()throws Exception{
DatagramSocket socket = new DatagramSocket(8081);
byte[] buffer = new byte[100];
DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
socket.receive(packet);
System.out.println(new String(packet.getData(), 0, buffer.length));
}
}
URL类的理解与实例化
URL:统一资源定位符,他表示internet上某一资源的地址。
格式:协议,主机名,端口号,片段名,参数列表
public static void main(String[] args) throws IOException {
URL url = new URL("www.baidu.com");
HttpURLConnection connection= (HttpURLConnection) url.openConnection();//获取连接
connection.connect();//连接
connection.getInputStream();//获取流
}
十三,反射
1.概述
反射
反射机制允许程序在执行时借助于反射API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
反射相关的主要API
java.lang.Class
java.lang.reflect.
关于java.lang.Class类的理解:*
1.类的加载过程:程序在经过javac.exe命令后,会生成一个或多个字节码文件(.class结尾),接着我们
使用java.exe命令对某个字节码文件进行解释运行。相当于将某个字节码文件加载到内存中。此过程称为类的加载。
加载到内存中的类,我们就称为运行时类,此运行的类,就作为Class的一个实例。
2.换句话说:Class的实例就对应着一个运行时类。
类的加载过程(了解)
①类的加载:将类的class文件读入内存,并为之创建一个java.lang.Class对象,此过程由类的加载器完成。
②类的链接:将类的二进制数据合并到JRE中,赋默认值。
③类的初始化:JVM负责对类进行初始化。将静态代码块和类中赋值操作的语句读取,给变量/常量赋值。
类的加载器ClassLoader的理解:(了解)
作用:把类加载进内存。
2.获取Class的实例的方式(重点)
加载到内存中的运行时类,会缓存一定的时间,在此时间内,我们可以通过不同的方式来获取此运行时的类。
Class实例对应的结构说明:
①claass,②interface,③数组④枚举类⑤注解⑥基本数据类型⑦void
/**
* @author yinhuidong
* @createTime 2020-04-11-9:57
* 获取Class实例的四种方式
*/
public class Test1 {
//通过对象.getClass()的方式
@Test
public void test1() {
Class<? extends Person> clazz = new Person().getClass();
}
//通过类.class
@Test
public void test2() {
Class<Person> clazz = Person.class;
}
//通过Class的静态方法
@Test
public void test3() throws Exception {
Class<?> clazz = Class.forName("com.atguigui.java1.Person");
}
//通过类加载器
@Test
public void test4() throws Exception{
ClassLoader classLoader = Person.class.getClassLoader();
classLoader.loadClass("com.atguigui.java1.Person");
}
}
class Person {
private String name;
private Integer age;
public Person() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
3.使用ClassLoader加载配置文件
@Test
public void test4() throws Exception {
Properties prop=new Properties();
//读取配置文件的方式一:
//此时配置文件默认在当前module下
// FileInputStream fis = new FileInputStream("jdbc.properties");
// prop.load(fis);
//读取配置文件的方式二:使用ClassLoader
//配置文件默认识别为:当前module的src下
ClassLoader classLoader=Test1.class.getClassLoader();
InputStream is = classLoader.getResourceAsStream("driud.properties");
prop.load(is);
String user=prop.getProperty("user");
String password=prop.getProperty("password");
System.out.println(user+" "+password);
}
4.创建运行时类对象与反射的动态性
通过反射,创建运行时类对象
newInstance()调用此方法,创建对应的运行时类的对象,内部调用了运行时类的空参构造器。
要想此方法正常运行:
①运行时类必须提供空参的构造器
②空参构造器访问权限得够。
在JavaBean中要求提供一个空参构造器的原因:
①便于通过反射,创建运行时类的对象。
②便于子类继承此运行类时,默认调用super方法时,保证父类有此构造器。
@Test
public void test5() throws IllegalAccessException, InstantiationException {
Class<Person>clazz=Person.class;
Person obj=clazz.newInstance();
System.out.println(obj);
}
反射的动态性举例
@Test
public void test6() throws Exception {
Object instance = getInstance("java.util.Date");
System.out.println(instance);
}
//创建一个指定类的对象。classPath:指定类的全类名。
public Object getInstance(String classPath)throws Exception{
Class clazz=Class.forName(classPath);
return clazz.newInstance();
}
5.调用运行时类的指定结构
属性,
@Test
public void test() throws Exception {
Class clazz=Person.class;
//创建运行时类的对象
Object o = clazz.newInstance();
//获取指定的属性:public
Field name = clazz.getField("name");
name.set(o,"yinhuidong");
String o1 = (String) name.get(o);
System.out.println(o1);
}
@Test//掌握
public void test2() throws Exception {
Class clazz=Person.class;
//创建运行时类的对象
Object o = clazz.newInstance();
//获取指定的属性:无关权限修饰符,不包含父类
Field age = clazz.getDeclaredField("age");
age.setAccessible(true);//给与修改权限
age.set(o,20);
Object obj = age.get(o);
System.out.println(obj);
}
方法,
@Test//掌握
public void test3()throws Exception{
//如何操作运行时类中的指定非静态方法
Class<Person> clazz = Person.class;
Person person = clazz.newInstance();
Method show = clazz.getDeclaredMethod("show");
show.setAccessible(true);
Object obj = show.invoke(person);
Method add = clazz.getDeclaredMethod("add", int.class, int.class);
add.setAccessible(true);
Integer invoke = (Integer) add.invoke(person, 1, 1);
System.out.println(invoke);
}
@Test
public void test4() throws Exception{
//如何操作运行时类中的指定静态方法
Class clazz=Person.class;
Method eat = clazz.getDeclaredMethod("eat");
eat.setAccessible(true);
eat.invoke(Person.class);
}
构造器
@Test//不是很常用,了解
public void test5() throws Exception{
//调用运行时类中的指定构造器
Class clazz=Person.class;
Constructor constructor = clazz.getDeclaredConstructor(String.class, Integer.class);
constructor.setAccessible(true);
Object obj = constructor.newInstance("Tom",22);
System.out.println(obj);
}
6.代理
代理设计模式的原理:使用一个代理将对象包装起来,然后用该代理对象取代原始对象。
任何对原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。
静态代理举例
特点:编译期间,代理类和被代理类就被确定下来了。
interface ClothFactory{
void produceCloth();
}
//代理类
class ProxyClothFactory implements ClothFactory{
private ClothFactory factory;//就拿被代理对象进行实例化
public ProxyClothFactory(ClothFactory factory) {
this.factory = factory;
}
@Override
public void produceCloth() {
System.out.println("代理工厂进行准备工作");
factory.produceCloth();
System.out.println("代理工厂做后续工作!");
}
}
//被代理类
class Nike implements ClothFactory{
@Override
public void produceCloth() {
System.out.println("耐克工厂生产一批运动服!");
}
}
@Test
public void test(){
Nike nike=new Nike();
ProxyClothFactory proxyClothFactory = new ProxyClothFactory(nike);
proxyClothFactory.produceCloth();
}
动态代理示例
动态代理:可以通过一个代理类完成全部的代理功能。
要求:理解过程。
/**
* @author yinhuidong
* @createTime 2020-04-11-11:17
* 基于接口的动态代理
*/
public class Test1 {
private PersonDao dao=new PersonDaoImpl();
@Test
public void test(){
//动态代理
PersonDao personDao = (PersonDao) Proxy.newProxyInstance(
//被代理类的类加载器
dao.getClass().getClassLoader(),
//被代理类实现的接口
dao.getClass().getInterfaces(),
//InvocationHandler接口的实现类
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object o=null;
if (!method.getName().equals("show")){
Integer a= (Integer) args[0];
Integer b= (Integer) args[1];
//对方法进行增强
o=method.invoke(dao,a*2,b*2);
return o;
}
o=method.invoke(dao);
return o;
}
}
);
System.out.println(personDao.add(1, 1));
personDao.del(2,1);
personDao.show();
}
}
//被代理类实现的接口
interface PersonDao{
int add(int a,int b);
void del(int a,int b);
void show();
}
//被代理类
class PersonDaoImpl implements PersonDao{
@Override
public int add(int a, int b) {
return a+b;
}
@Override
public void del(int a, int b) {
System.out.println(a-b);
}
@Override
public void show() {
System.out.println("show()....");
}
}
7.总结
import java.util.Properties;
/**
* @author yinhuidong
* @createTime 2020-02-25-23:36
*/
public class Test3 {
/**
* 第二轮复习
* 获取运行时类的Class实例
*/
@Test
public void test1() throws ClassNotFoundException {
//方式一:
Class<Person> clazz = Person.class;
System.out.println(clazz);
//方式二:
Person person = new Person();
Class<? extends Person> clazz1 = person.getClass();
System.out.println(clazz1);
//方式:
Class<?> clazz2 = Class.forName("com.atguigu.java3.Person");
System.out.println(clazz2);
//方式四:
ClassLoader loader = Test3.class.getClassLoader();
Class<?> clazz3 = loader.loadClass("com.atguigu.java3.Person");
System.out.println(clazz3);
}
/**
* 使用ClassLoader加载配置文件
*/
@Test
public void test2() throws IOException {
InputStream is = Test3.class.getClassLoader().getResourceAsStream("xxx.properties");
Properties prop = new Properties();
prop.load(is);
}
/**
* 通过反射,创建运行时类的对象
*/
@Test
public void test3() throws IllegalAccessException, InstantiationException {
Class<Person> clazz = Person.class;
Person person = clazz.newInstance();
System.out.println(person.toString());
}
/**
* 反射的动态性举例
*/
@Test
public void test4() {
try {
Object p = GetInstance("com.atguigu.java3.Person");
System.out.println(p.toString());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public Object GetInstance(String path) throws ClassNotFoundException {
Class<?> clazz = Class.forName(path);
return clazz;
}
/**
* 调用运行时类的指定结构
* 1.属性
*/
@Test//只能获取公的属性
public void test5() throws IllegalAccessException, InstantiationException, NoSuchFieldException {
Class<Person> clazz = Person.class;
Person p = clazz.newInstance();
Field name = clazz.getField("name");
name.set(p,"张");
System.out.println(name.get(p));
}
@Test//可以获取私的属性
public void test6() throws IllegalAccessException, InstantiationException, NoSuchFieldException {
Class<Person> clazz = Person.class;
Person p = clazz.newInstance();
//可以获取所属性
Field name = clazz.getDeclaredField("name");
name.setAccessible(true);
name.set(p,"张");
System.out.println(name.getName());
Field age = clazz.getDeclaredField("age");
age.setAccessible(true);
age.set(p,12);
System.out.println(age.get(p));
System.out.println(p.toString());
}
@Test//调用非静态方法
public void test7() throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class<Person> clazz = Person.class;
Person p = clazz.newInstance();
Method show = clazz.getDeclaredMethod("show", String.class);//方法名和形参类型
show.setAccessible(true);
Object args = show.invoke(p, "args");//对象,实参
System.out.println(args);//方法的返回值
}
@Test//调用静态方法
public void test8() throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class<Person> clazz = Person.class;
Person p = clazz.newInstance();
Method eat = clazz.getDeclaredMethod("eat", String.class);
eat.setAccessible(true);
Object o = eat.invoke(Person.class, "可比克");
System.out.println(o);
}
}
class Person {
private String name;
private int age;
public Person() {
}
private int show(String args){
System.out.println(args);
return 1;
}
private static void eat(String food){
System.out.println("正在吃。。。"+food);
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
十四,jdk8新特性
1.Lambda表达式
Lambda表达式的使用
1.举例:Comparator<Integer> c= Comparator.comparingInt(o -> o);
2.格式:->:Lambda操作符
左边叫做形参列表,其实就是接口中的抽象方法的形参列表
右边叫做Lambda体(重写的抽象方法的方法体)
3.关于Lambda表达式的使用
总结:
-> 左边:lambda形参列表的参数类型可以省略(类型推断),如果形参列表只有一个参数,()可以省略。
-> 右边:Lambda体应该使用一对{}包裹,如果Lambda体只有一条执行语句(可能是return语句),{}和return也可以省略。
要求接口只有一个抽象方法。
4.Lambda表达式的本质:作为函数式接口的实例。
5.如果一个接口中只声明了一个抽象方法,则此接口称为函数式接口。
可以使用注解@FunctionalInterface检查是否是一个函数式接口。
用匿名实现类表示的现在都可以用Lambda表达式表示。
public class LambdaTest1 {
//语法格式一:无参数,无返回值
@Test
public void test() {
Runnable r = () -> System.out.println("语法格式一:无参数,无返回值");
r.run();
}
//语法格式二:一个参数,无返回值
@Test
public void test2() {
Consumer<String> c = (String s) -> {
System.out.println(s);
};
c.accept("语法格式二:一个参数,无返回值");
}
//语法格式:类型推断
@Test
public void test3() {
Consumer<String> c = (s) -> {
System.out.println(s);
};
c.accept("语法格式:类型推断");
}
//语法格式四:只一个参数时,省略小括号
@Test
public void test4() {
Consumer<String> c = s -> {
System.out.println(s);
};
c.accept("语法格式四:只一个参数时,省略小括号");
}
//语法格式五:Lambda 需要两个以上参数,多条执行语句,并且有返回值。
@Test
public void test5() {
Comparator<Integer> c = (o1, o2) -> {
System.out.println("语法格式五:Lambda 需要两个以上参数,多条执行语句,并且有返回值。");
return o1.compareTo(o2);
};
int compare = c.compare(32, 21);
System.out.println(compare);
}
//语法格式六:当Lambda体只一条语句时,reurn与大括号若,都可以省略。
@Test
public void test6() {
Comparator<Integer> c = (o1, o2) -> o1.compareTo(o2);
int compare = c.compare(32, 21);
System.out.println(compare);
}
}
Java内置四大核心函数式接口(要求能看懂)
消费性接口 Consumer<T> void accept(T t)
供给型接口 Supplier<T> T get()
函数型接口 Function<T,R> R apply(T t)
断定型接口 Predicate<T> boolean test(T t)
test()
使用情景:当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用。
方法引用:本质上就是Lambda表达式,而Lambda表达式作为函数式接口的实例,
所以方法引用,也是函数式接口的实例。
使用格式: 类(对象)::方法名
具体分为如下三种情况:
对象::非静态方法
类::静态方法
类::非静态方法
方法引用的使用要求,要求接口中的抽象方法的形参列表和返回值类型与方法引用
的方法的形参列表和返回值类型相同!
2.Stream API
1.Stream关注的是数据的运算,与CPU打交道。
集合关注的是是数据的存储,与内存打交道。
2.
①Stream自己不会存储元素。
②Stream不会改变源对象,相反,他们会返回一个持有结果的新Stream。
③Stream操作是延迟执行的,这意味着它们会等到需要结果的时候才执行。
3.Stream的执行流程
①Stream的实例化
②一系列的中间操作(过滤,映射,。。。)
③终止操作
4.说明:
①一个中间链操作,对数据源的数据进行处理。
②一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用。
Stream的实例化:
//创建Stream的方式一:通过集合创建
@Test
public void test() {
List<Employee> employees = EmployeeData.getEmployees();
//返回一个顺序流
Stream<Employee> stream = employees.stream();
//返回一个并行流
Stream<Employee> employeeStream = employees.parallelStream();
}
//创建Stream的方式二:通过数组
@Test
public void test2() {
int[] arr = new int[]{1, 2, 3, 4, 5, 6};
IntStream stream = Arrays.stream(arr);
}
//创建方式:通过Stream的of()
@Test
public void test3() {
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);
}
//创建Stream的方式四,无限流
@Test
public void test4() {
//迭代
Stream.iterate(0, t -> t + 2).limit(10).forEach(System.out::println);
//生成
Stream.generate(Math::random).limit(10).forEach(System.out::println);
}
Stream的中间操作:
1.筛选与切片
@Test//filter()过滤出需要的元素
public void test(){
List<Employee> employees = EmployeeData.getEmployees();
Stream<Employee> stream = employees.stream();
stream.filter(e->e.getAge()>25).forEach(System.out::println);
}
@Test//limit()截断取前面
public void test2(){
List<Employee> employees = EmployeeData.getEmployees();
Stream<Employee> stream = employees.stream();
stream.limit(5).forEach(System.out::println);
}
@Test//skip()截断取后面
public void test3(){
List<Employee> employees = EmployeeData.getEmployees();
Stream<Employee> stream = employees.stream();
stream.skip(5).forEach(System.out::println);
}
@Test//
public void test4(){//distinct()去除重复元素
List<Employee> employees = EmployeeData.getEmployees();
Stream<Employee> stream = employees.stream();
stream.distinct().forEach(System.out::println);
}
2.映射
@Test//map(str -> str + str)
public void test() {
int a[] = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9};
IntStream stream = Arrays.stream(a);
stream.map(str -> str + str).forEach(System.out::println);
}
@Test////map(Employee::getAge)
public void test2() {
List<Employee> employees = EmployeeData.getEmployees();
Stream<Employee> stream = employees.stream();
stream.map(Employee::getAge).filter(age -> age > 25).forEach(System.out::println);
}
3.排序
@Test//自然排序
public void test() {
int a[] = new int[]{1, 2, 3, 5, 9, 7, 6, 45, 65};
IntStream stream = Arrays.stream(a);
stream.sorted().forEach(System.out::print);
}
@Test//定制排序
public void test2() {
List<Employee> employees = EmployeeData.getEmployees();
Stream<Employee> stream = employees.stream();
stream.sorted((o1, o2) -> {
return -o1.getAge().compareTo(o2.getAge());
}).forEach(System.out::println);
}
@Test//定制排序
public void test3() {
List<Employee> employees = EmployeeData.getEmployees();
Stream<Employee> stream = employees.stream();
stream.sorted((o1, o2) -> {
if (o1.getAge() != o2.getAge()) {
return o1.getAge().compareTo(o2.getAge());
} else {
return o1.getId().compareTo(o2.getId());
}
}).forEach(System.out::println);
}
Stream的终止操作
1.匹配与查找
@Test
public void test(){
List<Employee> employees = EmployeeData.getEmployees();
Stream<Employee> stream = employees.stream();
boolean b = stream.allMatch(e -> e.getAge() > 23);
System.out.println(b);
}
@Test
public void test2(){
List<Employee> employees = EmployeeData.getEmployees();
Stream<Employee> stream = employees.stream();
boolean b = stream.anyMatch(e -> e.getAge() > 23);
System.out.println(b);
}
@Test
public void test3(){
List<Employee> employees = EmployeeData.getEmployees();
Stream<Employee> stream = employees.stream();
boolean b = stream.noneMatch(e -> e.getName().contains("java"));
System.out.println(b);
}
@Test
public void test4(){
List<Employee> employees = EmployeeData.getEmployees();
Stream<Employee> stream = employees.stream();
Optional<Employee> first = stream.findFirst();
System.out.println(first);
}
@Test
public void test5(){
List<Employee> employees = EmployeeData.getEmployees();
Stream<Employee> stream = employees.stream();
Optional<Employee> any = stream.findAny();
System.out.println(any);
}
@Test
public void test6(){
List<Employee> employees = EmployeeData.getEmployees();
Stream<Employee> stream = employees.stream();
long count = stream.count();
System.out.println(count);
}
@Test
public void test7(){
List<Employee> employees = EmployeeData.getEmployees();
Stream<Employee> stream = employees.stream();
Optional<Employee> max = stream.max((e1, e2) -> e1.getAge().compareTo(e2.getAge()));
System.out.println(max);
}
@Test
public void test8(){
List<Employee> employees = EmployeeData.getEmployees();
Stream<Employee> stream = employees.stream();
Optional<Employee> min = stream.max((e1, e2) -> -(e1.getAge().compareTo(e2.getAge())));
System.out.println(min);
}
2.归约
@Test
public void test(){
List<Employee> employees = EmployeeData.getEmployees();
Stream<Employee> stream = employees.stream();
Optional<Integer> reduce = stream.map(e -> e.getAge()).reduce((d1, d2) -> d1 + d2);
System.out.println(reduce);
}
@Test
public void test2(){
Integer a[]=new Integer []{1,2,3,4,5,6,7,8,9};
Stream<Integer> stream = Arrays.stream(a);
Integer reduce = stream.reduce(0, Integer::sum);
System.out.println(reduce);
}
3.收集
@Test
public void test(){
List<Employee> employees = EmployeeData.getEmployees();
Stream<Employee> stream = employees.stream();
List<Employee> collect = stream.collect(Collectors.toList());
for (Employee employee : collect) {
System.out.print(employee+" ");
}
}
3.Optional类
Optional类:为了在程序中避免出现空指针异常而创建的。
常用的方法:ofNullable(T t)//允许存null
ofElse(T t)//如果是null,使用形参中的对象。
get()://如果调用对象包含值,返回调用对象,否则抛出异常。
public class OptionalTest {
@Test
public void test() {
Person p=new Person();
String boyName = getBoyName(p);
System.out.println(boyName);//java.lang.NullPointerException原因:男孩为null
}
@Test
public void test2(){
Person p=null;
String boyName = getBoyName(p);
System.out.println(boyName);//java.lang.NullPointerException原因:Person为null
}
@Test
public void test3(){
Person p=null;
System.out.println(getName(p));
}
public String getBoyName(Person person){
return person.getBoy().getName();
}
public String getName(Person person){
Optional<Person> person1 = Optional.ofNullable(person);
Person person2 = person1.orElse(new Person());
Optional<Boy> boy = Optional.ofNullable(person2.getBoy());
Boy boy1 = boy.orElse(new Boy("Tom"));
return boy1.getName();
}
}
class Person {
private Boy boy;
public Person() {
}
public Person(Boy boy) {
this.boy = boy;
}
public Boy getBoy() {
return boy;
}
public void setBoy(Boy boy) {
this.boy = boy;
}
}
class Boy {
private String name;
public Boy() {
}
public Boy(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
十五,JDBC核心技术
1.概述
软件架构方式:
B/S:浏览器
C/S:客户端
数据的持久化
把数据保存到可掉电式存储设备中以供之后使用
JDBC的理解:
JDBC(Java Database Connectivity)是一个独立于特定数据库管理系统、通用的SQL数据库存取和操作的公共接口(一组API)
简单理解为:JDBC,是SUN提供的一套 API,使用这套API可以实现对具体数据库的操作(获取连接、关闭连接、DML、DDL、DCL)
图示理解:
2.获取连接
驱动和url
Driver driver=new com.mysql.jdbc.Driver();//MySQL具体driver的实现类
String url="jdbc:mysql://localhost:3306/test";
jdbc:mysql :协议
localhost :ip地址
3306 :端口号
test:数据库
方式一
@Test
public void test() throws SQLException {
Driver driver = new com.mysql.jdbc.Driver();
String url = "jdbc:mysql://localhost:3306/test";
Properties prop = new Properties();
prop.setProperty("user", "root");
prop.setProperty("password", "yhd666");
Connection connect = driver.connect(url, prop);
}
上述代码中显式出现了第三方数据库的API
方拾二
@Test//方式二:对方式一的迭代,不出现第方api,使程序具更好的可移植性
public void test2() throws Exception {
//1.利用反射获取Driver的具体实现类对象
Class clazz = Class.forName("com.mysql.jdbc.Driver");
Driver driver = (Driver) clazz.newInstance();
//2.提供要链接的数据库
String url = "jdbc:mysql://localhost:3306/test";
Properties prop = new Properties();//将用户名和密码封装在prop中。
prop.setProperty("user", "root");
prop.setProperty("password", "yhd666");
//3..获取连接
Connection connect = driver.connect(url, prop);
System.out.println(connect);
}
方式三
@Test //方式:使用DriverManager替换driver
public void test3() throws Exception {
//注册驱动
DriverManager.registerDriver((Driver) Class.forName("com.mysql.jdbc.Driver").newInstance());
//获取连接
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "yhd666");
System.out.println(connection);
}
使用DriverManager实现数据库的连接。体会获取连接必要的4个基本要素。
方式四
@Test
public void testConnection4() throws Exception {
//1.数据库连接的4个基本要素:
String url = "jdbc:mysql://localhost:3306/test";
String user = "root";
String password = "yhd666";
String driverName = "com.mysql.jdbc.Driver";
//2.加载驱动 (①实例化Driver ②注册驱动
Class.forName(driverName);
//Driver driver = (Driver) clazz.newInstance();
//3.注册驱动
//DriverManager.registerDriver(driver);
/*
可以注释掉上述代码的原因,是因为在mysql的Driver类中声明:
static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
*/
//3.获取连接
Connection conn = DriverManager.getConnection(url, user, password);
System.out.println(conn);
}
方式五
@Test//最终版,配置文件版
//1.实现了数据与代码的分离,解耦
//2.如果需要修改配置文件信息,就可以避免程序重新打包
public void test5() throws Exception {
InputStream is = Test1.class.getClassLoader().getResourceAsStream("jdbc.properties");
Properties prop = new Properties();
prop.load(is);
String user = prop.getProperty("user");
String password = prop.getProperty("password");
String url = prop.getProperty("url");
String driverClass = prop.getProperty("driverClass");
Class.forName(driverClass);
Connection connection = DriverManager.getConnection(url, user, password);
System.out.println(connection);
}
其中,配置文件声明在工程的src目录下:【jdbc.properties】
```properties
user=root
password=yhd666
url=jdbc:mysql://localhost:3306/test
driverClass=com.mysql.jdbc.Driver
3.PreparedStatement
Statement
数据库连接被用于向数据库服务器发送命令和 SQL 语句,并接受数据库服务器返回的结果。其实一个数据库连接就是一个Socket连接。
- 在 java.sql 包中有 3 个接口分别定义了对数据库的调用的不同方式:
- Statement:用于执行静态 SQL 语句并返回它所生成结果的对象。
- PrepatedStatement:SQL 语句被预编译并存储在此对象中,可以使用此对象多次高效地执行该语句。
- CallableStatement:用于执行 SQL 存储过程
使用Statement操作数据表的弊端
- 通过调用 Connection 对象的 createStatement() 方法创建该对象。该对象用于执行静态的 SQL 语句,并且返回执行结果。
- Statement 接口中定义了下列方法用于执行 SQL 语句:
```sql
int excuteUpdate(String sql):执行更新操作INSERT、UPDATE、DELETE
ResultSet executeQuery(String sql):执行查询操作SELECT
但是使用Statement操作数据表存在弊端:
- 问题一:存在拼串操作,繁琐
- 问题二:存在SQL注入问题 其他问题: Statement没办法操作Blob类型变量 Statement实现批量插入时,效率较低
SQL 注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的 SQL 语句段或命令(如:SELECT user, password FROM user_table WHERE user=’a’ OR 1 = ‘ AND password = ‘ OR ‘1’ = ‘1’) ,从而利用系统的 SQL 引擎完成恶意行为的做法。
对于 Java 而言,要防范 SQL 注入,只要用 PreparedStatement(从Statement扩展而来) 取代 Statement 就可以了。 ```
JDBCUtils封装获取连接和关闭资源
/**
* @author yinhuidong
* @createTime 2020-02-04-19:26
* JDBC工具类
*/
public class JDBCUtils {
//获取连接
public static Connection getConnection()throws Exception{
InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
Properties prop = new Properties();
prop.load(is);
String driverClass=prop.getProperty("driverClass");
String url=prop.getProperty("url");
String user = prop.getProperty("user");
String password = prop.getProperty("password");
Class.forName(driverClass);
Connection connection = DriverManager.getConnection(url, user, password);
return connection;
}
//关闭资源
public static void closeResource(Connection co, PreparedStatement ps, ResultSet rs){
try {
if (co!=null){
co.close();
}
if (ps!=null){
ps.close();
}
if (rs!=null){
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
增删改操作
添加操作
@Test//添加操作
public void add(){
Connection co=null;
PreparedStatement ps=null;
try {
co=JDBCUtils.getConnection();
String sql="insert into customers(name,email,birth) values(?,?,?);";
ps = co.prepareStatement(sql);
ps.setObject(1,"yinhuidong");
ps.setObject(2,"1972039773@qq.com");
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
java.util.Date date = format.parse("1998-11-16");
ps.setObject(3,new Date(date.getTime()));
ps.execute();
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(co,ps,null);
}
}
删除操作
@Test//删除操作
public void delete(){
Connection co=null;
PreparedStatement ps=null;
try {
co=JDBCUtils.getConnection();
String sql="delete from customers where id = ?;";
ps=co.prepareStatement(sql);
ps.setObject(1,20);
ps.execute();
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(co,ps,null);
}
}
修改操作:
@Test//修改
public void update(){
Connection co=null;
PreparedStatement ps=null;
try {
co=JDBCUtils.getConnection();
String sql="update customers set name=? where id =?;";
ps=co.prepareStatement(sql);
ps.setObject(1,"尹会东");
ps.setObject(2,1);
ps.execute();
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(co,ps,null);
}
}
通用增删改:
//通用增删改
public static void update(String sql,Object...args){
Connection conn=null;
PreparedStatement ps=null;
try {
conn=getConnection();
ps=conn.prepareStatement(sql);
for (int i = 0; i <args.length ; i++) {
ps.setObject(i+1,args[i]);
}
ps.execute();
} catch (Exception e) {
e.printStackTrace();
} finally {
closeResource(conn,ps,null);
}
}
通用查询操作
public static <T>List<T> find1(Class<T>clazz,String sql,Object...args) {
Connection co=null;
PreparedStatement ps=null;
ResultSet rs=null;
try {
co=getConnection();
ps=co.prepareStatement(sql);
for (int i = 0; i <args.length ; i++) {
ps.setObject(i+1,args[i]);
}
rs=ps.executeQuery();
ResultSetMetaData data = rs.getMetaData();//获取数据源
int count = data.getColumnCount();//获取一共有多少列
ArrayList<T> list = new ArrayList<>();
while (rs.next()){
T t = clazz.newInstance();
for (int i = 0; i <count ; i++) {
Object value=rs.getObject(i+1);
String name = data.getColumnLabel(i + 1);//获取别名,如果没别名就获取列名
Field field = clazz.getDeclaredField(name);
field.setAccessible(true);
field.set(t,value);
}
list.add(t);
}
return list;
} catch (Exception e) {
e.printStackTrace();
} finally {
closeResource(co,ps,rs);
}
return null;
}
表的列名和对象的属性名不一致的解决办法
Java与SQL对应数据类型转换表
| Java类型 | SQL类型 |
| ------------------ | ------------------------ |
| boolean | BIT |
| byte | TINYINT |
| short | SMALLINT |
| int | INTEGER |
| long | BIGINT |
| String | CHAR,VARCHAR,LONGVARCHAR |
| byte array | BINARY , VAR BINARY |
| java.sql.Date | DATE |
| java.sql.Time | TIME |
| java.sql.Timestamp | TIMESTAMP |
1. **如何获取 ResultSetMetaData**: 调用 ResultSet 的 getMetaData() 方法即可
2. **获取 ResultSet 中有多少列**:调用 ResultSetMetaData 的 getColumnCount() 方法
3. **获取 ResultSet 每一列的列的别名是什么**:调用 ResultSetMetaData 的getColumnLabel() 方法
JDBC API小结
- 两种思想
- 面向接口编程的思想
- ORM思想(object relational mapping)
- 一个数据表对应一个java类
- 表中的一条记录对应java类的一个对象
- 表中的一个字段对应java类的一个属性
> sql是需要结合列名和表的属性名来写。注意起别名。
- 两种技术
- JDBC结果集的元数据:ResultSetMetaData
- 获取列数:getColumnCount()
- 获取列的别名:getColumnLabel()
- 通过反射,创建指定类的对象,获取指定的属性并赋值
面试题:statement和preparedStatement的区别
操作Blob类型的变量
@Test//像数据表中插入一个图片
public void test(){
Connection co=null;
PreparedStatement ps=null;
try {
co=JDBCUtils.getConnection();
String sql="insert into customers(name,email,birth,photo)values(?,?,?,?);";
ps=co.prepareStatement(sql);
ps.setObject(1,"宋红康");
ps.setObject(2,"shk@126.com");
ps.setObject(3,"1988-11-13");
FileInputStream fis = new FileInputStream("D:\\copy1.jpg");
ps.setObject(4,fis);
ps.execute();
} catch (SQLException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(co,ps,null);
}
}
@Test//查询blob字段
public void test2(){
Connection co=null;
PreparedStatement ps=null;
ResultSet rs=null;
InputStream bs=null;
FileOutputStream fos=null;
try {
co=JDBCUtils.getConnection();
String sql="select * from customers where id=?;";
ps=co.prepareStatement(sql);
ps.setObject(1,22);
rs=ps.executeQuery();
while (rs.next()) {
Integer id = (Integer) rs.getObject(1);
String name = (String) rs.getObject(2);
String email = (String) rs.getObject(3);
Date birth = (Date) rs.getObject(4);
Customer customer = new Customer(id,name,email,birth);
System.out.println(customer);
Blob photo=rs.getBlob(5);
bs = photo.getBinaryStream();
fos = new FileOutputStream("2.jpg");
byte[]bytes=new byte[1024];
int len;
while ((len=bs.read(bytes))!=-1) {
fos.write(bytes,0,len);
}
}
} catch (SQLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(co,ps,rs);
try {
if (bs!=null){
bs.close();
}
if (fos!=null){
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
插入中遇到的问题:
批处理
@Test//像数据库一张表插入两万条数据
public void test() {
Connection conn = null;
PreparedStatement ps = null;
try {
conn = JDBCUtils.getConnection();
String sql = "insert into goods(name)values(?)";
ps = conn.prepareStatement(sql);
for (int i = 1; i <= 20000; i++) {
ps.setString(1, "name_" + i);
ps.executeUpdate();
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn, ps, null);
}
}
@Test//插入优化
public void test3(){
Connection conn = null;
PreparedStatement ps = null;
try {
conn = JDBCUtils.getConnection();
//设置不允许自动提交数据
conn.setAutoCommit(false);
String sql = "insert into goods(name)values(?)";
ps = conn.prepareStatement(sql);
for (int i = 0; i <=20000 ; i++) {
ps.setString(1, "name_" + i);
ps.addBatch();
if (i%500==0){
ps.executeBatch();
ps.clearBatch();
}
}
conn.commit();
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn,ps,null);
}
}
4.事务
1.事务:一组逻辑操作单元,使数据从一种状态变换到另一种状态。
* > 一组逻辑操作单元:一个或多个DML操作。
> 2.事务处理的原则:
> 保证所事务都作为一个工作单元来执行,即使出现了故障,都不能改变这种执行方式。
> 当在一个事务中执行多个操作时,要么所有的事务都被提交(commit),那么这些修改就永久地保存
> 下来;要么数据库管理系统将放弃所作的所有修改,整个事务回滚(rollback)到最初状态。
说明:
1.数据一旦提交,就不可回滚
* 2.哪些操作会导致数据的自动提交?
* >DDL操作一旦执行,都会自动提交。
* >set autocommit = false 对DDL操作失效
* >DML默认情况下,一旦执行,就会自动提交。
* >我们可以通过set autocommit = false的方式取消DML操作的自动提交。
* >默认在关闭连接时,会自动的提交数据
考虑事务以后的转账问题
@Test
public void test() {
Connection co = null;
try {
co = JDBCUtils.getConnection();
co.setAutoCommit(false);
String sql1 = "update user_table set balance=balance-? where user=?";
String sql2 = "update user_table set balance=balance+? where user=?";
update(co,sql1,100,"AA");
//System.out.println(10/0);
update(co,sql2,100,"BB");
co.commit();
System.out.println("转账成功!");
} catch (SQLException e) {
try {
co.rollback();
System.out.println("转账失败!");
} catch (SQLException e1) {
e1.printStackTrace();
}
} finally {
JDBCUtils.closeResource(co,null,null);
}
}
public static int update(Connection co, String sql, Object... args) {
PreparedStatement ps = null;
try {
ps = co.prepareStatement(sql);
for (int i = 0; i < args.length; i++) {
ps.setObject(i + 1, args[i]);
}
return ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(null, ps, null);
}
return 0;
}
事务的属性
ACID
数据操作过程中可能出现的问题:(针对隔离性)
数据库的四种隔离级别:(一致性和并发性:一致性越好,并发性越差)
如何查看并设置隔离级别:
5.连接池技术
传统连接存在的问题:
使用数据库连接池大的好处
1.提高程序的响应速度(减少了创建连接相应的时间)
2.降低资源的消耗(可以重复使用已经提供好的连接)
3.便于连接的管理
c3p0连接池
//使用c3p0数据库连接池的配置文件方式,获取数据库的连接:推荐
private static DataSource cpds = new ComboPooledDataSource("helloc3p0");
public static Connection getConnection() throws SQLException {
Connection conn = cpds.getConnection();
return conn;
}
c3p0-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<named-config name="helloc3p0">
<!-- 提供获取连接的4个基本信息 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql:///test</property>
<property name="user">root</property>
<property name="password">yhd666</property>
<!-- 进行数据库连接池管理的基本信息 -->
<!-- 当数据库连接池中的连接数不够时,c3p0一次性向数据库服务器申请的连接数 -->
<property name="acquireIncrement">5</property>
<!-- c3p0数据库连接池中初始化时的连接数 -->
<property name="initialPoolSize">10</property>
<!-- c3p0数据库连接池维护的最少连接数 -->
<property name="minPoolSize">10</property>
<!-- c3p0数据库连接池维护的最多的连接数 -->
<property name="maxPoolSize">100</property>
<!-- c3p0数据库连接池最多维护的Statement的个数 -->
<property name="maxStatements">50</property>
<!-- 每个连接中可以最多使用的Statement的个数 -->
<property name="maxStatementsPerConnection">2</property>
</named-config>
</c3p0-config>
dbcp连接池
//使用dbocp数据库连接池的配置文件方式,获取数据库的连接:推荐
private static DataSource source = null;
static{
try {
Properties pros = new Properties();
InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("dbcp.properties");
pros.load(is);
//根据提供的BasicDataSourceFactory创建对应的DataSource对象
source = BasicDataSourceFactory.createDataSource(pros);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection2() throws SQLException {
Connection conn = source.getConnection();
return conn;
}
dbcp.properties
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///test
username=root
password=yhd666
initialSize=10
druid连接池
//使用druid数据库连接池的配置文件方式,获取数据库的连接:推荐
private static DataSource ds = null;
static {
try {
Properties pro = new Properties();
// pro.load(PoolTest.class.getClassLoader().getResourceAsStream("druid.properties"));//加载配置文件
pro.load(ClassLoader.getSystemClassLoader().getResourceAsStream("druid.properties"));
ds = DruidDataSourceFactory.createDataSource(pro);//通过工厂创建数据源
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection3() {
return ds.getConnection();//通过数据源获取连接
}
druid.properties
url=jdbc:mysql://localhost:3306/test?rewriteBatchedStatements=true
username=root
password=yhd666
driverClassName=com.mysql.jdbc.Driver
#初始化时的连接数
initialSize=10
#最大连接池数量
maxActive=20
#获取连接时最大等待时间,单位毫秒。
maxWait=1000
#防御sql注入的filter:wall
filters=wall
#mysql下建议关闭
poolPreparedStatements=false
#建议配置为true,不影响性能,并且保证安全性。
testWhileIdle=true
6.DBUtils工具类
通用增删改
使用现成的jar中的QueryRunner测试增、删、改的操作:
//测试插入
@Test
public void testInsert() {
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
conn = JDBCUtils.getConnection3();
String sql = "insert into customers(name,email,birth)values(?,?,?)";
int insertCount = runner.update(conn, sql, "蔡徐坤","caixukun@126.com","1997-09-08");
System.out.println("添加了" + insertCount + "条记录");
} catch (SQLException e) {
e.printStackTrace();
}finally{
JDBCUtils.closeResource(conn, null);
}
}
查询操作1
使用现成的jar中的QueryRunner测试查询的操作:
//测试查询
/*
* BeanHander:是ResultSetHandler接口的实现类,用于封装表中的一条记录。
*/
@Test
public void testQuery1(){
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
conn = JDBCUtils.getConnection3();
String sql = "select id,name,email,birth from customers where id = ?";
BeanHandler<Customer> handler = new BeanHandler<>(Customer.class);
Customer customer = runner.query(conn, sql, handler, 23);
System.out.println(customer);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
JDBCUtils.closeResource(conn, null);
}
}
查询操作2
/*
* BeanListHandler:是ResultSetHandler接口的实现类,用于封装表中的多条记录构成的集合。
*/
@Test
public void testQuery2() {
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
conn = JDBCUtils.getConnection3();
String sql = "select id,name,email,birth from customers where id < ?";
BeanListHandler<Customer> handler = new BeanListHandler<>(Customer.class);
List<Customer> list = runner.query(conn, sql, handler, 23);
list.forEach(System.out::println);
} catch (SQLException e) {
e.printStackTrace();
}finally{
JDBCUtils.closeResource(conn, null);
}
}
查询操作3
/*
* MapHander:是ResultSetHandler接口的实现类,对应表中的一条记录。
* 将字段及相应字段的值作为map中的key和value
*/
@Test
public void testQuery3(){
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
conn = JDBCUtils.getConnection3();
String sql = "select id,name,email,birth from customers where id = ?";
MapHandler handler = new MapHandler();
Map<String, Object> map = runner.query(conn, sql, handler, 23);
System.out.println(map);
} catch (SQLException e) {
e.printStackTrace();
}finally{
JDBCUtils.closeResource(conn, null);
}
}
查询操作4
/*
* MapListHander:是ResultSetHandler接口的实现类,对应表中的多条记录。
* 将字段及相应字段的值作为map中的key和value。将这些map添加到List中
*/
@Test
public void testQuery4(){
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
conn = JDBCUtils.getConnection3();
String sql = "select id,name,email,birth from customers where id < ?";
MapListHandler handler = new MapListHandler();
List<Map<String, Object>> list = runner.query(conn, sql, handler, 23);
list.forEach(System.out::println);
} catch (SQLException e) {
e.printStackTrace();
}finally{
JDBCUtils.closeResource(conn, null);
}
}
查询操作5
/*
* ScalarHandler:用于查询特殊值
*/
@Test
public void testQuery5(){
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
conn = JDBCUtils.getConnection3();
String sql = "select count(*) from customers";
ScalarHandler handler = new ScalarHandler();
Long count = (Long) runner.query(conn, sql, handler);
System.out.println(count);
} catch (SQLException e) {
e.printStackTrace();
}finally{
JDBCUtils.closeResource(conn, null);
}
}
@Test
public void testQuery6(){
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
conn = JDBCUtils.getConnection3();
String sql = "select max(birth) from customers";
ScalarHandler handler = new ScalarHandler();
Date maxBirth = (Date) runner.query(conn, sql, handler);
System.out.println(maxBirth);
} catch (SQLException e) {
e.printStackTrace();
}finally{
JDBCUtils.closeResource(conn, null);
}
}
自定义ResultSetHandler的实现类
/*
* 自定义ResultSetHandler的实现类
*/
@Test
public void testQuery7(){
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
conn = JDBCUtils.getConnection3();
String sql = "select id,name,email,birth from customers where id = ?";
ResultSetHandler<Customer> handler = new ResultSetHandler<Customer>(){
@Override
public Customer handle(ResultSet rs) throws SQLException {
// System.out.println("handle");
// return null;
// return new Customer(12, "成龙", "Jacky@126.com", new Date(234324234324L));
if(rs.next()){
int id = rs.getInt("id");
String name = rs.getString("name");
String email = rs.getString("email");
Date birth = rs.getDate("birth");
Customer customer = new Customer(id, name, email, birth);
return customer;
}
return null;
}
};
Customer customer = runner.query(conn, sql, handler,23);
System.out.println(customer);
} catch (SQLException e) {
e.printStackTrace();
}finally{
JDBCUtils.closeResource(conn, null);
}
}
资源关闭
使用dbutils.jar包中的DbUtils工具类实现连接等资源的关闭:
/**
*
* @Description 使用dbutils.jar中提供的DbUtils工具类,实现资源的关闭
* @author shkstart
* @date 下午4:53:09
* @param conn
* @param ps
* @param rs
*/
public static void closeResource1(Connection conn,Statement ps,ResultSet rs){
DbUtils.closeQuietly(conn);
DbUtils.closeQuietly(ps);
DbUtils.closeQuietly(rs);
}
7.DAO设计模式
BaseDao类
package com.atguigu.utils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.*;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
/**
* @author yinhuidong
* @createTime 2020-02-12-21:07
*/
public class BaseDao<T> {
private Class<T> type;// 定义一个变量来接收泛型的类型
public BaseDao() {
//当子类调用父类方法时获取当前子类的父类类型
ParameterizedType parameterizedType = (ParameterizedType) this.getClass().getGenericSuperclass();
//获取具体的泛型的类型
Type[] types = parameterizedType.getActualTypeArguments();
this.type = (Class<T>) types[0];
}
private QueryRunner runner = new QueryRunner();
/**
* 考虑到事务以后的通用增删改
*/
public int update(Connection co, String sql, Object... args) throws SQLException {
return runner.update(co, sql, args);
}
/**
* 考虑到事务以后的通用查询一
*/
public <T> T select1(Connection co, String sql, Object... args) throws SQLException {
BeanHandler<T> handler = new BeanHandler<>((Class<T>) type);
return runner.query(co, sql, handler, args);
}
/**
* 考虑到事务以后的通用查询二
*/
public <T> List<T> select2(Connection co, String sql, Object... args) throws SQLException {
BeanListHandler<T> handler = new BeanListHandler<>((Class<T>) type);
return runner.query(co, sql, handler, args);
}
/**
* MapHandler
*/
public Map<String, Object> select3(Connection co, String sql, Object... args) throws SQLException {
MapHandler handler = new MapHandler();
return runner.query(co, sql, handler, args);
}
/**
* MapListHandler
*/
public List<Map<String, Object>> select4(Connection co, String sql, Object... args) throws SQLException {
MapListHandler handler = new MapListHandler();
return runner.query(co, sql, handler, args);
}
/**
* 利用ScalarHandler获取单一值
* 考虑事务问题
*/
public Object select5(Connection co, String sql, Object... args) throws SQLException {
ScalarHandler handler = new ScalarHandler();
return runner.query(co, sql, handler, args);
}
}
Dao接口
/**
* @author yinhuidong
* @createTime 2020-02-06-14:49
*/
public interface CustomerDao {
int add(Connection co,Object...args) throws SQLException;
int delete(Connection co,Object...args) throws SQLException;
int updates(Connection co,Object...args) throws SQLException;
Customer FindByValue(Connection co,Object...args) throws SQLException;
List<Customer> FindMore(Connection co, Object...args) throws SQLException;
Long count(Connection co,Object...args) throws SQLException;
}
DaoImpl实现类
/**
* @author yinhuidong
* @createTime 2020-02-06-14:56
*/
public class CustomerDaoImpl extends BaseDao<Customer> implements CustomerDao {
@Override
public int add(Connection co, Object... args) throws SQLException {
String sql="insert into customers (name,email,birth)values(?,?,?);";
return update(co,sql,args);
}
@Override
public int delete(Connection co, Object... args) throws SQLException {
String sql="delete from customers where id=?;";
return update(co,sql,args);
}
@Override
public int updates(Connection co, Object... args) throws SQLException {
String sql="update customers set name=?,email=?,birth=? where id=?;";
return update(co,sql,args);
}
@Override
public Customer FindByValue(Connection co, Object... args) throws SQLException {
String sql="select id,name,email,birth from customers where id=?;";
return selectById(co,sql,args);
}
@Override
public List<Customer> FindMore(Connection co, Object... args) throws SQLException {
String sql="select id,name,email,birth from customers ;";
return selectMore(co,sql,args);
}
@Override
public Long count(Connection co,Object...args) throws SQLException {
String sql="select count(*) from customers ;";
return (Long) selectOne(co,sql,args);
}
}
测试类
/**
* @author yinhuidong
* @createTime 2020-02-06-15:10
*/
public class TestDao {
private CustomerDao dao=new CustomerDaoImpl();
@Test
public void test(){
Connection co=null;
try {
co=JDBCUtils.getConnection();
co.setAutoCommit(false);
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Date date = format.parse("2017-02-21");
int add = dao.add(co, "name", "email", new java.sql.Date(date.getTime()));
co.commit();
if (add>0){
System.out.println("添加成功!");
}else{
System.out.println("添加失败!");
}
} catch (SQLException e) {
try {
co.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
} catch (ParseException e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(co);
}
}
@Test
public void test2(){
Connection co=null;
try {
co=JDBCUtils.getConnection();
co.setAutoCommit(false);
Customer customer = dao.FindByValue(co, 21);
co.commit();
System.out.println(customer);
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(co);
}
}
}
JDBCUtils工具类
package com.atguigu.java6;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.alibaba.druid.util.JdbcUtils;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
/**
* @author yinhuidong
* @createTime 2020-02-27-21:52
*/
public class JDBCUtils {
/**
* c3p0
*/
private static DataSource source1=new ComboPooledDataSource("helloc3p0");
public static Connection getConnection() throws SQLException {
return source1.getConnection();
}
/**
* dbcp
*/
private static DataSource source2=null;
static{
try {
InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("dbcp.properties");
Properties prop = new Properties();
prop.load(is);
source2=BasicDataSourceFactory.createDataSource(prop);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection2() throws SQLException {
return source2.getConnection();
}
private static DataSource source3=null;
static {
try {
Properties prop = new Properties();
InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties");
prop.load(is);
source3=DruidDataSourceFactory.createDataSource(prop);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection3() throws SQLException {
return source3.getConnection();
}
/**
* closeResource
*/
public static void closeResource(Connection co){
JdbcUtils.close(co);
}
}