JAVA-SE核心高级篇

    科技2023-10-04  86

    十一,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); } @Testmap(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); } }
    Processed: 0.015, SQL: 9