学习连接:Java 视频教程全集javascript
课件连接:Java课件html
声明:全是本人边学习边手打的,但愿对你们有帮助。前端
反射Reflection:把java类中的各类结构(方法、属性、构造器、类名)映射成一个个的java对象。利用反射技术能够对一个类进行解剖,反射是框架设计的灵魂。java
获取Class对象(三种方式):推荐使用Class.forName(“完整路径”)python
能够动态建立对象:clz.getConstructor().newInstance()mysql
练习git
package com.sxt.Server_study01; import java.lang.reflect.InvocationTargetException; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: ReflectTest.java * @time: 2019/11/29 14:55 * @desc: */ public class ReflectTest { public static void main(String[] args){ // 1. 对象.getClass() | 买iphone照着作 Iphone iphone = new Iphone(); Class clz = iphone.getClass(); // 2. 类.class() | 买通工程师给图纸 clz = Iphone.class; // 3. Class.forName("包名.类名") | 偷图纸 try { clz = Class.forName("com.sxt.Server_study01.Iphone"); } catch (ClassNotFoundException e) { e.printStackTrace(); } // 建立对象 try { Iphone iphone2 = (Iphone)clz.newInstance(); System.out.println(iphone2); } catch (InstantiationException | IllegalAccessException e) { e.printStackTrace(); } // 建立对象推荐方式 try { Iphone iphone3 = (Iphone)clz.getConstructor().newInstance(); System.out.println(iphone3); } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { e.printStackTrace(); } } } class Iphone{ public Iphone(){ } }
XML:Extensible Markup Language,可扩展标记语言,做为数据的一种存储格式或用于存储软件的参数,程序解析此配置文件,就能够达到不修改代码就能更改程序的目的。github
利用Sax解析XMLweb
xml例子正则表达式
<?xml version="1.0" encoding="UTF-8"?> <persons> <person> <name>至尊宝</name> <age>9000</age> </person> <person> <name>白晶晶</name> <age>7000</age> </person> </persons>
制做Person类
package com.sxt.Server_study01; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Person.java * @time: 2019/11/29 15:29 * @desc: */ public class Person { 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; } }
熟悉sax解析流程
package com.sxt.Server_study01; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import java.io.IOException; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: XmlTest01.java * @time: 2019/11/29 15:10 * @desc: 熟悉sax解析流程 */ public class XmlTest01 { public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException { // SAX解析 // 1. 获取解析工厂 SAXParserFactory factory = SAXParserFactory.newInstance(); // 2. 从解析工厂获取解析器 SAXParser parse = null; parse = factory.newSAXParser(); // 3. 加载文档Document注册处理器 // 4. 编写处理器 PHandler handler = new PHandler(); parse.parse(Thread.currentThread().getContextClassLoader().getResourceAsStream("com/sxt/Server_study01/p.xml"), handler); } } class PHandler extends DefaultHandler { @Override public void startDocument() throws SAXException { System.out.println("解析文档开始"); } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { System.out.println(qName + "-->解析开始"); } @Override public void characters(char[] ch, int start, int length) throws SAXException { String contents = new String(ch, start, length).trim(); if(contents.length()>0) { System.out.println("内容为:" + contents); }else{ System.out.println("内容为空!"); } } @Override public void endDocument() throws SAXException { System.out.println("解析文档结束"); } @Override public void endElement(String uri, String localName, String qName) throws SAXException { System.out.println(qName + "-->解析结束"); } }
获取xml中的内容
package com.sxt.Server_study01; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: XmlTest02.java * @time: 2019/11/29 15:31 * @desc: 获取xml中的内容 */ public class XmlTest02 { public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException { // SAX解析 // 1. 获取解析工厂 SAXParserFactory factory = SAXParserFactory.newInstance(); // 2. 从解析工厂获取解析器 SAXParser parse = null; parse = factory.newSAXParser(); // 3. 加载文档Document注册处理器 // 4. 编写处理器 PersonHandler handler = new PersonHandler(); parse.parse(Thread.currentThread().getContextClassLoader().getResourceAsStream("com/sxt/Server_study01/p.xml"), handler); // 5. 获取数据 List<Person> persons = handler.getPersons(); for (Person p : persons) { System.out.println(p.getName() + "-->" + p.getAge()); } } } class PersonHandler extends DefaultHandler { private List<Person> persons; private Person person; private String tag; // 存储操做的标签 @Override public void startDocument() throws SAXException { System.out.println("解析文档开始"); persons = new ArrayList<>(); } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if (null != qName) { tag = qName; // 存储标签名 if (tag.equals("person")) { person = new Person(); } } } @Override public void characters(char[] ch, int start, int length) throws SAXException { String contents = new String(ch, start, length).trim(); if (contents.length() > 0) { if (tag.equals("name")) { person.setName(contents); } else if (tag.equals("age")) { person.setAge(Integer.valueOf(contents)); } } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { if (qName.equals("person")) { persons.add(person); } } @Override public void endDocument() throws SAXException { System.out.println("解析文档结束"); } public List<Person> getPersons() { return persons; } }
webxml例子
<?xml version="1.0" encoding="UTF-8"?> <web-app> <servlet> <servlet-name>login</servlet-name> <servlet-class>com.sxt.server.basic.servlet.LoginServlet</servlet-class> </servlet> <servlet> <servlet-name>reg</servlet-name> <servlet-class>com.sxt.server.basic.servlet.RegisterServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>login</servlet-name> <url-pattern>/login</url-pattern> <url-pattern>/g</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>reg</servlet-name> <url-pattern>/reg</url-pattern> </servlet-mapping> </web-app>
解析webxml
package com.sxt.Server_study01.servlet; import com.sxt.Server_study01.Person; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: XmlTest02.java * @time: 2019/11/29 15:31 * @desc: 解析Webxml */ public class XmlTest02 { public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException { // SAX解析 // 1. 获取解析工厂 SAXParserFactory factory = SAXParserFactory.newInstance(); // 2. 从解析工厂获取解析器 SAXParser parse = null; parse = factory.newSAXParser(); // 3. 加载文档Document注册处理器 // 4. 编写处理器 WebHandler handler = new WebHandler(); parse.parse(Thread.currentThread().getContextClassLoader().getResourceAsStream("com/sxt/Server_study01/servlet/web.xml"), handler); // 5. 获取数据 List<Entity> entitys = handler.getEntitys(); List<Mapping> mappings = handler.getMappings(); System.out.println(entitys.size()); System.out.println(mappings.size()); } } class WebHandler extends DefaultHandler { private List<Entity> entitys; private List<Mapping> mappings; private Entity entity; private Mapping mapping; private String tag; private boolean isMapping = false; public List<Entity> getEntitys() { return entitys; } public void setEntitys(List<Entity> entitys) { this.entitys = entitys; } public List<Mapping> getMappings() { return mappings; } public void setMappings(List<Mapping> mappings) { this.mappings = mappings; } @Override public void startDocument() throws SAXException { entitys = new ArrayList<>(); mappings = new ArrayList<>(); } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if (null != qName) { tag = qName; // 存储标签名 if (tag.equals("servlet")) { entity = new Entity(); isMapping = false; } else if (tag.equals("servlet-mapping")) { mapping = new Mapping(); isMapping = true; } } } @Override public void characters(char[] ch, int start, int length) throws SAXException { String contents = new String(ch, start, length).trim(); if (contents.length() > 0) { if (isMapping) {// 操做servlet-mapping if (tag.equals("servlet-name")) { mapping.setName(contents); } else if (tag.equals("url-pattern")) { mapping.addPattern(contents); } } else {// 操做servlet if (tag.equals("servlet-name")) { entity.setName(contents); } else if (tag.equals("servlet-class")) { entity.setClz(contents); } } } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { if (qName.equals("servlet")) { entitys.add(entity); } else if (qName.equals("servlet-mapping")) { mappings.add(mapping); } } }
xml样例
<?xml version="1.0" encoding="UTF-8"?> <web-app> <servlet> <servlet-name>login</servlet-name> <servlet-class>com.sxt.Server_study01.servlet.LoginServlet</servlet-class> </servlet> <servlet> <servlet-name>reg</servlet-name> <servlet-class>com.sxt.Server_study01.servlet.RegisterServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>login</servlet-name> <url-pattern>/login</url-pattern> <url-pattern>/g</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>reg</servlet-name> <url-pattern>/reg</url-pattern> </servlet-mapping> </web-app>
解析xml
Entity类
package com.sxt.Server_study01.servlet; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Entity.java * @time: 2019/12/2 13:20 * @desc: */ public class Entity { private String name; private String clz; public Entity() { } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getClz() { return clz; } public void setClz(String clz) { this.clz = clz; } }
Mapping类
package com.sxt.Server_study01.servlet; import java.util.HashSet; import java.util.Set; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Mapping.java * @time: 2019/12/2 13:21 * @desc: */ public class Mapping { private String name; private Set<String> patterns; public Mapping() { patterns = new HashSet<>(); } public String getName() { return name; } public void setName(String name) { this.name = name; } public Set<String> getPatterns() { return patterns; } public void setPatterns(Set<String> patterns) { this.patterns = patterns; } public void addPattern(String pattern){ this.patterns.add(pattern); } }
经过URL的路径找到了对应的class
package com.sxt.Server_study01.servlet; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: WebContext.java * @time: 2019/12/3 10:51 * @desc: */ public class WebContext { private List<Entity> entitys = null; private List<Mapping> mappings = null; // key-->servlet-name value-->servlet-class private Map<String, String> mappingMap = new HashMap<>(); // key-->url-pattern value-->servlet-name private Map<String, String> entityMap = new HashMap<>(); public WebContext(List<Entity> entitys, List<Mapping> mappings) { this.entitys = entitys; this.mappings = mappings; // 将entity的List转成了对应的map for(Entity entity: entitys){ entityMap.put(entity.getName(), entity.getClz()); } // 将map的List转成了对应的map for(Mapping mapping: mappings){ for(String pattern: mapping.getPatterns()){ mappingMap.put(pattern, mapping.getName()); } } } // 经过URL的路径找到了对应的class public String getClz(String pattern) { String name = mappingMap.get(pattern); return entityMap.get(name); } }
核心代码,取出数据
package com.sxt.Server_study01.servlet; import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: XmlTest02.java * @time: 2019/11/29 15:31 * @desc: 解析Webxml */ public class XmlTest02 { public static void main(String[] args) throws Exception { // SAX解析 // 1. 获取解析工厂 SAXParserFactory factory = SAXParserFactory.newInstance(); // 2. 从解析工厂获取解析器 SAXParser parse = null; parse = factory.newSAXParser(); // 3. 加载文档Document注册处理器 // 4. 编写处理器 WebHandler handler = new WebHandler(); parse.parse(Thread.currentThread().getContextClassLoader().getResourceAsStream("com/sxt/Server_study01/servlet/web.xml"), handler); // 5. 获取数据 WebContext context = new WebContext(handler.getEntitys(), handler.getMappings()); // 假设你输入了 /login or /g String className = context.getClz("/g"); Class clz = Class.forName(className); Servlet servlet = (Servlet)clz.getConstructor().newInstance(); System.out.println(servlet); servlet.service(); } } class WebHandler extends DefaultHandler { private List<Entity> entitys; private List<Mapping> mappings; private Entity entity; private Mapping mapping; private String tag; private boolean isMapping = false; public List<Entity> getEntitys() { return entitys; } public void setEntitys(List<Entity> entitys) { this.entitys = entitys; } public List<Mapping> getMappings() { return mappings; } public void setMappings(List<Mapping> mappings) { this.mappings = mappings; } @Override public void startDocument() throws SAXException { entitys = new ArrayList<>(); mappings = new ArrayList<>(); } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if (null != qName) { tag = qName; // 存储标签名 if (tag.equals("servlet")) { entity = new Entity(); isMapping = false; } else if (tag.equals("servlet-mapping")) { mapping = new Mapping(); isMapping = true; } } } @Override public void characters(char[] ch, int start, int length) throws SAXException { String contents = new String(ch, start, length).trim(); if (contents.length() > 0) { if (isMapping) {// 操做servlet-mapping if (tag.equals("servlet-name")) { mapping.setName(contents); } else if (tag.equals("url-pattern")) { mapping.addPattern(contents); } } else {// 操做servlet if (tag.equals("servlet-name")) { entity.setName(contents); } else if (tag.equals("servlet-class")) { entity.setClz(contents); } } } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { if (qName.equals("servlet")) { entitys.add(entity); } else if (qName.equals("servlet-mapping")) { mappings.add(mapping); } } }
Servlet接口
package com.sxt.Server_study01.servlet; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Servlet.java * @time: 2019/12/3 15:59 * @desc: */ public interface Servlet { void service(); }
须要被映射的类:Loginservlet
package com.sxt.Server_study01.servlet; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: LoginServlet.java * @time: 2019/12/3 15:59 * @desc: */ public class LoginServlet implements Servlet { @Override public void service() { System.out.println("LoginServlet"); } }
须要被映射的类:RegisterServlet
package com.sxt.Server_study01.servlet; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: RegisterServlet.java * @time: 2019/12/3 15:59 * @desc: */ public class RegisterServlet implements Servlet{ @Override public void service() { System.out.println("RegisterServlet"); } }
HyperText Markup Language ,超文本标记语言,简单理解为浏览器使用的语言。
name是后端用的,id是前端用的
<html> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <head> <title>第一个html登录</title> </head> <body> <h1>表单的使用</h1> <pre> post: 提交,基于http协议不一样 量大 请求参数url不可见 安全<br/> get: 默认,获取,基于http协议不一样 量小 请求参数url可见 不安全<br/> action: 请求web服务器的资源 URL<br/> name: 做为后端使用,区分惟一,请求服务器,必须存在,数据不能提交<br/> id: 做为前端使用,区分惟一<br/> </pre> <form method="post" action="http://localhost:8888/index.html"> 用户名: <input type="text" name="uname" id="uname"/> 密码: <input type="password" name="pwd" id="pwd"/> <input type="submit" value="登录"/> </form> </body> </html>
http请求协议
http响应协议
使用ServerSocket创建与浏览器的链接,获取请求协议
package com.sxt.Server_study02; import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Server01.java * @time: 2019/12/4 9:26 * @desc: 使用ServerSocket创建与浏览器的链接,获取请求协议 */ public class Server01 { private ServerSocket serverSocket; public static void main(String[] args) { Server01 server = new Server01(); server.start(); } // 启动服务 public void start() { try { serverSocket = new ServerSocket(8888); receive(); } catch (IOException e) { e.printStackTrace(); System.out.println("服务器启动失败..."); } } // 接受链接处理 public void receive() { try { Socket client = serverSocket.accept(); System.out.println("一个客户端创建了链接..."); // 获取请求协议 InputStream is = client.getInputStream(); byte[] datas = new byte[1024*1024]; int len = is.read(datas); String requstInfo = new String(datas, 0, len); System.out.println(requstInfo); } catch (IOException e) { e.printStackTrace(); System.out.println("客户端错误..."); } } // 中止服务 public void stop() { } }
两种请求方法get和post:GET和POST两种基本请求方法的区别,GET 和 POST 到底有什么区别?
package com.sxt.Server_study02; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStreamWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.Date; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Server02.java * @time: 2019/12/4 9:26 * @desc: 返回响应协议 */ public class Server02 { private ServerSocket serverSocket; public static void main(String[] args) { Server02 server = new Server02(); server.start(); } // 启动服务 public void start() { try { serverSocket = new ServerSocket(8888); receive(); } catch (IOException e) { e.printStackTrace(); System.out.println("服务器启动失败..."); } } // 接受链接处理 public void receive() { try { Socket client = serverSocket.accept(); System.out.println("一个客户端创建了链接..."); // 获取请求协议 InputStream is = client.getInputStream(); byte[] datas = new byte[1024*1024]; int len = is.read(datas); String requstInfo = new String(datas, 0, len); System.out.println(requstInfo); StringBuilder content = new StringBuilder(); content.append("<html>"); content.append("<head>"); content.append("<title>"); content.append("服务器响应成功"); content.append("</title>"); content.append("</head>"); content.append("<body>"); content.append("终于回来了..."); content.append("</body>"); content.append("</html>"); int size = content.toString().getBytes().length; StringBuilder responseInfo = new StringBuilder(); String blank = " "; String CRLF = "\r\n"; // 返回 // 1. 响应行:HTTP/1.1 200 OK responseInfo.append("HTTP/1.1").append(blank); responseInfo.append(200).append(blank); responseInfo.append("OK").append(CRLF); // 2. 响应头(最后一行存在空行): responseInfo.append("Date:").append(new Date()).append(CRLF); responseInfo.append("Server:").append("shsxt Server/0.0.1;charset=GBK").append(CRLF); responseInfo.append("Content-type:text/html").append(CRLF); responseInfo.append("Content-length:").append(size).append(CRLF); responseInfo.append(CRLF); // 3. 正文 responseInfo.append(content.toString()); // 写出到客户端 BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream())); bw.write(responseInfo.toString()); bw.flush(); bw.close(); } catch (IOException e) { e.printStackTrace(); System.out.println("客户端错误..."); } } // 中止服务 public void stop() { } }
动态添加内容print
累加字节数的长度
根据状态码拼接响应头协议
根据状态码统一推送出去
package com.sxt.Server_study02; import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Server03.java * @time: 2019/12/4 9:26 * @desc: 封装响应信息 */ public class Server03 { private ServerSocket serverSocket; public static void main(String[] args) { Server03 server = new Server03(); server.start(); } // 启动服务 public void start() { try { serverSocket = new ServerSocket(8888); receive(); } catch (IOException e) { e.printStackTrace(); System.out.println("服务器启动失败..."); } } // 接受链接处理 public void receive() { try { Socket client = serverSocket.accept(); System.out.println("一个客户端创建了链接..."); // 获取请求协议 InputStream is = client.getInputStream(); byte[] datas = new byte[1024*1024]; int len = is.read(datas); String requstInfo = new String(datas, 0, len); System.out.println(requstInfo); Response response = new Response(client); // 关注了内容 response.print("<html>"); response.print("<head>"); response.print("<title>"); response.print("服务器响应成功"); response.print("</title>"); response.print("</head>"); response.print("<body>"); response.print("终于回来了..."); response.print("</body>"); response.print("</html>"); // 关注了状态码 response.pushToBrowser(200); } catch (IOException e) { e.printStackTrace(); System.out.println("客户端错误..."); } } // 中止服务 public void stop() { } }
package com.sxt.Server_study02; import java.io.BufferedWriter; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.net.Socket; import java.util.Date; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Response.java * @time: 2019/12/5 9:17 * @desc: */ public class Response { private BufferedWriter bw; // 正文 private StringBuilder content; // 协议头信息:状态行与请求头、回车 private StringBuilder headInfo; // 正文的字节数 private int len; private final String BLANK = " "; private final String CRLF = "\r\n"; public Response() { content = new StringBuilder(); headInfo = new StringBuilder(); len = 0; } public Response(Socket client) { this(); try { bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream())); } catch (IOException e) { e.printStackTrace(); headInfo = null; } } public Response(OutputStream os) { this(); bw = new BufferedWriter(new OutputStreamWriter(os)); } // 动态添加内容 public Response print(String info){ content.append(info); len += info.getBytes().length; return this; } public Response println(String info){ content.append(info).append(CRLF); len += (info + CRLF).getBytes().length; return this; } // 推送响应信息 public void pushToBrowser(int code) throws IOException { if (null == headInfo){ code = 505; } createHeadInfo(code); bw.append(headInfo); bw.append(content); bw.flush(); } // 构建头信息 private void createHeadInfo(int code) { // 1. 响应行:HTTP/1.1 200 OK headInfo.append("HTTP/1.1").append(BLANK); headInfo.append(code).append(BLANK); switch (code) { case 200: headInfo.append("OK").append(CRLF); break; case 404: headInfo.append("NOT FOUND").append(CRLF); break; case 505: headInfo.append("SERVER ERROR").append(CRLF); break; } // 2. 响应头(最后一行存在空行): headInfo.append("Date:").append(new Date()).append(CRLF); headInfo.append("Server:").append("shsxt Server/0.0.1;charset=GBK").append(CRLF); headInfo.append("Content-type:text/html").append(CRLF); headInfo.append("Content-length:").append(len).append(CRLF); headInfo.append(CRLF); } }
经过分解字符串获取method、URL和请求参数
POST请求参数可能在请求体中存在
分解协议
package com.sxt.Server_study02; import java.io.IOException; import java.io.InputStream; import java.net.Socket; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Request.java * @time: 2019/12/5 10:15 * @desc: */ public class Request { private String requestInfo; // 请求方式 private String method; // 请求url private String url; // 请求参数 private String queryStr; private final String BLANK = " "; private final String CRLF = "\r\n"; public Request(Socket client) throws IOException { this(client.getInputStream()); } public Request(InputStream is) { byte[] datas = new byte[1024 * 1024]; int len; try { len = is.read(datas); this.requestInfo = new String(datas, 0, len); } catch (IOException e) { e.printStackTrace(); return; } // 分解字符串 parseRequestInfo(); } private void parseRequestInfo() { System.out.println("---分解---"); System.out.println("1. 获取请求方式:开头到第一个/"); this.method = this.requestInfo.substring(0, this.requestInfo.indexOf("/")).toLowerCase().trim(); System.out.println("2. 获取请求url:第一个/ 到HTTP/"); System.out.println("可能包含请求参数?前面的url"); // 1. 获取/的位置 int startIdx = this.requestInfo.indexOf("/") + 1; // 2. 获取HTTP/的位置 int endIdx = this.requestInfo.indexOf("HTTP/"); // 3. 分割字符串 this.url = this.requestInfo.substring(startIdx, endIdx); // 4. 获取?的位置 int queryIdx = this.url.indexOf("?"); if (queryIdx >= 0) { // 表示存在请求参数 String[] urlArray = this.url.split("\\?"); this.url = urlArray[0].trim(); queryStr = urlArray[1].trim(); } System.out.println(this.url); System.out.println("3. 获取请求参数:若果Get已经获取,若是post可能在请求体中"); if (method.equals("post")) { String qStr = this.requestInfo.substring(this.requestInfo.lastIndexOf(CRLF)).trim(); if (null == queryStr) { queryStr = qStr; } else { queryStr += "&" + qStr; } } queryStr = null == queryStr?"": queryStr; System.out.println(method + "-->" + url + "-->" + queryStr); } }
package com.sxt.Server_study02; import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Server04.java * @time: 2019/12/4 9:26 * @desc: 封装请求协议:获取method uri以及请求参数 */ public class Server04 { private ServerSocket serverSocket; public static void main(String[] args) { Server04 server = new Server04(); server.start(); } // 启动服务 public void start() { try { serverSocket = new ServerSocket(8888); receive(); } catch (IOException e) { e.printStackTrace(); System.out.println("服务器启动失败..."); } } // 接受链接处理 public void receive() { try { Socket client = serverSocket.accept(); System.out.println("一个客户端创建了链接..."); // 获取请求协议 Request request = new Request(client); Response response = new Response(client); // 关注了内容 response.print("<html>"); response.print("<head>"); response.print("<title>"); response.print("服务器响应成功"); response.print("</title>"); response.print("</head>"); response.print("<body>"); response.print("终于回来了..."); response.print("</body>"); response.print("</html>"); // 关注了状态码 response.pushToBrowser(200); } catch (IOException e) { e.printStackTrace(); System.out.println("客户端错误..."); } } // 中止服务 public void stop() { } }
分解参数
package com.sxt.Server_study02; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.Socket; import java.util.*; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Request2.java * @time: 2019/12/5 10:15 * @desc: 封装请求协议:封装请求参数为Map */ public class Request2 { private String requestInfo; // 请求方式 private String method; // 请求url private String url; // 请求参数 private String queryStr; // 存储参数 private Map<String, List<String>> parameterMap; private final String BLANK = " "; private final String CRLF = "\r\n"; public Request2(Socket client) throws IOException { this(client.getInputStream()); } public String getMethod() { return method; } public String getUrl() { return url; } public String getQueryStr() { return queryStr; } public Request2(InputStream is) { parameterMap = new HashMap<>(); byte[] datas = new byte[1024 * 1024]; int len; try { len = is.read(datas); this.requestInfo = new String(datas, 0, len); } catch (IOException e) { e.printStackTrace(); return; } // 分解字符串 parseRequestInfo(); } private void parseRequestInfo() { System.out.println("---分解---"); System.out.println("1. 获取请求方式:开头到第一个/"); this.method = this.requestInfo.substring(0, this.requestInfo.indexOf("/")).toLowerCase().trim(); System.out.println("2. 获取请求url:第一个/ 到HTTP/"); System.out.println("可能包含请求参数?前面的url"); // 1. 获取/的位置 int startIdx = this.requestInfo.indexOf("/") + 1; // 2. 获取HTTP/的位置 int endIdx = this.requestInfo.indexOf("HTTP/"); // 3. 分割字符串 this.url = this.requestInfo.substring(startIdx, endIdx); // 4. 获取?的位置 int queryIdx = this.url.indexOf("?"); if (queryIdx >= 0) { // 表示存在请求参数 String[] urlArray = this.url.split("\\?"); this.url = urlArray[0].trim(); queryStr = urlArray[1].trim(); } System.out.println(this.url); System.out.println("3. 获取请求参数:若果Get已经获取,若是post可能在请求体中"); if (method.equals("post")) { String qStr = this.requestInfo.substring(this.requestInfo.lastIndexOf(CRLF)).trim(); if (null == queryStr) { queryStr = qStr; } else { queryStr += "&" + qStr; } } queryStr = null == queryStr?"": queryStr; System.out.println(method + "-->" + url + "-->" + queryStr); // 转成Map fav=1&fav=2&uname=shsxt&age=18&other= convertMap(); } // 处理请求参数为Map private void convertMap(){ // 分割字符串 & String[] keyValues = this.queryStr.split("&"); for(String queryStr: keyValues){ // 再次分割字符串 = String[] kv = queryStr.split("="); // 保持两个长度 key 和 value kv = Arrays.copyOf(kv, 2); // 获取key 和 value String key = kv[0]; String value = kv[1]==null? null: decode(kv[1], "utf-8"); // 存储在Map中 if(!parameterMap.containsKey(key)){ // 容器里面没有,第一次 parameterMap.put(key, new ArrayList<String>()); } parameterMap.get(key).add(value); } } // 处理中文 private String decode(String value, String enc){ try { return java.net.URLDecoder.decode(value, enc); } catch (UnsupportedEncodingException e) { e.printStackTrace(); return null; } } // 经过name获取对应的多个值 public String[] getParameterValues(String key){ List<String> values = this.parameterMap.get(key); if(null == values || values.size()<1){ return null; } return values.toArray(new String[0]); } // 经过name获取对应的一个值 public String getParameter(String key){ String[] values = getParameterValues(key); return values == null?null: values[0]; } }
package com.sxt.Server_study02; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Server05.java * @time: 2019/12/4 9:26 * @desc: 封装请求信息中参数转成map */ public class Server05 { private ServerSocket serverSocket; public static void main(String[] args) { Server05 server = new Server05(); server.start(); } // 启动服务 public void start() { try { serverSocket = new ServerSocket(8888); receive(); } catch (IOException e) { e.printStackTrace(); System.out.println("服务器启动失败..."); } } // 接受链接处理 public void receive() { try { Socket client = serverSocket.accept(); System.out.println("一个客户端创建了链接..."); // 获取请求协议 Request2 request = new Request2(client); Response response = new Response(client); // 关注了内容 response.print("<html>"); response.print("<head>"); response.print("<title>"); response.print("服务器响应成功"); response.print("</title>"); response.print("</head>"); response.print("<body>"); response.print("终于回来了..." + request.getParameter("uname")); response.print("</body>"); response.print("</html>"); // 关注了状态码 response.pushToBrowser(200); } catch (IOException e) { e.printStackTrace(); System.out.println("客户端错误..."); } } // 中止服务 public void stop() { } }
加入了Servlet解耦了业务代码
package com.sxt.Server_study03; import com.sxt.tcp.Server; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Server06.java * @time: 2019/12/4 9:26 * @desc: 加入了Servlet解耦了业务代码 */ public class Server06 { private ServerSocket serverSocket; public static void main(String[] args) { Server06 server = new Server06(); server.start(); } // 启动服务 public void start() { try { serverSocket = new ServerSocket(8888); receive(); } catch (IOException e) { e.printStackTrace(); System.out.println("服务器启动失败..."); } } // 接受链接处理 public void receive() { try { Socket client = serverSocket.accept(); System.out.println("一个客户端创建了链接..."); // 获取请求协议 Request request = new Request(client); Response response = new Response(client); // 关注了内容 Servlet servlet = null; if(request.getUrl().equals("login")){ servlet = new LoginServlet(); }else if (request.getUrl().equals("reg")){ servlet = new RegisterServlet(); }else { // 首页 } servlet.service(request, response); // 关注了状态码 response.pushToBrowser(200); } catch (IOException e) { e.printStackTrace(); System.out.println("客户端错误..."); } } // 中止服务 public void stop() { } }
Request和Response同上
Servlet
package com.sxt.Server_study03; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Servlet.java * @time: 2019/12/9 12:03 * @desc: 服务器小脚本接口 */ public interface Servlet { void service(Request request, Response response); }
RegisterServlet
package com.sxt.Server_study03; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: RegisterServlet.java * @time: 2019/12/3 15:59 * @desc: */ public class RegisterServlet implements Servlet{ @Override public void service(Request request, Response response){ response.print("注册成功..."); } }
LoginServlet
package com.sxt.Server_study03; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: LoginServlet.java * @time: 2019/12/3 15:59 * @desc: */ public class LoginServlet implements Servlet { @Override public void service(Request request, Response response) { response.print("<html>"); response.print("<head>"); response.print("<title>"); response.print("第一个servlet"); response.print("</title>"); response.print("</head>"); response.print("<body>"); response.print("欢迎回来..." + request.getParameter("uname")); response.print("</body>"); response.print("</html>"); } }
将以前的Mapping,Entity,WebContext,WebHandler拷贝到工程中
解析web.xml代码
package com.sxt.Server_study03; import com.sxt.Server_study01.servlet.WebContext; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: WebApp.java * @time: 2019/12/9 12:37 * @desc: 解析代码 */ public class WebApp { private static WebContext context; static { try { // SAX解析 // 1. 获取解析工厂 SAXParserFactory factory = SAXParserFactory.newInstance(); // 2. 从解析工厂获取解析器 SAXParser parse = null; parse = factory.newSAXParser(); // 3. 加载文档Document注册处理器 // 4. 编写处理器 WebHandler handler = new WebHandler(); parse.parse(Thread.currentThread().getContextClassLoader().getResourceAsStream("web.xml"), handler); // 5. 获取数据 context = new WebContext(handler.getEntitys(), handler.getMappings()); } catch (Exception e) { System.out.println("解析配置文件错误!"); } } // 经过url获取配置文件对应的servlet public static Servlet getServletFromUrl(String url) { // 假设你输入了 /login or /g or /reg String className = context.getClz("/" + url); Class clz = null; try { clz = Class.forName(className); Servlet servlet = (Servlet) clz.getConstructor().newInstance(); return servlet; } catch (Exception e) { e.printStackTrace(); } return null; } }
新增OthersServlet
package com.sxt.Server_study03; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: OthersServlet.java * @time: 2019/12/9 13:17 * @desc: 其余测试页面 */ public class OthersServlet implements Servlet{ @Override public void service(Request request, Response response) { response.print("其余测试页面..."); } }
修改xml
<?xml version="1.0" encoding="UTF-8"?> <web-app> <servlet> <servlet-name>login</servlet-name> <servlet-class>com.sxt.Server_study03.LoginServlet</servlet-class> </servlet> <servlet> <servlet-name>reg</servlet-name> <servlet-class>com.sxt.Server_study03.RegisterServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>login</servlet-name> <url-pattern>/login</url-pattern> <url-pattern>/g</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>reg</servlet-name> <url-pattern>/reg</url-pattern> </servlet-mapping> <servlet> <servlet-name>others</servlet-name> <servlet-class>com.sxt.Server_study03.OthersServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>others</servlet-name> <url-pattern>/o</url-pattern> </servlet-mapping> </web-app>
整合配置文件
package com.sxt.Server_study03; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Server06.java * @time: 2019/12/4 9:26 * @desc: 整合配置文件 */ public class Server07 { private ServerSocket serverSocket; public static void main(String[] args) { Server07 server = new Server07(); server.start(); } // 启动服务 public void start() { try { serverSocket = new ServerSocket(8888); receive(); } catch (IOException e) { e.printStackTrace(); System.out.println("服务器启动失败..."); } } // 接受链接处理 public void receive() { try { Socket client = serverSocket.accept(); System.out.println("一个客户端创建了链接..."); // 获取请求协议 Request request = new Request(client); Response response = new Response(client); Servlet servlet = WebApp.getServletFromUrl(request.getUrl()); if(null != servlet){ servlet.service(request, response); // 关注了状态码 response.pushToBrowser(200); }else { // 错误页面... response.pushToBrowser(404); } } catch (IOException e) { e.printStackTrace(); System.out.println("客户端错误..."); } } // 中止服务 public void stop() { } }
多线程处理,加入分发器
package com.sxt.Server_study03; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Server08.java * @time: 2019/12/4 9:26 * @desc: 多线程处理,加入分发器 */ public class Server08 { private ServerSocket serverSocket; private boolean isRunning; public static void main(String[] args) { Server08 server = new Server08(); server.start(); } // 启动服务 public void start() { try { serverSocket = new ServerSocket(8888); isRunning = true; receive(); } catch (IOException e) { e.printStackTrace(); System.out.println("服务器启动失败..."); stop(); } } // 接受链接处理 public void receive() { while (isRunning) { try { Socket client = serverSocket.accept(); System.out.println("一个客户端创建了链接..."); // 多线程处理 new Thread(new Dispatcher(client)).start(); } catch (IOException e) { e.printStackTrace(); System.out.println("客户端错误..."); } } } // 中止服务 public void stop() { isRunning = false; try { this.serverSocket.close(); System.out.println("服务器已中止..."); } catch (IOException e) { e.printStackTrace(); } } }
分发器
package com.sxt.Server_study03; import java.io.IOException; import java.net.Socket; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Dispatcher.java * @time: 2019/12/12 16:36 * @desc: 分发器 */ public class Dispatcher implements Runnable { private Socket client; private Request request; private Response response; public Dispatcher(Socket client) { this.client = client; try { // 获取请求和响应 request = new Request(client); response = new Response(client); } catch (IOException e) { e.printStackTrace(); this.release(); } } @Override public void run() { try { Servlet servlet = WebApp.getServletFromUrl(request.getUrl()); if (null != servlet) { servlet.service(request, response); // 关注了状态码 response.pushToBrowser(200); } else { // 错误页面... response.pushToBrowser(404); } }catch (Exception e){ try { response.pushToBrowser(500); } catch (IOException ex) { ex.printStackTrace(); } } release(); } // 释放资源 private void release() { try { client.close(); } catch (IOException ex) { ex.printStackTrace(); } } }
这一部分有问题is.readAllBytes()这里报错,而且也没有找到解决办法
分发器
package com.sxt.Server_study03; import java.io.IOException; import java.io.InputStream; import java.net.Socket; import java.nio.file.Files; import java.nio.file.Paths; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Dispatcher.java * @time: 2019/12/12 16:36 * @desc: 分发器 */ public class Dispatcher implements Runnable { private Socket client; private Request request; private Response response; public Dispatcher(Socket client) { this.client = client; try { // 获取请求和响应 request = new Request(client); response = new Response(client); } catch (IOException e) { e.printStackTrace(); this.release(); } } @Override public void run() { try { if (null == request.getUrl() || request.getUrl().equals("")) { InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("index.html"); response.print(new String(is.readAllBytes())); response.println(new String(Files.readAllBytes(Paths.get("index.html")))); response.pushToBrowser(200); is.close(); return; } Servlet servlet = WebApp.getServletFromUrl(request.getUrl()); if (null != servlet) { servlet.service(request, response); // 关注了状态码 response.pushToBrowser(200); } else { InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("error.html"); response.print(new String(is.readAllBytes())); response.pushToBrowser(404); is.close(); } } catch (Exception e) { try { response.print("你好我很差,我会立刻好"); response.pushToBrowser(500); } catch (IOException ex) { ex.printStackTrace(); } } release(); } // 释放资源 private void release() { try { client.close(); } catch (IOException ex) { ex.printStackTrace(); } } }
处理404/505和首页
package com.sxt.Server_study03; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Server08.java * @time: 2019/12/4 9:26 * @desc: 处理404/505和首页 */ public class Server09 { private ServerSocket serverSocket; private boolean isRunning; public static void main(String[] args) { Server09 server = new Server09(); server.start(); } // 启动服务 public void start() { try { serverSocket = new ServerSocket(8888); isRunning = true; receive(); } catch (IOException e) { e.printStackTrace(); System.out.println("服务器启动失败..."); stop(); } } // 接受链接处理 public void receive() { while (isRunning) { try { Socket client = serverSocket.accept(); System.out.println("一个客户端创建了链接..."); // 多线程处理 new Thread(new Dispatcher(client)).start(); } catch (IOException e) { e.printStackTrace(); System.out.println("客户端错误..."); } } } // 中止服务 public void stop() { isRunning = false; try { this.serverSocket.close(); System.out.println("服务器已中止..."); } catch (IOException e) { e.printStackTrace(); } } }
Annotation
做用
格式
package com.sxt.test.annotation; import java.util.ArrayList; import java.util.Date; import java.util.List; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Demo01.java * @time: 2019/12/16 9:34 * @desc: */ public class Demo01 { @Override // 重写父类方法 public String toString() { return ""; } @Deprecated // 该方法不建议使用 public static void test1() { System.out.println("你大爷"); } @SuppressWarnings("all") // 不显示全部警告信息 public static void test2() { List list = new ArrayList(); } @SuppressWarnings(value = {"unchecked", "deprecation"}) // 不显示某几个警告信息 public static void main(String[] args) { test1(); } }
ORM:Object Relationship Mapping,对象关系映射
使用注解完成类和表结构的映射关系
类注解
package com.sxt.test.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: LTTable.java * @time: 2019/12/16 12:44 * @desc: */ @Target(value = {ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface LTTable { String value(); }
属性注解
package com.sxt.test.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: LTField.java * @time: 2019/12/16 12:46 * @desc: 说明属性的特征 */ @Target(value = {ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface LTField { String columnName(); String type(); int length(); }
学生类
package com.sxt.test.annotation; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Student.java * @time: 2019/12/16 12:43 * @desc: */ @LTTable("tb_student") public class Student { @LTField(columnName = "id", type = "int", length = 10) private int id; @LTField(columnName = "sname", type = "varchar", length = 10) private String studentName; @LTField(columnName = "age", type = "int", length = 3) private int age; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getStudentName() { return studentName; } public void setStudentName(String studentName) { this.studentName = studentName; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
使用反射读取注解的信息,模拟处理注解信息的流程
package com.sxt.test.annotation; import java.lang.annotation.Annotation; import java.lang.reflect.Field; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Demo03.java * @time: 2019/12/16 12:49 * @desc: 使用反射读取注解的信息,模拟处理注解信息的流程 */ public class Demo03 { public static void main(String[] args) { try { Class clazz = Class.forName("com.sxt.test.annotation.Student"); // 得到类的全部有效注解 Annotation[] annotations = clazz.getAnnotations(); for (Annotation a : annotations) { System.out.println(a); } // 得到类的指定的注解 LTTable st = (LTTable) clazz.getAnnotation(LTTable.class); System.out.println(st.value()); // 得到类的属性的注解 Field f = clazz.getDeclaredField("studentName"); LTField ltField = f.getAnnotation(LTField.class); System.out.println(ltField.columnName()+"-->"+ltField.type()+"-->"+ltField.length()); // 根据得到的代表、字段的信息,拼出DDL语句,而后使用JDBC执行这个SQL,在数据库中生成相关的表 } catch (Exception e) { e.printStackTrace(); } } }
介绍+Class对象获取
动态语言:程序运行时,能够改变程序结构或变态类型。(如python、javascript)
Java不是动态语言,但能够称为“准动态语言”。Java有必定的动态性,咱们能够利用反射机制、字节码操做得到相似动态语言的特性。
反射机制
测试各类类型对应的java.lang.Class对象的获取方式
package com.sxt.test.reflection; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Demo01.java * @time: 2019/12/17 18:59 * @desc: 测试各类类型对应的java.lang.Class对象的获取方式 */ public class Demo01 { public static void main(String[] args) { String path = "com.sxt.test.bean.User"; try { Class clazz = Class.forName(path); // 对象是表示或封装一些数据。一个类被加载后,JVM会建立一个对应该类的Class对象, // 类的整个结构信息会放到对应的Class对象中。这个Class对象就像一面镜子同样, // 经过这面镜子咱们能够看到对应类的所有信息。 System.out.println(clazz); System.out.println(clazz.hashCode()); // 一个类只对应一个Class对象 Class clazz2 = Class.forName(path); System.out.println(clazz2.hashCode()); Class strClazz = String.class; Class strClazz2 = path.getClass(); // 得到的都是String的Class对象 System.out.println(strClazz==strClazz2); Class intClazz = int.class; System.out.println(intClazz.hashCode()); // 数组跟维度、类型都有关 int[] arr01 = new int[10]; int[] arr02 = new int[30]; int[][] arr03 = new int[10][10]; double[] arr04 = new double[10]; System.out.println(arr01.getClass().hashCode() == arr02.getClass().hashCode()); System.out.println(arr01.getClass().hashCode() == arr03.getClass().hashCode()); System.out.println(arr01.getClass().hashCode() == arr04.getClass().hashCode()); } catch (Exception e) { e.printStackTrace(); } } }
动态操做+构造器+方法+属性
应用反射的API获取类的信息(类的名字、属性、方法、构造器等)
package com.sxt.test.reflection; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Demo02.java * @time: 2020/1/7 14:33 * @desc: 应用反射的API获取类的信息(类的名字、属性、方法、构造器等) */ public class Demo02 { public static void main(String[] args) { String path = "com.sxt.test.bean.User"; try { Class clazz = Class.forName(path); // 获取类的全名 System.out.println(clazz.getName()); // 获取类的包名+全名 System.out.println(clazz.getSimpleName()); // 获取属性信息 // 只能得到public的field // Field[] fields = clazz.getFields(); // 返回全部的field Field[] fields = clazz.getDeclaredFields(); System.out.println(fields.length); for(Field temp: fields){ System.out.println("属性:" + temp); } // 经过名称获取属性 Field f = clazz.getDeclaredField("uname"); System.out.println(f); // 获取方法信息 Method[] methods = clazz.getDeclaredMethods(); Method m1 = clazz.getDeclaredMethod("getUname"); Method m2 = clazz.getDeclaredMethod("setUname", String.class); for(Method temp: methods){ System.out.println("方法:" + temp); } // 获取构造器信息 Constructor[] constructors = clazz.getDeclaredConstructors(); for(Constructor temp: constructors){ System.out.println("构造器:" + temp); } // 获取某个特定的构造器 Constructor c1 = clazz.getDeclaredConstructor(); System.out.println("无参构造器:" + c1); Constructor c2 = clazz.getDeclaredConstructor(int.class, int.class, String.class); System.out.println("有参构造器:" + c2); } catch (Exception e) { e.printStackTrace(); } } }
经过反射API动态的操做:构造器、方法、属性
package com.sxt.test.reflection; import com.sxt.test.bean.User; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Demo3.java * @time: 2020/1/8 17:03 * @desc: 经过反射API动态的操做:构造器、方法、属性 */ public class Demo3 { public static void main(String[] args) { String path = "com.sxt.test.bean.User"; try { Class<User> clazz = (Class<User>) Class.forName(path); // 经过反射API调用构造方法,构造对象 // 实际上是调用了User的无参构造方法 User u = clazz.newInstance(); System.out.println(u); // 指定构造器的调用 Constructor<User> c = clazz.getDeclaredConstructor(int.class, int.class, String.class); User u2 = c.newInstance(1001, 18, "李英俊"); System.out.println(u2.getUname()); // 经过反射API调用普通方法 User u3 = clazz.newInstance(); u3.setUname("李不羁"); // 上一句用反射来写以下 Method method = clazz.getDeclaredMethod("setUname", String.class); method.invoke(u3, "李不羁"); System.out.println(u3.getUname()); // 经过反射API操做属性 User u4 = clazz.newInstance(); Field f = clazz.getDeclaredField("uname"); // 这个属性不须要作安全检查了,能够直接访问 f.setAccessible(true); // 经过反射直接写属性 f.set(u4, "李傻瓜"); System.out.println(u4.getUname()); // 经过反射直接读属性的值 System.out.println(f.get(u4)); } catch (Exception e) { e.printStackTrace(); } } }
提升反射效率+操做泛型+操做注解
setAccessible
反射操做泛型(Generic)
操做泛型
package com.sxt.test.reflection; import com.sxt.test.bean.User; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.List; import java.util.Map; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Demo4.java * @time: 2020/1/9 10:44 * @desc: 操做泛型 */ public class Demo4 { public void test01(Map<String, User> map, List<User> list){ System.out.println("Demo04.test01()"); } public Map<Integer, User> test02(){ System.out.println("Demo04.test02()"); return null; } public static void main(String[] args){ try{ // 得到指定方法参数泛型信息 Method m = Demo4.class.getMethod("test01", Map.class, List.class); Type[] t = m.getGenericParameterTypes(); for (Type paramType: t){ System.out.println("#" + paramType); if(paramType instanceof ParameterizedType){ Type[] genericTypes = ((ParameterizedType) paramType).getActualTypeArguments(); for (Type genericType: genericTypes){ System.out.println("泛型类型:" + genericType); } } } // 得到指定方法返回值泛型信息 Method m2 = Demo4.class.getMethod("test02"); Type returnType = m2.getGenericReturnType(); if(returnType instanceof ParameterizedType){ Type[] genericTypes = ((ParameterizedType) returnType).getActualTypeArguments(); for (Type genericType: genericTypes){ System.out.println("返回值,泛型类型:" + genericType); } } } catch (NoSuchMethodException e) { e.printStackTrace(); } } }
操做注解
package com.sxt.test.annotation; import java.lang.annotation.Annotation; import java.lang.reflect.Field; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Demo5.java * @time: 2020/1/9 10:57 * @desc: 操做注解 */ public class Demo5 { public static void main(String[] args) { try { Class clazz = Class.forName("com.sxt.test.annotation.Student"); // 得到类的全部有效注解 Annotation[] annotations = clazz.getAnnotations(); for (Annotation a : annotations) { System.out.println(a); } // 得到类指定的注解 LTTable st = (LTTable) clazz.getAnnotation(LTTable.class); System.out.println(st.value()); // 得到类的属性的注解 Field f = clazz.getDeclaredField("studentName"); LTField ltField = f.getAnnotation(LTField.class); System.out.println(ltField.columnName() + "--" + ltField.type() + "--" + ltField.length()); // 根据得到的表名、字段的信息,拼出DDL语句,而后,使用JDBC执行这个SQL,在数据库中生成相关的表 } catch (Exception e) { e.printStackTrace(); } } }
经过JavaCompiler动态编译
public static int compileFile(String sourceFile){ // 动态编译 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); int result = compiler.run(null, null, null, sourceFile); System.out.println(result==0?"编译成功": "编译失败"); return result; }
package com.sxt.test.testDynamicCompile; import javax.tools.JavaCompiler; import javax.tools.ToolProvider; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Demo1.java * @time: 2020/1/9 14:38 * @desc: 动态编译 */ public class Demo1 { public static void main(String[] args) throws IOException { // 若是是给的字符串的话,能够 // 经过IO流操做,将字符串存储成一个临时文件,而后调用动态编译方法! // 若是是文件的话,就按下面的方法 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); int result = compiler.run(null, null, null, "D:\\java_test\\HelloWorld.java"); System.out.println(result == 0 ? "编译成功" : "编译失败"); // 上面只是进行了编译,下面还要进行动态运行编译好的类 // 1. 经过Runtime调用执行类 Runtime run = Runtime.getRuntime(); Process process = run.exec("java -cp D:\\java_test HelloWorld"); InputStream in = process.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(in)); String info = ""; while ((info = reader.readLine()) != null) { System.out.println(info); } // 2. 经过反射调用执行类 try { URL[] urls = new URL[]{new URL("file:/" + "D:\\java_test\\")}; URLClassLoader loader = new URLClassLoader(urls); Class c = loader.loadClass("HelloWorld"); // 调用加载类的main方法 Method m = c.getMethod("main", String[].class); // 若是这里不用Object强制转型的话,invoke后面传入的就不是一个String // 的字符串数组,而是两个字符串,认为是两个参数,因而就会发生参数个数不匹配的问题 m.invoke(null, (Object) new String[]{}); } catch (Exception e) { e.printStackTrace(); } } }
JAVA脚本引擎是从JDK6.0以后添加的新功能
在写Demo的时候存在一些报错的状况,这是由于JDK6.0的语法在JDK8.0中已通过时了
function test(){ var a = 3; var b = 4; print("invoke js file: " + (a+b)); } // 执行test方法 test();
package com.sxt.test.testRhino; import javax.script.Invocable; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import java.io.FileReader; import java.net.URL; import java.util.List; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Demo01.java * @time: 2020/1/13 15:58 * @desc: 测试脚本引擎执行JavaScript代码 */ public class Demo01 { public static void main(String[] args) throws Exception { // 得到脚本引擎的对象 ScriptEngineManager sem = new ScriptEngineManager(); ScriptEngine engine = sem.getEngineByName("javascript"); // 定义变量,存储到引擎上下文中 engine.put("msg", "liyingjun is g good man!"); String str = "var user = {name: 'litian', age: 18, schools: ['清华大学', '北京尚学堂']};"; str += "print(user.name);"; // 执行脚本 engine.eval(str); engine.eval("msg = 'sxt is a good school!'"); System.out.println(engine.get("msg")); System.out.println("########################"); // 定义函数 engine.eval("function add(a, b){var sum = a + b; return sum;}"); // 取得调用接口 Invocable jsInvoke = (Invocable) engine; // 执行脚本中定义的方法 Object result1 = jsInvoke.invokeFunction("add", new Object[]{13, 20}); System.out.println(result1); // 导入其余java包,使用其余包中的java类 String jsCode = "var list=java.util.Arrays.asList([\"北京尚学堂\", \"清华大学\", \"中国石油大学\"]);"; engine.eval(jsCode); List<String> list2 = (List<String>) engine.get("list"); for (String temp : list2) { System.out.println(temp); } // 执行一个js文件 URL url = Demo01.class.getClassLoader().getResource("com/sxt/test/testRhino/test.js"); FileReader fr = new FileReader(url.getPath()); engine.eval(fr); fr.close(); } }
Java动态性的两种常见实现方式:
运行时操做字节码可让咱们实现以下功能:
优点
常见的字节码操做类库
测试使用javassist生成一个新的类
package com.sxt.test.testJavassist; import javassist.*; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Demo1.java * @time: 2020/1/14 9:21 * @desc: 测试使用javassist生成一个新的类 */ public class Demo1 { public static void main(String[] args) throws Exception { ClassPool pool = ClassPool.getDefault(); CtClass cc = pool.makeClass("com.sxt.test.testJavassist.EmpTest"); // 建立属性 CtField f1 = CtField.make("private int empno;", cc); CtField f2 = CtField.make("private String ename;", cc); cc.addField(f1); cc.addField(f2); // 建立方法 CtMethod m1 = CtMethod.make("public int getEmpno(){return empno;}", cc); CtMethod m2 = CtMethod.make("public void setEmpno(int empno){this.empno=empno;}", cc); cc.addMethod(m1); cc.addMethod(m2); // 添加构造器 CtConstructor constructor = new CtConstructor(new CtClass[]{CtClass.intType, pool.get("java.lang.String")}, cc); constructor.setBody("{this.empno = empno; this.ename = ename;}"); cc.addConstructor(constructor); // 将上面构造好的类写入到下面的工做空间下面 cc.writeFile("D:\\java_test"); System.out.println("生成类,成功!"); } }
测试javassist的API
Emp.java
package com.sxt.test.testJavassist; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Emp.java * @time: 2020/1/14 9:28 * @desc: */ @Author(name="litian", year=2020) public class Emp { private int empno; private String name; public int getEmpno() { return empno; } public void setEmpno(int empno) { this.empno = empno; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Emp() { } public Emp(int empno, String name) { this.empno = empno; this.name = name; } public void sayHello(int a){ System.out.println("Hello!: " + a); } }
Author.java
package com.sxt.test.testJavassist; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Author.java * @time: 2020/1/14 14:50 * @desc: */ public @interface Author { String name(); int year(); }
测试javassist的API
package com.sxt.test.testJavassist; import javassist.*; import java.lang.reflect.Method; import java.util.Arrays; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Demo2.java * @time: 2020/1/14 10:45 * @desc: 测试javassist的API */ public class Demo2 { /* 处理类的基本用法 */ public static void test1() throws Exception { ClassPool pool = ClassPool.getDefault(); CtClass cc = pool.get("com.sxt.test.testJavassist.Emp"); byte[] bytes = cc.toBytecode(); System.out.println(Arrays.toString(bytes)); // 获取类名 System.out.println(cc.getName()); // 获取简要类名 System.out.println(cc.getSimpleName()); // 得到父类 System.out.println(cc.getSuperclass()); // 得到接口 System.out.println(cc.getInterfaces()); } public static void test2() throws Exception { /* 测试产生新的方法 */ ClassPool pool = ClassPool.getDefault(); CtClass cc = pool.get("com.sxt.test.testJavassist.Emp"); // 新建方法1 CtMethod m1 = CtNewMethod.make("public int add(int a, int b){return a+b;}", cc); // 新建方法2 CtMethod m2 = new CtMethod(CtClass.intType, "add", new CtClass[]{CtClass.intType, CtClass.intType}, cc); // 设置权限 m2.setModifiers(Modifier.PUBLIC); // 设置方法体 $1等等表明的是形参的占位符 m2.setBody("{System.out.println(\"冲冲冲!\"); return $1+$2;}"); cc.addMethod(m2); // 经过反射调用新生成的方法 Class clazz = cc.toClass(); // 经过调用Emp无参构造器,建立新的Emp对象 Object obj = clazz.newInstance(); Method method = clazz.getDeclaredMethod("add", int.class, int.class); Object result = method.invoke(obj, 200, 300); System.out.println(result); } public static void test3() throws Exception { /* 对已有的方法进行修改 */ ClassPool pool = ClassPool.getDefault(); CtClass cc = pool.get("com.sxt.test.testJavassist.Emp"); CtMethod cm = cc.getDeclaredMethod("sayHello", new CtClass[]{CtClass.intType}); cm.insertBefore("System.out.println($1);System.out.println(\"start!!!\");"); cm.insertAfter("System.out.println(\"end!!!\");"); // 在某一行前面加代码,从1开始计数,不存在迭代效应,也就是改行代码的行数不会因加入了新的代码而改变 cm.insertAt(41, "System.out.println(\"???\");"); cm.insertAt(42, "System.out.println(\"!!!\");"); // 经过反射调用新生成的方法 Class clazz = cc.toClass(); Object obj = clazz.newInstance(); Method method = clazz.getDeclaredMethod("sayHello", int.class); Object result = method.invoke(obj, 200); System.out.println(result); } public static void test4() throws Exception { /* 对已有的属性进行修改 */ ClassPool pool = ClassPool.getDefault(); CtClass cc = pool.get("com.sxt.test.testJavassist.Emp"); // CtField f1 = CtField.make("private int empno;", cc); CtField f1 = new CtField(CtClass.intType, "salary", cc); f1.setModifiers(Modifier.PRIVATE); // 后面的参数是默认值,若是不写的话,就没有默认值 cc.addField(f1, "1000"); // 获取指定的属性 cc.getDeclaredField("salary"); // 除了直接经过增长方法的方式提供getter和setter方法,还能够经过如下方式 cc.addMethod(CtNewMethod.getter("getSalary", f1)); cc.addMethod(CtNewMethod.setter("setSalary", f1)); } public static void test5() throws Exception { /* 查看已有构造方法,并进行修改 */ ClassPool pool = ClassPool.getDefault(); CtClass cc = pool.get("com.sxt.test.testJavassist.Emp"); CtConstructor[] cs = cc.getConstructors(); for (CtConstructor c : cs) { System.out.println(c.getLongName()); c.insertBefore("System.out.println(\"what?\");"); } // 经过反射调用新生成的方法 Class clazz = cc.toClass(); Object obj = clazz.newInstance(); } public static void test6() throws Exception { /* 注解 */ ClassPool pool = ClassPool.getDefault(); CtClass cc = pool.get("com.sxt.test.testJavassist.Emp"); Object[] all = cc.getAnnotations(); Author a = (Author) all[0]; String name = a.name(); int year = a.year(); System.out.println("name: " + name + "year: " + year); } public static void main(String[] args) throws Exception { test6(); } }
Javassist库的局限性
JVM运行和类加载全过程
类的加载机制(JVM内存分析+反射机制核心原理+常量池理解)
JVM把class文件加载到内存,并对数据进行校验、解析和初始化,最终造成JVM能够直接使用的Java类型的过程。
加载:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区中的运行时数据结构,在堆中生成一个表明这个类的java.lang.Class对象,做为方法区类数据的访问入口。
连接:将Java类的二进制代码合并到JVM的运行状态之中的过程
初始化
<clinit>()
方法的过程。类构造器<clinit>()
方法是由编译器自动收集类中的全部类变量的赋值动做和静态语句块(static块)中的语句合并产生的。<clinit>()
方法在多线程环境中被正确加锁和同步。过程图解
初始化时机+静态初始化块执行的顺序问题
类的主动引用和被动引用
深刻类加载器
类加载器原理
类加载器树状结构、双亲委托(代理)机制
分类:
类加载器的代理模式
类加载器实战
package com.sxt.test.classLoader; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Demo01.java * @time: 2020/1/30 21:40 * @desc: */ public class Demo01 { public static void main(String[] args){ // 应用加载器 System.out.println(ClassLoader.getSystemClassLoader()); // 扩展加载器(上一个的父类) System.out.println(ClassLoader.getSystemClassLoader().getParent()); // 引导加载器,可是是C写的,因此为null(上一个的父类) System.out.println(ClassLoader.getSystemClassLoader().getParent().getParent()); // 系统中类的路径 System.out.println(System.getProperty("java.class.path")); } }
自定义类加载器(文件、网路、加密)
自定义加载器的流程:
自定义文件系统类加载器
FileSystemClassLoader
package com.sxt.test.classLoader; import java.io.*; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: FileSystemClassLoader.java * @time: 2020/1/31 20:58 * @desc: 自定义文件系统类加载器 */ public class FileSystemClassLoader extends ClassLoader { // com.sxt.test.bean.User --> F:/BookStudy/else/JAVAPro/src/com/sxt/test/bean/User.class private String rootDir; public FileSystemClassLoader(String rootDir) { this.rootDir = rootDir; } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { Class<?> c = findLoadedClass(name); // 应该要先查询有没有加载过这个类,若是已经加载,则直接返回加载好的类,若是没有,则加载新的类。 if (c != null) { return c; } else { ClassLoader parent = this.getParent(); // 委派给父类加载 try { c = parent.loadClass(name); }catch (Exception e){ System.out.println("父类加载器没有加载到这个类哦!"); } if (c != null) { return c; } else { byte[] classData = getClassData(name); if (classData == null) { throw new ClassNotFoundException(); } else { c = defineClass(name, classData, 0, classData.length); } } } return c; } private byte[] getClassData(String classname) { String path = rootDir + "/" + classname.replace('.', '/') + ".class"; // 能够使用IOUtils将流中的数据转成字节数组,这里采用手写了 InputStream is = null; ByteArrayOutputStream baos = null; try { is = new FileInputStream(path); baos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int temp = 0; while ((temp = is.read(buffer)) != -1) { baos.write(buffer, 0, temp); } return baos.toByteArray(); } catch (IOException e) { e.printStackTrace(); return null; } finally { try { if (is != null) { is.close(); } }catch(IOException e){ e.printStackTrace(); } try { if (baos != null) { baos.close(); } }catch(IOException e){ e.printStackTrace(); } } } }
测试自定义类加载器FileSystemClassLoader
package com.sxt.test.classLoader; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Demo02.java * @time: 2020/1/31 21:17 * @desc: 测试自定义类加载器FileSystemClassLoader */ public class Demo02 { public static void main(String[] args) throws ClassNotFoundException { FileSystemClassLoader loader1 = new FileSystemClassLoader("F:\\Java WorkSpace"); FileSystemClassLoader loader2 = new FileSystemClassLoader("F:\\Java WorkSpace"); System.out.println(loader1 == loader2); Class<?> c1 = loader1.loadClass("NewClass"); Class<?> c2 = loader1.loadClass("NewClass"); Class<?> c3 = loader2.loadClass("NewClass"); Class<?> c4 = loader1.loadClass("java.lang.String"); Class<?> c5 = loader1.loadClass("com.sxt.test.classLoader.Demo01"); System.out.println(c1); System.out.println(c1.hashCode()); System.out.println(c2); System.out.println(c2.hashCode()); // 注意:被两个类加载器加载的同一个类,JVM不认为是相同的类。 System.out.println(c3); System.out.println(c3.hashCode()); System.out.println(c4); System.out.println(c4.hashCode()); System.out.println(c1.getClassLoader()); System.out.println(c2.getClassLoader()); System.out.println(c3.getClassLoader()); // 自定义的类加载器 System.out.println(c4.getClassLoader()); // 引导类加载器 System.out.println(c5.getClassLoader()); // 系统默认的类加载器 } }
自定义网路类加载器
package com.sxt.test.classLoader; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: FileSystemClassLoader.java * @time: 2020/1/31 20:58 * @desc: 自定义网路类加载器 */ public class NetSystemClassLoader extends ClassLoader { // com.sxt.test.bean.User --> www.sxt.cn/JAVAPro/src/com/sxt/test/bean/User.class private String rootUrl; public NetSystemClassLoader(String rootDir) { this.rootUrl = rootDir; } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { Class<?> c = findLoadedClass(name); // 应该要先查询有没有加载过这个类,若是已经加载,则直接返回加载好的类,若是没有,则加载新的类。 if (c != null) { return c; } else { ClassLoader parent = this.getParent(); // 委派给父类加载 try { c = parent.loadClass(name); }catch (Exception e){ System.out.println("父类加载器没有加载到这个类哦!"); } if (c != null) { return c; } else { byte[] classData = getClassData(name); if (classData == null) { throw new ClassNotFoundException(); } else { c = defineClass(name, classData, 0, classData.length); } } } return c; } private byte[] getClassData(String classname) { String path = rootUrl + "/" + classname.replace('.', '/') + ".class"; // 能够使用IOUtils将流中的数据转成字节数组,这里采用手写了 InputStream is = null; ByteArrayOutputStream baos = null; try { URL url = new URL(path); is = url.openStream(); baos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int temp = 0; while ((temp = is.read(buffer)) != -1) { baos.write(buffer, 0, temp); } return baos.toByteArray(); } catch (IOException e) { e.printStackTrace(); return null; } finally { try { if (is != null) { is.close(); } }catch(IOException e){ e.printStackTrace(); } try { if (baos != null) { baos.close(); } }catch(IOException e){ e.printStackTrace(); } } } }
自定义加密解密类加载器
加密工具类
package com.sxt.test.classLoader; import java.io.*; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: EncrpUtil.java * @time: 2020/2/1 22:52 * @desc: 加密工具类 */ public class EncrpUtil { public static void main(String[] args) { encrpt("F:/Java WorkSpace/NewClass.class", "F:/Java WorkSpace/temp/NewClass.class"); } public static void encrpt(String src, String dest) { FileInputStream fis = null; FileOutputStream fos = null; try { fis = new FileInputStream(src); fos = new FileOutputStream(dest); int temp = -1; while ((temp = fis.read()) != -1) { // 取反操做 fos.write(temp ^ 0xff); } } catch (IOException e) { e.printStackTrace(); } finally { try { if (fis != null) { fis.close(); } } catch (IOException e) { e.printStackTrace(); } } try { if (fos != null) { fos.close(); } } catch (IOException e) { e.printStackTrace(); } } }
解密工具类:加载文件系统中加密后的class字节码的类加载器
package com.sxt.test.classLoader; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: DecrptClassLoader.java * @time: 2020/2/1 23:03 * @desc: 解密工具类:加载文件系统中加密后的class字节码的类加载器 */ public class DecrptClassLoader extends ClassLoader { // com.sxt.test.bean.User --> F:/BookStudy/else/JAVAPro/src/com/sxt/test/bean/User.class private String rootDir; public DecrptClassLoader(String rootDir) { this.rootDir = rootDir; } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { Class<?> c = findLoadedClass(name); // 应该要先查询有没有加载过这个类,若是已经加载,则直接返回加载好的类,若是没有,则加载新的类。 if (c != null) { return c; } else { ClassLoader parent = this.getParent(); // 委派给父类加载 try { c = parent.loadClass(name); } catch (Exception e) { System.out.println("父类加载器没有加载到这个类哦!"); } if (c != null) { return c; } else { byte[] classData = getClassData(name); if (classData == null) { throw new ClassNotFoundException(); } else { c = defineClass(name, classData, 0, classData.length); } } } return c; } private byte[] getClassData(String classname) { String path = rootDir + "/" + classname.replace('.', '/') + ".class"; // 能够使用IOUtils将流中的数据转成字节数组,这里采用手写了 InputStream is = null; ByteArrayOutputStream baos = null; try { is = new FileInputStream(path); baos = new ByteArrayOutputStream(); int temp = -1; while ((temp = is.read()) != -1) { // 取反操做,进行解密 baos.write(temp ^ 0xff); } return baos.toByteArray(); } catch (IOException e) { e.printStackTrace(); return null; } finally { try { if (is != null) { is.close(); } } catch (IOException e) { e.printStackTrace(); } try { if (baos != null) { baos.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
测试简单加密解密(取反)操做
package com.sxt.test.classLoader; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Demo03.java * @time: 2020/2/1 22:49 * @desc: 测试简单加密解密(取反)操做 */ public class Demo03 { public static void main(String[] args) throws ClassNotFoundException { int a = 3; // 00000011 System.out.println(Integer.toBinaryString(a ^ 0xff)); // 加载这个加密的类会报类格式错误ClassFormatError FileSystemClassLoader loader1 = new FileSystemClassLoader("F:/Java WorkSpace"); Class<?> c1 = loader1.loadClass("NewClass_encrp"); System.out.println(c1); // 使用解密类加载器加载加密后的类 DecrptClassLoader loader = new DecrptClassLoader("F:/Java WorkSpace/temp"); Class<?> c = loader.loadClass("NewClass"); System.out.println(c); } }
线程上下文类加载器
线程上下文类加载器测试
package com.sxt.test.classLoader; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Demo05.java * @time: 2020/2/2 22:51 * @desc: 线程上下文类加载器测试 */ public class Demo05 { public static void main(String[] args) throws ClassNotFoundException { ClassLoader loader = Demo05.class.getClassLoader(); System.out.println(loader); ClassLoader loader2 = Thread.currentThread().getContextClassLoader(); System.out.println(loader2); Thread.currentThread().setContextClassLoader(new FileSystemClassLoader("F:/Java WorkSpace")); System.out.println(Thread.currentThread().getContextClassLoader()); Class<Demo01> c = (Class<Demo01>) Thread.currentThread().getContextClassLoader().loadClass("com.sxt.test.classLoader.Demo01"); System.out.println(c); System.out.println(c.getClassLoader()); } }
服务器类加载原理和OSGI介绍
核心做用:保证一个类只有一个实例,而且提供一个访问该实例的全局访问点。
常见的应用场景:
单例模式的优势:
常见的五种单例模式实现方式:
(单例对象当即加载)
代码
package com.sxt.singleton; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: SingletonDemo01.java * @time: 2020/2/3 18:41 * @desc: 测试饿汉式单例模式 */ public class SingletonDemo01 { // 上来就把这个对象先new了,无论后面你使不使用它。因此叫作饿汉式。 // 类初始化时,当即加载这个对象。(因此不能延时加载) // 因为加载类时,自然的是线程安全的! private static SingletonDemo01 instance = new SingletonDemo01(); private SingletonDemo01(){ } // 方法没有同步,调用效率高! public static SingletonDemo01 getInstance(){ return instance; } }
饿汉式单例模式代码中,static变量会在类装载时初始化,此时也不会涉及多个线程对象访问该对象的问题。虚拟机保证只会装载一次该类,确定不会发生并发访问的问题。所以,能够省略synchronized关键字。
问题:若是只是加载本类,而不是要调用getInstance(),甚至永远没有调用,则会形成资源浪费!
(单例对象延迟加载)
代码
package com.sxt.singleton; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: SingletonDemo01.java * @time: 2020/2/3 18:41 * @desc: 测试懒汉式单例模式 */ public class SingletonDemo02 { // 类初始化时,不初始化这个对象。(延时加载,真正用的时候再建立) private static SingletonDemo02 instance; private SingletonDemo02() { } // 方法同步,调用效率低! public static synchronized SingletonDemo02 getInstance() { if (instance == null){ instance = new SingletonDemo02(); } return instance; } }
要点:lazy load!延迟加载,懒加载!真正用的时候才加载!
问题:资源利用率高了。可是,每次调用getInstance()方法都要同步,并发效率较低。
代码
package com.sxt.singleton; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: SingletonDemo01.java * @time: 2020/2/3 18:41 * @desc: 测试双重检测锁实现单例模式 */ public class SingletonDemo03 { private static SingletonDemo03 instance = null; private SingletonDemo03() { } public static SingletonDemo03 getInstance() { if (instance == null){ SingletonDemo03 sc; synchronized (SingletonDemo03.class){ sc = instance; if(sc == null){ synchronized (SingletonDemo03.class){ if(sc == null){ sc = new SingletonDemo03(); } } instance = sc; } } } return instance; } }
这个模式将同步内容下放到if内部,提升了执行的效率,没必要每次获取对象时都进行同步,只有第一次才同步,建立了之后就不必了。
问题:因为编辑器优化缘由和JVM底层内部模型缘由,偶尔会出问题,不建议使用。
(也是一种懒加载方式)
代码
package com.sxt.singleton; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: SingletonDemo01.java * @time: 2020/2/3 18:41 * @desc: 测试静态内部类实现单例模式,这种方式线程安全,调用效率高,而且实现了延时加载 */ public class SingletonDemo04 { private static class SingletonClassInstance{ private static final SingletonDemo04 instance = new SingletonDemo04(); } private SingletonDemo04(){ } // 方法没有同步,调用效率高! public static SingletonDemo04 getInstance(){ return SingletonClassInstance.instance; } }
要点
问题:
代码
package com.sxt.singleton; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: SingletonDemo01.java * @time: 2020/2/3 18:41 * @desc: 测试枚举实现单例模式(没有延时加载) */ public enum SingletonDemo05 { // 这个枚举元素,自己就是单例对象! INSTANCE; // 添加本身须要的操做! public void singletonOperation(){ } }
优势
缺点
UML类图
如何选用?
测试懒汉式单例模式
package com.sxt.singleton; import java.io.Serializable; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: SingletonDemo01.java * @time: 2020/2/3 18:41 * @desc: 测试懒汉式单例模式(如何防止反射和反序列化) */ public class SingletonDemo06 implements Serializable { // 类初始化时,不初始化这个对象。(延时加载,真正用的时候再建立) private static SingletonDemo06 instance; private SingletonDemo06() { // 经过检查是否已经建立对象了,若是有了,则抛出异常 if (instance != null) { throw new RuntimeException(); } } // 方法同步,调用效率低! public static synchronized SingletonDemo06 getInstance() { if (instance == null) { instance = new SingletonDemo06(); } return instance; } // 反序列化时,若是定了readResolve方法,则直接返回此方法指定的对象,而不须要单独再建立新对象! private Object readResolve() throws Exception{ return instance; } }
测试反射和反序列化被破解单例模式
package com.sxt.singleton; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/2/3 20:13 * @desc: 测试反射和反序列化被破解单例模式 */ public class Client2 { public static void main(String[] args) throws Exception { // 测试饿汉实现单例 SingletonDemo06 s1 = SingletonDemo06.getInstance(); SingletonDemo06 s2 = SingletonDemo06.getInstance(); System.out.println(s1); System.out.println(s2); // 经过反射的方式直接调用私有构造器 Class<SingletonDemo06> clazz = (Class<SingletonDemo06>) Class.forName("com.sxt.singleton.SingletonDemo06"); Constructor<SingletonDemo06> c = clazz.getDeclaredConstructor(null); // 这样设置就能够访问private的构造器了,这种方式则跳过了单例模式的限制 c.setAccessible(true); SingletonDemo06 s3 = c.newInstance(); SingletonDemo06 s4 = c.newInstance(); System.out.println(s3); System.out.println(s4); // 经过反序列化的方式构造多个对象 FileOutputStream fos = new FileOutputStream("a.txt"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(s1); oos.close(); fos.close(); ObjectInputStream ois = new ObjectInputStream(new FileInputStream("a.txt")); SingletonDemo06 s5 = (SingletonDemo06) ois.readObject(); System.out.println(s5); } }
CountDownLatch
测试五种建立单例模式的效率
package com.sxt.singleton; import java.util.concurrent.CountDownLatch; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/2/3 20:13 * @desc: 测试五种建立单例模式的效率 */ public class Client03 { public static void main(String[] args) throws Exception { long start = System.currentTimeMillis(); int threadNum = 10; final CountDownLatch countDownLatch = new CountDownLatch(threadNum); for (int i = 0; i < threadNum; i++) { new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 100000; i++) { // Object o = SingletonDemo04.getInstance(); Object o = SingletonDemo05.INSTANCE; } countDownLatch.countDown(); } }).start(); } // main线程阻塞,直到计数器变为0,才会继续往下执行! countDownLatch.await(); long end = System.currentTimeMillis(); System.out.println("总耗时:" + (end - start)); } }
要点:
代码:
Car接口
package com.sxt.factory.simplefactor; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Car.java * @time: 2020/2/5 15:59 * @desc: */ public interface Car { void run(); }
奥迪车
package com.sxt.factory.simplefactor; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Audi.java * @time: 2020/2/5 16:00 * @desc: */ public class Audi implements Car { @Override public void run() { System.out.println("奥迪在跑!"); } }
比亚迪车
package com.sxt.factory.simplefactor; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Byd.java * @time: 2020/2/5 16:01 * @desc: */ public class Byd implements Car { @Override public void run() { System.out.println("比亚迪在跑!"); } }
测试在没有工厂模式的状况下
package com.sxt.factory.simplefactor; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client01.java * @time: 2020/2/5 16:02 * @desc: 测试在没有工厂模式的状况下 */ public class Client01 { // 调用者 public static void main(String[] args){ Car c1 = new Audi(); Car c2 = new Byd(); c1.run(); c2.run(); } }
简单工厂类1
package com.sxt.factory.simplefactor; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: CarFactory.java * @time: 2020/2/5 16:04 * @desc: */ public class CarFactory { public static Car createCar(String type){ if("奥迪".equals(type)){ return new Audi(); }else if("比亚迪".equals(type)){ return new Byd(); }else{ // 简单工厂仍是有点小问题的,这里若是要加新的车辆的话,就须要改代码,违反了开闭原则OCP return null; } } }
简单工厂2
package com.sxt.factory.simplefactor; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: CarFactory.java * @time: 2020/2/5 16:04 * @desc: 简单工厂类2 */ public class CarFactory2 { public static Car createAudi() { return new Audi(); } public static Car createByd() { return new Byd(); } }
测试在简单工厂模式的状况下
package com.sxt.factory.simplefactor; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client01.java * @time: 2020/2/5 16:02 * @desc: 测试在简单工厂模式的状况下 */ public class Client02 { // 调用者 public static void main(String[] args){ Car c1 = CarFactory.createCar("奥迪"); Car c2 = CarFactory.createCar("比亚迪"); c1.run(); c2.run(); } }
UML类图
为了不简单工厂模式的缺点,不彻底知足OCP。
工厂方法模式和简单工厂模式最大的不一样在于,简单工厂模式只有一个(对于一个项目或者一个独立模块而言)工厂类,而工厂方法模式有一组实现了相同接口的工厂类。
代码:
新增了车的工厂interface
package com.sxt.factory.factorymethod; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: CarFactory.java * @time: 2020/2/5 19:42 * @desc: */ public interface CarFactory { Car createCar(); }
实现了车工厂的audi工厂
package com.sxt.factory.factorymethod; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: AudiFactory.java * @time: 2020/2/5 19:42 * @desc: */ public class AudiFactory implements CarFactory { @Override public Car createCar() { return new Audi(); } }
实现了车工厂的byd工厂
package com.sxt.factory.factorymethod; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: BydFactory.java * @time: 2020/2/5 19:43 * @desc: */ public class BydFactory extends Byd implements CarFactory { @Override public Car createCar() { return new Byd(); } }
客户端
package com.sxt.factory.factorymethod; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/2/5 19:44 * @desc: */ public class Client { public static void main(String[] args){ Car c1 = new AudiFactory().createCar(); Car c2 = new BydFactory().createCar(); Car c3 = new BenzFactory().createCar(); c1.run(); c2.run(); c3.run(); } }
若是须要新增车的类型的话,不须要修改原来的代码,只须要增长类就行,即知足了OCP
新增benz类
package com.sxt.factory.factorymethod; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Benz.java * @time: 2020/2/5 19:45 * @desc: */ public class Benz extends BenzFactory implements Car { @Override public void run() { System.out.println("奔驰在跑!"); } }
新增benz工厂
package com.sxt.factory.factorymethod; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Benz.java * @time: 2020/2/5 19:45 * @desc: */ public class Benz extends BenzFactory implements Car { @Override public void run() { System.out.println("奔驰在跑!"); } }
简单工厂模式和工厂方法模式PK:
根据设计理论建议:工厂方法模式。但实际上,咱们通常都用简单工厂模式。
用来生产不一样产品族的所有产品。(对于增长新的产品,无能为力;支持增长产品族)
抽象工厂模式是工厂方法模式的升级版本,在有多个业务品种、业务分类时,经过抽象工厂模式产生须要的对象是一种很是好的解决方式。
代码:
发动机
package com.sxt.factory.abstractfactory; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Engine.java * @time: 2020/2/6 12:40 * @desc: */ public interface Engine { void run(); void start(); } class LuxuryEngine implements Engine{ @Override public void run() { System.out.println("转得快!"); } @Override public void start() { System.out.println("启动快!能够自动启停!"); } } class LowerEngine implements Engine{ @Override public void run() { System.out.println("转得慢!"); } @Override public void start() { System.out.println("启动慢!能够自动启停!"); } }
座位
package com.sxt.factory.abstractfactory; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Seat.java * @time: 2020/2/6 12:42 * @desc: */ public interface Seat { void massage(); } class LuxurySeat implements Seat{ @Override public void massage() { System.out.println("能够按摩!"); } } class LowerSeat implements Seat{ @Override public void massage() { System.out.println("不能够按摩!"); } }
轮胎
package com.sxt.factory.abstractfactory; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Tyre.java * @time: 2020/2/6 12:43 * @desc: */ public interface Tyre { void revolve(); } class LuxuryTyre implements Tyre{ @Override public void revolve() { System.out.println("磨损慢!"); } } class LowerTyre implements Tyre{ @Override public void revolve() { System.out.println("磨损快!"); } }
车工厂
package com.sxt.factory.abstractfactory; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: CarFactory.java * @time: 2020/2/6 12:44 * @desc: */ public interface CarFactory { Engine createEngine(); Seat createSeat();; Tyre createTyre(); }
高端车工厂
package com.sxt.factory.abstractfactory; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: LuxuryCarFactory.java * @time: 2020/2/6 12:45 * @desc: */ public class LuxuryCarFactory implements CarFactory { @Override public Engine createEngine() { return new LuxuryEngine(); } @Override public Seat createSeat() { return new LuxurySeat(); } @Override public Tyre createTyre() { return new LuxuryTyre(); } }
低端车工厂
package com.sxt.factory.abstractfactory; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: LowerCarFactory.java * @time: 2020/2/6 12:45 * @desc: */ public class LowerCarFactory implements CarFactory { @Override public Engine createEngine() { return new LowerEngine(); } @Override public Seat createSeat() { return new LowerSeat(); } @Override public Tyre createTyre() { return new LowerTyre(); } }
客户端
package com.sxt.factory.abstractfactory; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/2/6 12:47 * @desc: */ public class Client { public static void main(String[] args){ CarFactory factory = new LuxuryCarFactory(); Engine e = factory.createEngine(); e.run(); e.start(); } }
工厂模式要点
应用场景
场景:
建造者模式的本质
代码:
宇宙飞船
package com.sxt.builder; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: AirShip.java * @time: 2020/2/6 13:48 * @desc: 宇宙飞船 */ public class AirShip { // 轨道舱 private OrbitalModule orbitalModule; // 发动机 private Engine engine; // 逃逸仓 private EscapeTower escapeTower; public void launch(){ System.out.println("发动机【" + engine.getName() + "】" + "轨道舱【" + orbitalModule.getName() + "】" + "逃离塔【" + escapeTower.getName() + "】" + "-->发射!"); } public OrbitalModule getOrbitalModule() { return orbitalModule; } public void setOrbitalModule(OrbitalModule orbitalModule) { this.orbitalModule = orbitalModule; } public Engine getEngine() { return engine; } public void setEngine(Engine engine) { this.engine = engine; } public EscapeTower getEscapeTower() { return escapeTower; } public void setEscapeTower(EscapeTower escapeTower) { this.escapeTower = escapeTower; } } class OrbitalModule { private String name; public OrbitalModule(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } } class Engine { private String name; public Engine(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } } class EscapeTower{ private String name; public EscapeTower(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
构建者接口
package com.sxt.builder; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: AirShipBuilder.java * @time: 2020/2/6 13:53 * @desc: */ public interface AirShipBuilder { Engine buildEngine(); OrbitalModule builderOrbitalModule(); EscapeTower buildEscapeTower(); }
装配者接口
package com.sxt.builder; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: AirShipDirector.java * @time: 2020/2/6 13:54 * @desc: 组装飞船对象 */ public interface AirShipDirector { // 组装飞船对象 AirShip directAirShip(); }
构建者
package com.sxt.builder; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: MyAirShipBuilder.java * @time: 2020/2/6 13:55 * @desc: */ public class MyAirShipBuilder implements AirShipBuilder{ @Override public Engine buildEngine() { System.out.println("构建发动机!"); return new Engine("个人发动机"); } @Override public OrbitalModule builderOrbitalModule() { System.out.println("构建轨道舱!"); return new OrbitalModule("个人轨道舱"); } @Override public EscapeTower buildEscapeTower() { System.out.println("构建逃逸塔!"); return new EscapeTower("个人逃逸塔"); } }
装配者
package com.sxt.builder; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: MyAirShipDirector.java * @time: 2020/2/6 13:59 * @desc: */ public class MyAirShipDirector implements AirShipDirector{ private AirShipBuilder builder; public MyAirShipDirector(AirShipBuilder builder) { this.builder = builder; } @Override public AirShip directAirShip() { // 从构建者获取组件 Engine e = builder.buildEngine(); OrbitalModule o = builder.builderOrbitalModule(); EscapeTower es = builder.buildEscapeTower(); // 进行组装 AirShip ship = new AirShip(); ship.setEngine(e); ship.setOrbitalModule(o); ship.setEscapeTower(es); return ship; } }
客户端
package com.sxt.builder; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/2/6 14:02 * @desc: */ public class Client { public static void main(String[] args) { AirShipDirector director = new MyAirShipDirector(new MyAirShipBuilder()); AirShip ship = director.directAirShip(); ship.launch(); } }
UML类图
开发中应用场景:
代码:
羊
package com.sxt.prototype; import java.util.Date; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Sheep1.java * @time: 2020/2/6 15:53 * @desc: 测试浅复制 */ public class Sheep1 implements Cloneable{ private String sname; private Date birthday; public String getSname() { return sname; } public void setSname(String sname) { this.sname = sname; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public Sheep1(String sname, Date birthday) { this.sname = sname; this.birthday = birthday; } public Sheep1() { } @Override protected Object clone() throws CloneNotSupportedException { // 直接调用object对象的clone()方法 Object obj = super.clone(); return obj; } }
客户端
package com.sxt.prototype; import java.util.Date; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client2.java * @time: 2020/2/6 15:57 * @desc: 测试原型模式(浅复制) */ public class Client1 { public static void main(String[] args) throws CloneNotSupportedException { Date d = new Date(3333333333L); Sheep1 s1 = new Sheep1("少理", d); System.out.println(s1); System.out.println(s1.getSname()); System.out.println(s1.getBirthday()); // 两个是不一样的对象,可是值是同样的! Sheep1 s2 = (Sheep1) s1.clone(); // 修改s1生日 d.setTime(22222222222L); System.out.println("--------------------------"); System.out.println(s1.getBirthday()); System.out.println(s2); System.out.println(s2.getSname()); System.out.println(s2.getBirthday()); // 修改s2的值 System.out.println("--------------------------"); s2.setSname("多里"); System.out.println(s2); System.out.println(s2.getSname()); System.out.println(s2.getBirthday()); } }
代码
羊
package com.sxt.prototype; import java.util.Date; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Sheep2.java * @time: 2020/2/6 15:53 * @desc: 测试深复制 */ public class Sheep2 implements Cloneable{ private String sname; private Date birthday; public String getSname() { return sname; } public void setSname(String sname) { this.sname = sname; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public Sheep2(String sname, Date birthday) { this.sname = sname; this.birthday = birthday; } public Sheep2() { } @Override protected Object clone() throws CloneNotSupportedException { // 直接调用object对象的clone()方法 Object obj = super.clone(); // 添加以下代码实现深复制 Sheep2 s = (Sheep2) obj; // 把属性也进行克隆 s.birthday = (Date) this.birthday.clone(); return obj; } }
客户端同上
区别
浅克隆和深克隆的区别
运行结果区别:浅克隆只是复制了生日变量对应的地址,这样即便值改变了,地址相同,则得到的生日的值也相同;深克隆将生日变量复制了一份,两个地址不一样,所以原型的值变了,与复制的值无关,所以生日的值依然是以前复制的值。
利用序列化和反序列化的技术实现深克隆!
package com.sxt.prototype; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.Date; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/2/6 15:57 * @desc: 测试原型模式(深复制),使用序列化和反序列化的方式实现深复制 */ public class Client3 { public static void main(String[] args) throws Exception { Date d = new Date(3333333333L); Sheep1 s1 = new Sheep1("少理", d); System.out.println(s1); System.out.println(s1.getSname()); System.out.println(s1.getBirthday()); // 两个是不一样的对象,可是值是同样的! // Sheep1 s2 = (Sheep1) s1.clone(); // 这里用序列化和反序列化实现深复制,因此用的是Sheep1,即浅复制的类 ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(s1); byte[] bytes = bos.toByteArray(); ByteArrayInputStream bis = new ByteArrayInputStream(bytes); ObjectInputStream ois = new ObjectInputStream(bis); Sheep1 s2 = (Sheep1) ois.readObject(); // 修改s1生日 d.setTime(22222222222L); System.out.println("--------------------------"); System.out.println(s1.getBirthday()); System.out.println(s2); System.out.println(s2.getSname()); System.out.println(s2.getBirthday()); } }
短期大量建立对象时,原型模式和普通new方式效率测试:若是须要短期建立大量对象,而且new的过程比较耗时。则能够考虑使用原型模式!
开发中的应用场景
建立型模式:都是来帮助咱们建立对象的!
结构型模式:
什么是适配器模式(adapter):将一个类的接口转换成客户但愿的另一个接口。Adapter模式使得本来因为接口不兼容而不能一块儿工做的那些类能够在一块儿工做。
模式中的角色:
代码:
被适配的类(没有usb插口的键盘)
package com.sxt.adapter; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Adaptee.java * @time: 2020/2/7 11:01 * @desc: 被适配的类,至关于PS/2键盘 */ public class Adaptee { public void request(){ System.out.println("能够完成客户请求的须要的功能!"); } }
客户端(只有usb接口的笔记本电脑)
package com.sxt.adapter; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/2/7 11:02 * @desc: 客户类,至关于笔记本,只有USB接口 */ public class Client { public void test1(Target t){ t.handleReq(); } public static void main(String[] args){ Client c = new Client(); Adaptee a = new Adaptee(); // 方式1:类适配器方式 Target t1 = new Adapter(); // 方式2:对象适配器方式 Target t2 = new Adapter2(a); c.test1(t2); } }
接口:usb插口
package com.sxt.adapter; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Target.java * @time: 2020/2/7 11:02 * @desc: 至关于USB插口 */ public interface Target { void handleReq(); }
package com.sxt.adapter; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Adapter.java * @time: 2020/2/7 11:03 * @desc: 【类适配器方式】适配器,至关于把键盘转换成usb接口的转接器 */ public class Adapter extends Adaptee implements Target{ // 个人理解:把适配器变成键盘(子类),并实现USB接口-->打字 @Override public void handleReq() { super.request(); } }
package com.sxt.adapter; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Adapter2.java * @time: 2020/2/7 11:07 * @desc: 【对象组合的方式,对象适配器方式】适配器 */ public class Adapter2 implements Target{ // 个人理解:把原来不兼容的键盘接口变成Target(即USB接口) private Adaptee adaptee; @Override public void handleReq() { adaptee.request(); } public Adapter2(Adaptee adaptee) { this.adaptee = adaptee; } }
工做中的场景:
咱们学习中见过的场景
以对象适配器为例,绘制UML类图
代码:
明星接口
package com.sxt.proxy.staticproxy; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Star.java * @time: 2020/2/7 13:51 * @desc: */ public interface Star { // 面谈 void confer(); // 签合同 void signContract(); // 订票 void bookTicket(); // 唱歌 void sing(); // 收钱 void collectMoney(); }
真实明星
package com.sxt.proxy.staticproxy; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: RealStar.java * @time: 2020/2/7 13:53 * @desc: */ public class RealStar implements Star { private String name = "真实明星"; @Override public void confer() { System.out.println(name + "面谈!"); } @Override public void signContract() { System.out.println(name + "签合同"); } @Override public void bookTicket() { System.out.println(name + "订票"); } @Override public void sing() { System.out.println(name + "唱歌"); } @Override public void collectMoney() { System.out.println(name + "收钱"); } }
代理经纪人
package com.sxt.proxy.staticproxy; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: ProxyStar.java * @time: 2020/2/7 13:55 * @desc: */ public class ProxyStar implements Star { private String name = "经纪人"; private Star star; public ProxyStar(Star star) { this.star = star; } @Override public void confer() { System.out.println(name + "面谈!"); } @Override public void signContract() { System.out.println(name + "签合同"); } @Override public void bookTicket() { System.out.println(name + "订票"); } @Override public void sing() { star.sing(); } @Override public void collectMoney() { System.out.println(name + "收钱"); } }
客户端
package com.sxt.proxy.staticproxy; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/2/7 13:57 * @desc: */ public class Client { public static void main(String[] args){ Star real = new RealStar(); Star proxy = new ProxyStar(real); proxy.confer(); proxy.signContract(); proxy.bookTicket(); proxy.sing(); proxy.collectMoney(); } }
动态生成代理类
动态代理相比于静态代理的优势:抽象角色中(接口)声明的全部方法都被转移到调用处理器一个集中的方法中处理,这样咱们能够更加灵活和统一的处理众多的方法。
JDK自带的动态代理
代码:
明星接口和真实明星接口同上
动态代理类
package com.sxt.proxy.dynamicproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: StarHandler.java * @time: 2020/2/7 16:19 * @desc: */ public class StarHandler implements InvocationHandler { Star realStar; public StarHandler(Star realStar) { this.realStar = realStar; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object obj = null; System.out.println("真正的方法执行前!"); System.out.println("面谈,签合同等。。。"); if (method.getName().equals("sing")) { obj = method.invoke(realStar, args); } System.out.println("真正的方法执行后!"); System.out.println("收钱!"); return obj; } }
客户端
package com.sxt.proxy.dynamicproxy; import java.lang.reflect.Proxy; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/2/7 16:22 * @desc: */ public class Client { public static void main(String[] args){ Star realStar = new RealStar(); StarHandler handler = new StarHandler(realStar); Star proxy = (Star) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Star.class}, handler); proxy.sing(); } }
bridge pattern
场景:商场系统中常见的商品分类,以电脑为类,如何良好的处理商品分类销售的问题?
咱们能够用多继承结构实现下图关系
问题:
桥接模式核心要点:处理多层集成结构,处理多维度变化的场景,将各个维度设计成独立的继承结构,使各个维度能够独立的扩展在抽象层创建关联。
桥接模式总结:
桥接模式实际开发中应用场景
不用桥接模式的话
package com.sxt.bridge; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Computer.java * @time: 2020/2/9 14:44 * @desc: */ public interface Computer { void sale(); } class Desktop implements Computer{ @Override public void sale() { System.out.println("销售台式机!"); } } class Laptop implements Computer{ @Override public void sale() { System.out.println("销售笔记本!"); } } class Pad implements Computer{ @Override public void sale() { System.out.println("销售平板电脑!"); } } class LenovoDesktop extends Desktop{ @Override public void sale() { System.out.println("销售联想台式机!");; } } class LenovoLaptop extends Laptop{ @Override public void sale() { System.out.println("销售联想笔记本!");; } } class LenovoPad extends Pad{ @Override public void sale() { System.out.println("销售联想平板电脑!");; } } class ShenzhouDesktop extends Desktop{ @Override public void sale() { System.out.println("销售神舟台式机!");; } } class ShenzhouLaptop extends Laptop{ @Override public void sale() { System.out.println("销售神舟笔记本!");; } } class ShenzhouPad extends Pad{ @Override public void sale() { System.out.println("销售神舟平板电脑!");; } } class DellDesktop extends Desktop{ @Override public void sale() { System.out.println("销售戴尔台式机!");; } } class DellLaptop extends Laptop{ @Override public void sale() { System.out.println("销售戴尔笔记本!");; } } class DellPad extends Pad{ @Override public void sale() { System.out.println("销售戴尔平板电脑!");; } }
使用桥接模式
品牌
package com.sxt.bridge; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Brand.java * @time: 2020/2/9 14:56 * @desc: 品牌 */ public interface Brand { void sale(); } class Lenovo implements Brand{ @Override public void sale() { System.out.println("销售联想电脑!"); } } class Dell implements Brand{ @Override public void sale() { System.out.println("销售戴尔电脑!"); } }
电脑类型的维度
package com.sxt.bridge; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: ComputerBridge.java * @time: 2020/2/9 14:58 * @desc: 电脑类型的维度 */ public class ComputerBridge { protected Brand brand; public ComputerBridge(Brand brand) { this.brand = brand; } public void sale(){ brand.sale(); } } class Desktop2 extends ComputerBridge{ public Desktop2(Brand brand) { super(brand); } @Override public void sale() { super.sale(); System.out.println("销售台式机!"); } } class Laptop2 extends ComputerBridge{ public Laptop2(Brand brand) { super(brand); } @Override public void sale() { super.sale(); System.out.println("销售笔记本电脑!"); } }
客户顿
package com.sxt.bridge; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/2/9 15:01 * @desc: */ public class Client { public static void main(String[] args){ // 销售联想的笔记本电脑 ComputerBridge c = new Laptop2(new Lenovo()); c.sale(); // 销售戴尔的台式机 ComputerBridge c2 = new Desktop2(new Dell()); c2.sale(); } }
composite patern
使用组合模式的场景:把部分和总体的关系用树形结构来表示,从而使得客户端能够使用统一的方式处理部分对象和总体对象。
组合模式核心:
抽象组件构成代码
package com.sxt.composite; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Component.java * @time: 2020/2/9 16:39 * @desc: 抽象组件 */ public interface Component { void operation(); } // 叶子组件 interface Leaf extends Component { } // 容器组件 interface Composite extends Component{ void add(Component c); void remove(Component c); Component getChild(int index); }
组合模式工做流程分析:
使用组合模式,模拟杀毒软件架构设计
抽象构建
package com.sxt.composite; import java.util.ArrayList; import java.util.List; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: AbstarctFile.java * @time: 2020/2/9 16:46 * @desc: 抽象构建 */ public interface AbstarctFile { void killVirus(); } class ImageFile implements AbstarctFile{ private String name; public ImageFile(String name) { this.name = name; } @Override public void killVirus() { System.out.println("---图像文件:" + name + ",进行查杀!"); } } class TextFile implements AbstarctFile{ private String name; public TextFile(String name) { this.name = name; } @Override public void killVirus() { System.out.println("---文本文件:" + name + ",进行查杀!"); } } class VideoFile implements AbstarctFile{ private String name; public VideoFile(String name) { this.name = name; } @Override public void killVirus() { System.out.println("---视频文件:" + name + ",进行查杀!"); } } class Folder implements AbstarctFile{ private String name; // 定义容器,用来存放本容器构建下的子节点 private List<AbstarctFile> list = new ArrayList<>(); public Folder(String name) { this.name = name; } public void add(AbstarctFile file){ list.add(file); } public void remove(AbstarctFile file){ list.remove(file); } public AbstarctFile getChild(int index){ return list.get(index); } @Override public void killVirus() { System.out.println("---文件夹:" + name + ",进行查杀!"); for (AbstarctFile file: list){ file.killVirus(); } } }
客户端
package com.sxt.composite; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/2/9 16:54 * @desc: */ public class Client { public static void main(String[] args){ AbstarctFile f2, f3, f5, f6; Folder f1 = new Folder("个人收藏"); f2 = new ImageFile("个人头像.jpg"); f3 = new TextFile("Hello.txt"); f1.add(f2); f1.add(f3); Folder f4 = new Folder("电影"); f5 = new VideoFile("神雕侠侣.avi"); f6 = new VideoFile("笑傲江湖.avi"); f4.add(f5); f4.add(f6); f1.add(f4); f1.killVirus(); } }
开发中的应用场景
decorator pattern
职责:
实现细节:
代码
抽象组件
package com.sxt.decorator; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: ICar.java * @time: 2020/2/9 18:07 * @desc: 抽象组件 */ public interface ICar { void move(); } // 真实对象 class Car implements ICar{ @Override public void move() { System.out.println("陆地上跑"); } } //装饰角色 class SuperCar implements ICar{ private ICar car; public SuperCar(ICar car) { this.car = car; } @Override public void move() { car.move(); } } // 具体装饰对象 class FlyCar extends SuperCar{ public FlyCar(ICar car) { super(car); } public void fly(){ System.out.println("天上飞!"); } @Override public void move() { super.move(); fly(); } } class WaterCar extends SuperCar{ public WaterCar(ICar car) { super(car); } public void swim(){ System.out.println("水上游!"); } @Override public void move() { super.move(); swim(); } } class AICar extends SuperCar{ public AICar(ICar car) { super(car); } public void autoMove(){ System.out.println("无人驾驶!"); } @Override public void move() { super.move(); autoMove(); } }
客户端
package com.sxt.decorator; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/2/9 18:13 * @desc: */ public class Client { public static void main(String[] args){ Car car = new Car(); car.move(); System.out.println("增长新的功能,飞行!"); FlyCar flyCar = new FlyCar(car); flyCar.move(); System.out.println("增长新的功能,游泳!"); WaterCar waterCar = new WaterCar(car); waterCar.move(); System.out.println("增长新的功能,飞行和游泳!"); WaterCar car2 = new WaterCar(new FlyCar(car)); car2.move(); } }
UML类图
开发中使用的场景
IO流实现细节
总结:
优势:
缺点:
装饰模式和桥接模式的区别:
两个模式都是为了解决过多子类对象的问题。可是他们的诱因不同。
个人理解是:
迪米特法则(最少知识原则):一个软件实体应当尽量少的与其余实体发生相互做用。
外观模式核心:为子系统提供统一的入口。封装子系统的复杂性,便于客户端调用。
公司注册流程:
不使用外观模式
使用外观模式
开发中常见的场景
FlyWeight Pattern
场景:内存属于稀缺资源,不要随便浪费。若是有不少个彻底相同或类似的对象,咱们能够经过享元模式,节省内存。
核心:
围棋软件设计:每一个围棋棋子都是一个对象,有以下属性:
享元模式实现:
FlyweightFactory享元工厂类:
建立并管理享元对象,享元池通常设计成键值对
FlyWeight抽象享元类
一般是一个接口或抽象类,声明公共方法,这些方法能够向外界提供对象的内部状态,设置外部状态。
ConcreteFlyWeight具体享元类
为内部状态提供成员变量进行存储
UnsharedConcreteFlyWeight非共享享元类
不能被共享的子类能够设计为非共享享元类
享元模式实现的UML图
代码:
享元类和实际享元实现类(这里实现了颜色共享)
package com.sxt.flyweight; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: ChessFlyWeight.java * @time: 2020/2/10 12:37 * @desc: 享元类 */ public interface ChessFlyWeight { void setColor(String c); String getColor(); void display(Coordinate c); } class ConcreteChess implements ChessFlyWeight{ private String color; public ConcreteChess(String color) { this.color = color; } @Override public void setColor(String c) { this.color = c; } @Override public String getColor() { return color; } @Override public void display(Coordinate c) { System.out.println("棋子颜色:" + color); System.out.println("棋子位置:" + c.getX() + ", " + c.getY()); } }
外部类,这里是坐标,即非享元类
package com.sxt.flyweight; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Coordinate.java * @time: 2020/2/10 12:37 * @desc: 外部状态,UnsharedConcreteFlyWeight非共享享元类 */ public class Coordinate { private int x, y; public Coordinate(int x, int y) { this.x = x; this.y = y; } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } }
享元工厂类(用来生成享元对象)
package com.sxt.flyweight; import java.util.HashMap; import java.util.Map; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: ChessFlyWeightFactory.java * @time: 2020/2/10 12:43 * @desc: 享元工厂类 */ public class ChessFlyWeightFactory { // 享元池 private static Map<String, ChessFlyWeight> map = new HashMap<>(); public static ChessFlyWeight getChess(String color){ if(map.get(color) != null){ return map.get(color); }else{ ChessFlyWeight cfw = new ConcreteChess(color); map.put(color, cfw); return cfw; } } }
客户端
package com.sxt.flyweight; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/2/10 12:47 * @desc: */ public class Client { public static void main(String[] args){ ChessFlyWeight chess1 = ChessFlyWeightFactory.getChess("black"); ChessFlyWeight chess2 = ChessFlyWeightFactory.getChess("black"); System.out.println(chess1); System.out.println(chess2); // 增长外部状态的处理 chess1.display(new Coordinate(10, 10)); chess1.display(new Coordinate(20, 20)); } }
享元模式开发中应用的场景:
享元模式的优势:
享元模式的缺点:
封装请假的基本信息
package com.sxt.chainofresp; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: LeaveRequest.java * @time: 2020/2/10 18:01 * @desc: 封装请假的基本信息 */ public class LeaveRequest { private String empName; private int leaveDays; private String reason; public LeaveRequest(String empName, int leaveDays, String reason) { this.empName = empName; this.leaveDays = leaveDays; this.reason = reason; } public String getEmpName() { return empName; } public void setEmpName(String empName) { this.empName = empName; } public int getLeaveDays() { return leaveDays; } public void setLeaveDays(int leaveDays) { this.leaveDays = leaveDays; } public String getReason() { return reason; } public void setReason(String reason) { this.reason = reason; } }
抽象类领导
package com.sxt.chainofresp; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Leader.java * @time: 2020/2/10 18:02 * @desc: 抽象类 领导 */ public abstract class Leader { protected String name; // 领导的下一个责任领导 protected Leader nextLeader; public Leader(String name) { this.name = name; } // 设定责任链上的后继对象 public void setNextLeader(Leader nextLeader) { this.nextLeader = nextLeader; } // 处理请求的核心业务方法 public abstract void handleRequest(LeaveRequest request); }
上级
package com.sxt.chainofresp; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Director.java * @time: 2020/2/10 18:06 * @desc: */ public class Director extends Leader { public Director(String name) { super(name); } @Override public void handleRequest(LeaveRequest request) { if(request.getLeaveDays() < 3){ System.out.println("员工:" + request.getEmpName() + "请假:" + request.getLeaveDays() + "天,理由是:" + request.getReason()); System.out.println("主任:" + this.name + "审批经过!"); }else{ if(this.nextLeader != null){ this.nextLeader.handleRequest(request); } } } }
经理
package com.sxt.chainofresp; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Manager.java * @time: 2020/2/10 18:06 * @desc: 经理 */ public class Manager extends Leader { public Manager(String name) { super(name); } @Override public void handleRequest(LeaveRequest request) { if(request.getLeaveDays() < 10){ System.out.println("员工:" + request.getEmpName() + "请假:" + request.getLeaveDays() + "天,理由是:" + request.getReason()); System.out.println("经理:" + this.name + "审批经过!"); }else{ if(this.nextLeader != null){ this.nextLeader.handleRequest(request); } } } }
总经理
package com.sxt.chainofresp; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Manager.java * @time: 2020/2/10 18:06 * @desc: 总经理 */ public class GeneralManager extends Leader { public GeneralManager(String name) { super(name); } @Override public void handleRequest(LeaveRequest request) { if(request.getLeaveDays() < 30){ System.out.println("员工:" + request.getEmpName() + "请假:" + request.getLeaveDays() + "天,理由是:" + request.getReason()); System.out.println("总经理:" + this.name + "审批经过!"); }else{ System.out.println("莫非" + request.getEmpName() + "想辞职!居然请假" + request.getLeaveDays() + "天!"); } } }
客户端
package com.sxt.chainofresp; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/2/10 18:11 * @desc: */ public class Client { public static void main(String[] args){ Leader a = new Director("张三"); Leader b = new Manager("李四"); Leader c = new GeneralManager("王五"); // 组织责任链对象关系 a.setNextLeader(b); b.setNextLeader(c); // 开始请假操做 LeaveRequest req1 = new LeaveRequest("Tom", 10, "回家睡觉!"); a.handleRequest(req1); } }
iterator pattern
场景:
基本案例:
实现正向遍历的迭代器
自定义的迭代器接口
package com.sxt.iterator; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: MyIterator.java * @time: 2020/2/14 18:42 * @desc: 自定义的迭代器接口 */ public interface MyIterator { // 将游标指向第一个元素 void first(); // 将游标指向下一个元素 void next(); // 判断是否存在下一个元素 boolean hasNext(); boolean ifFirst(); boolean isLast(); // 获取当前游标指向的对象 Object getCurrentObj(); }
自定义的聚合类
package com.sxt.iterator; import java.util.ArrayList; import java.util.List; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: ConcreteMyAggregate.java * @time: 2020/2/14 18:45 * @desc: 自定义的聚合类 */ public class ConcreteMyAggregate { private List<Object> list = new ArrayList<Object>(); public void addObject(Object obj) { this.list.add(obj); } public void removeObject(Object obj) { this.list.remove(obj); } public List<Object> getList() { return list; } public void setList(List<Object> list) { this.list = list; } // 得到迭代器 public MyIterator createIterator(){ return new ConcreteIterator(); } // 使用内部类定义迭代器,能够直接使用外部类的属性 private class ConcreteIterator implements MyIterator { // 定义游标用于记录遍历时的位置 private int cursor; @Override public void first() { cursor = 0; } @Override public void next() { if (cursor < list.size()) { cursor++; } } @Override public boolean hasNext() { return cursor < list.size(); } @Override public boolean ifFirst() { return cursor == 0; } @Override public boolean isLast() { return cursor == (list.size() - 1); } @Override public Object getCurrentObj() { return list.get(cursor); } } }
客户端
package com.sxt.iterator; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/2/14 18:53 * @desc: */ public class Client { public static void main(String[] args){ ConcreteMyAggregate cma = new ConcreteMyAggregate(); cma.addObject("aa"); cma.addObject("bb"); cma.addObject("cc"); MyIterator iter = cma.createIterator(); while(iter.hasNext()){ System.out.println(iter.getCurrentObj()); iter.next(); } } }
实现逆向遍历的迭代器
开发中常见的场景:
Mediator Pattern
场景:总经理协调各个部门之间的关系,起到一个中介的做用。
核心:
代码类图
代码:
总经理类的接口
package com.sxt.mediator; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Mediator.java * @time: 2020/2/14 19:07 * @desc: 总经理类的接口 */ public interface Mediator { void regitster(String dname, Department d); void command(String dname); }
同事类接口
package com.sxt.mediator; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Department.java * @time: 2020/2/14 19:08 * @desc: 同事类的接口 */ public interface Department { // 作本部门的事情 void selfAction(); // 向总经理发出申请 void outAction(); }
研发部门
package com.sxt.mediator; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Development.java * @time: 2020/2/14 19:09 * @desc: */ public class Development implements Department { // 持有中介者(总经理)的引用 private Mediator m; public Development(Mediator m) { this.m = m; m.regitster("development", this); } @Override public void selfAction() { System.out.println("专心搞科研!"); } @Override public void outAction() { System.out.println("向总经理汇报工做!须要资金支持!"); } }
财务部门
package com.sxt.mediator; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Finacial.java * @time: 2020/2/14 19:11 * @desc: */ public class Finacial implements Department { // 持有中介者(总经理)的引用 private Mediator m; public Finacial(Mediator m) { this.m = m; m.regitster("finacial", this); } @Override public void selfAction() { System.out.println("数钱!"); } @Override public void outAction() { System.out.println("钱太多了啊总经理!怎么花!"); } }
市场部门
package com.sxt.mediator; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Market.java * @time: 2020/2/14 19:13 * @desc: */ public class Market implements Department { // 持有中介者(总经理)的引用 private Mediator m; public Market(Mediator m) { this.m = m; m.regitster("market", this); } @Override public void selfAction() { System.out.println("跑去接项目!"); } @Override public void outAction() { System.out.println("承接项目的进度!须要资金支持!"); m.command("finacial"); } }
总经理
package com.sxt.mediator; import java.util.HashMap; import java.util.Map; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: President.java * @time: 2020/2/14 19:14 * @desc: */ public class President implements Mediator { private Map<String, Department> map = new HashMap<String, Department>(); @Override public void regitster(String dname, Department d) { map.put(dname, d); } @Override public void command(String dname) { map.get(dname).selfAction(); } }
客户端
package com.sxt.mediator; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/2/14 19:17 * @desc: */ public class Client { public static void main(String[] args){ Mediator m = new President(); Market market = new Market(m); Development devp = new Development(m); Finacial f = new Finacial(m); market.selfAction(); market.outAction(); } }
中介者模式的本质:解耦多个同事对象之间的交互关系。每一个对象都持有中介者对象的引用,只跟中介者对象打交道。咱们经过中介者对象统一管理这些交互关系。
开发中常见的场景:
command pattern
介绍:将一个请求封装为一个对象,从而使咱们可用不一样的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操做。也称为:动做Action模式、事务transaction模式。
结构:
Command抽象命令类
ConcreteCommand具体命令类
Invoker调用者/请求者:请求的发送者,它经过命令对象来执行请求。一个调用者并不须要在设计时肯定其接受者,所以它只与抽象命令类之间存在关联。在程序运行时,将调用命令对象的execute(),间接调用接受者的相关操做。
Receiver接受者
Client客户类:在客户类中须要建立调用者对象、具体命令类对象,在建立具体命令对象时指定对应的接受者。发送者和接受者之间没有直接联系,都经过命令对象间接调用。
类图
代码:
真正的命令执行者
package com.sxt.command; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Receiver.java * @time: 2020/2/15 14:28 * @desc: 真正的命令执行者 */ public class Receiver { public void action(){ System.out.println("Receiver.action()"); } }
命令管理
package com.sxt.command; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Command.java * @time: 2020/2/15 14:29 * @desc: 命令管理 */ public interface Command { // 这个方法是一个返回结果为空的方法 // 实际项目中,能够根据需求设计多个不一样的方法 void execute(); } class ConcreteCommand implements Command{ // 命令的真正执行者 private Receiver receiver; public ConcreteCommand(Receiver receiver) { this.receiver = receiver; } @Override public void execute() { // 命令真正执行前或后,执行相关的处理 receiver.action(); } }
命令的调用者和发起者
package com.sxt.command; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Invoke.java * @time: 2020/2/15 14:34 * @desc: 命令的调用者和发起者 */ public class Invoke { // 也能够经过容器放不少不少命令,进行批处理。好比数据库底层的事务管理 private Command command; public Invoke(Command command) { this.command = command; } // 业务方法,用于调用命令类的方法 public void call(){ command.execute(); } }
客户端
package com.sxt.command; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/2/15 14:36 * @desc: */ public class Client { public static void main(String[] args){ Command c = new ConcreteCommand(new Receiver()); Invoke i = new Invoke(c); i.call(); } }
开发中常见的场景:
strategy pattern
场景:
本质:分离算法,选择实现
开发中常见的场景
策略模式对应于解决某一个问题的一个算法族,容许用户从该算法族中任选一个算法解决某以问题,同时能够方便的更换算法或者增长新的算法。而且由客户端决定调用哪一个算法。
代码
策略接口
package com.sxt.strategy; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Strategy.java * @time: 2020/2/29 16:37 * @desc: */ public interface Strategy { public double getPrice(double standarPrice); }
普通客户小批量购买
package com.sxt.strategy; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @time: 2020/2/29 16:37 * @desc: 普通客户小批量购买 */ public class NewCustomerFewStrategy implements Strategy{ @Override public double getPrice(double standarPrice) { System.out.println("不打折原价!"); return standarPrice; } }
普通客户大批量购买
package com.sxt.strategy; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @time: 2020/2/29 16:37 * @desc: 普通客户大批量购买 */ public class NewCustomerManyStrategy implements Strategy{ @Override public double getPrice(double standarPrice) { System.out.println("打九折!"); return standarPrice*0.9; } }
老客户小批量购买
package com.sxt.strategy; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @time: 2020/2/29 16:37 * @desc: 老客户小批量购买 */ public class OldCustomerFewStrategy implements Strategy{ @Override public double getPrice(double standarPrice) { System.out.println("打八五折!"); return standarPrice*0.85; } }
老客户大批量购买
package com.sxt.strategy; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @time: 2020/2/29 16:37 * @desc: 老客户大批量购买 */ public class OldCustomerManyStrategy implements Strategy{ @Override public double getPrice(double standarPrice) { System.out.println("打八折!"); return standarPrice*0.8; } }
负责和具体的策略类交互
package com.sxt.strategy; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Context.java * @time: 2020/2/29 16:40 * @desc: 负责和具体的策略类交互,这样的话,具体的算法和直接的客户端调用分类了,使得算法能够独立于客户端独立的变化。 * 若是使用Spring的依赖注入功能,还能够经过配置文件,动态的注入不一样策略对象,动态的切换不一样的算法。 */ public class Context { // 当前采用的算法对象 private Strategy strategy; // 能够经过构造器来注入 public Context(Strategy strategy) { this.strategy = strategy; } // 或者经过加一个set方法来注入 public void setStrategy(Strategy strategy) { this.strategy = strategy; } public void printPrice(double s){ System.out.println("您的报价:" + strategy.getPrice(s)); } }
客户端
package com.sxt.strategy; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/2/29 16:56 * @desc: | */ public class Client { public static void main(String[] args){ Strategy s1 = new OldCustomerManyStrategy(); Context ctx = new Context(s1); ctx.printPrice(998); } }
template method pattern
场景:客户到银行办理业务:
代码
模拟银行业务流程
package com.sxt.template; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: BankTemplateMethod.java * @time: 2020/2/29 17:10 * @desc: | */ public abstract class BankTemplateMethod { // 具体方法 public void takeNumber(){ System.out.println("取号排队!"); } // 办理具体的业务,钩子方法 public abstract void transact(); public void evaluate(){ System.out.println("反馈评分!"); } // 模板方法 public final void process(){ this.takeNumber(); this.transact(); this.evaluate(); } }
客户端
package com.sxt.template; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/2/29 17:11 * @desc: | */ public class Client { public static void main(String[] args){ BankTemplateMethod btm = new DrawMoney(); btm.process(); // 一般采用匿名内部类 BankTemplateMethod btm2 = new BankTemplateMethod() { @Override public void transact() { // 存钱 System.out.println("我要存钱"); } }; btm2.process(); } } // 取款 class DrawMoney extends BankTemplateMethod{ @Override public void transact() { System.out.println("我要取款!"); } }
方法回调(钩子方法)
何时用到模板方法模式:实现一个算法时,总体步骤很固定,可是,某些部分易变。易变的部分能够抽象出来,供子类实现。
开发中常见的场景:很是频繁。各个框架、类库中都有影子。好比常见的优:
state pattern
场景:
核心:用于解决系统中复杂对象的状态转换以及不一样状态下行为的封装问题
结构:
类图:
代码
状态接口
package com.sxt.state; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: State.java * @time: 2020/2/29 18:11 * @desc: | */ public interface State { void handle(); }
空闲状态
package com.sxt.state; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @time: 2020/2/29 18:11 * @desc: |空闲状态 */ public class FreeState implements State{ @Override public void handle() { System.out.println("房间空闲!没人住!"); } }
预约状态
package com.sxt.state; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @time: 2020/2/29 18:11 * @desc: |预约状态 */ public class BookedState implements State{ @Override public void handle() { System.out.println("房间已预订!"); } }
已入住状态
package com.sxt.state; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @time: 2020/2/29 18:11 * @desc: |已入住状态 */ public class CheckedState implements State{ @Override public void handle() { System.out.println("房间已入住!"); } }
上下文环境类:表明当前的状态和状态之间切换的核心方法
package com.sxt.state; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Context.java * @time: 2020/2/29 18:15 * @desc: | */ public class HomeContext { // 当前状态 private State state; public HomeContext(State state) { this.state = state; this.state.handle(); } // 设置不一样状态 public void setState(State s){ System.out.println("修改状态!"); state = s; state.handle(); } }
客户端
package com.sxt.state; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/2/29 18:17 * @desc: | */ public class Client { public static void main(String[] args) { HomeContext ctx = new HomeContext(new FreeState()); ctx.setState(new BookedState()); ctx.setState(new CheckedState()); } }
开发中常见的场景:
Observer Pattern
场景
上面这些场景,咱们均可以使用观察者模式处理。咱们能够把多个订阅者、客户称之为观察者;须要同步给多个订阅者的数据封装到对象中,称之为目标。
核心:
UML类图
代码:
消息发布对象
package com.sxt.observer; import java.util.ArrayList; import java.util.List; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Subject.java * @time: 2020/3/1 13:36 * @desc: | */ public class Subject { protected List<Observer> list = new ArrayList<>(); public void registerObserver(Observer obs) { list.add(obs); } public void removeObserver(Observer obs) { list.remove(obs); } // 通知全部的观察者更新状态 public void notifyAllObservers() { for (Observer obs : list) { obs.update(this); } } }
消息发布对象的具体实现
package com.sxt.observer; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: ConcreteSubject.java * @time: 2020/3/1 13:41 * @desc: | */ public class ConcreteSubject extends Subject { private int state; public int getState() { return state; } public void setState(int state) { this.state = state; // 主题对象/目标对象的值发生了变化,请通知全部的观察者 this.notifyAllObservers(); } }
观察者接口
package com.sxt.observer; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Observer.java * @time: 2020/3/1 13:36 * @desc: | */ public interface Observer { void update(Subject subject); }
观察者
package com.sxt.observer; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: ObserverA.java * @time: 2020/3/1 13:43 * @desc: | */ public class ObserverA implements Observer { // myState须要跟目标对象的值保持一致 private int myState; public int getMyState() { return myState; } public void setMyState(int myState) { this.myState = myState; } @Override public void update(Subject subject) { myState = ((ConcreteSubject)subject).getState(); } }
客户端
package com.sxt.observer; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/3/1 13:45 * @desc: | */ public class Client { public static void main(String[] args){ // 建立目标对象 ConcreteSubject subject = new ConcreteSubject(); // 建立多个观察者 ObserverA obs1 = new ObserverA(); ObserverA obs3 = new ObserverA(); ObserverA obs2 = new ObserverA(); // 让这三个观察者添加到subject对象的观察者队伍中 subject.registerObserver(obs1); subject.registerObserver(obs2); subject.registerObserver(obs3); // 改变subject的状态 subject.setState(3000); // 查看观察者的状态 System.out.println(obs1.getMyState()); System.out.println(obs2.getMyState()); System.out.println(obs3.getMyState()); } }
JAVASE中提供了java.util.Observable和java.util.Observer来实现观察者模式
目标对象
package com.sxt.observer2; import java.util.Observable; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: ConcreteSubject.java * @time: 2020/3/1 14:05 * @desc: | */ public class ConcreteSubject extends Observable { private int state; public int getState() { return state; } public void setState(int state) { this.state = state; } public void set(int s){ // 目标对象的状态发生了改变 state = s; // 表示目标对象已经发生了更改 setChanged(); // 通知全部的观察者 notifyObservers(state); } }
观察者对象
package com.sxt.observer2; import java.util.Observable; import java.util.Observer; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: ObserverA.java * @time: 2020/3/1 14:07 * @desc: | */ public class ObserverA implements Observer { private int myState; public int getMyState() { return myState; } public void setMyState(int myState) { this.myState = myState; } @Override public void update(Observable o, Object arg) { myState = ((ConcreteSubject)o).getState(); } }
客户端
package com.sxt.observer2; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/3/1 14:09 * @desc: | */ public class Client { public static void main(String[] args){ // 建立目标对象Observable ConcreteSubject subject = new ConcreteSubject(); // 建立观察者 ObserverA obs1 = new ObserverA(); ObserverA obs2 = new ObserverA(); ObserverA obs3 = new ObserverA(); // 将上面三个观察者对象加到目标对象subject的观察者容器中 subject.addObserver(obs1); subject.addObserver(obs2); subject.addObserver(obs3); // 改变subject对象的状态 subject.set(300); // 看看观察者的状态发生变化了没 System.out.println(obs1.getMyState()); System.out.println(obs2.getMyState()); System.out.println(obs3.getMyState()); } }
开发中常见的场景
memento pattern
场景:
核心:就是保存某个对象内部状态的拷贝,这样之后就能够将该对象恢复到原先的状态。
结构
代码:
源发器类
package com.sxt.memento; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Emp.java * @time: 2020/3/1 14:38 * @desc: |源发器类 */ public class Emp { private String name; private int age; private double salary; // 进行备忘操做,并返回备忘录对象 public EmpMemento memento() { return new EmpMemento(this); } // 进行数据恢复,恢复成制定备忘录对象的值 public void recovery(EmpMemento mmt){ this.name = mmt.getName(); this.age = mmt.getAge(); this.salary = mmt.getSalary(); } public Emp(String name, int age, double salary) { this.name = name; this.age = age; this.salary = salary; } 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; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } }
备忘录类
package com.sxt.memento; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: EmpMemento.java * @time: 2020/3/1 14:54 * @desc: |备忘录类 */ public class EmpMemento { private String name; private int age; private double salary; public EmpMemento(Emp e){ this.name = e.getName(); this.age = e.getAge(); this.salary = e.getSalary(); } 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; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } }
负责人类:管理备忘录对象
package com.sxt.memento; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: CareTaker.java * @time: 2020/3/1 14:58 * @desc: |负责人类:管理备忘录对象 */ public class CareTaker { private EmpMemento memento; public EmpMemento getMemento() { return memento; } public void setMemento(EmpMemento memento) { this.memento = memento; } }
客户端
package com.sxt.memento; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/3/1 14:58 * @desc: | */ public class Client { public static void main(String[] args) { CareTaker taker = new CareTaker(); Emp emp = new Emp("李英俊", 18, 900); System.out.println("第一次建立对象:" + emp.getName() + emp.getAge() + emp.getSalary()); // 进行一次备份 taker.setMemento(emp.memento()); emp.setAge(38); emp.setName("哈哈"); emp.setSalary(10); System.out.println("第二次建立对象:" + emp.getName() + emp.getAge() + emp.getSalary()); // 恢复到备忘录对象保存的状态 emp.recovery(taker.getMemento()); System.out.println("第三次建立对象:" + emp.getName() + emp.getAge() + emp.getSalary()); } }
UML类图
备忘点较多时
开发中常见的应用场景:
普通字符:匹配与之相同的一个字符
简单的转义字符:
标准字符集合
自定义字符集合
[\d.\-+]
将匹配:数字、小数点、+、-量词 | Quantifier
修饰匹配次数的特殊符号
\d\d{6} != {\d\d}{6}
匹配次数中的贪婪模式(匹配字符越多越好,默认!)
匹配次数中的非贪婪模式(匹配字符越少越好,修饰匹配次数的特殊符号后再加上一个“?”号)例:\d{2,3}?
字符边界(零宽)
本组标记匹配的不是字符而是位置,符合某 种条件的位置
\b匹配这样一个位置:前面的字符和后面的字符不全是\w
gaoqi\b
测试:
\bgaoqi\b
测试:
IGNORECASE:忽略大小写模式
SINGLELINE:单行模式
MULTILINE:多行模式
选择符和分组
反向引用(\nnm)
预搜索(零宽断言)
只进行子表达式的匹配,匹配内容不计入最终的匹配结果,是零宽度
这个位置应该符合某个条件。判断当前位置的先后字符,是否符合指定的条件,但不匹配先后的字符。是对位置的匹配。
正则表达式匹配过程当中,若是子表达式匹配到的是字符的内容,而非位置,并被保存到最终的匹配结果中,那么就认为这个子表达式是占有字符的;若是子表达式匹配的仅仅是位置,或者匹配的内容并不保存到最终的匹配结果中,那么就认为这个子表达式是零宽度的。占有字符仍是零宽度,是针对匹配的内容是否保存到最终的匹配结果中而言的。
练习1
解答1:(0\d{2,3}-\d{7,8})|(1[35789]\d{9})
练习2
解答2:[\w\-]+@[a-z0-9A-Z]+(\.[A-Za-z]{2,4}){1,2}
开发环境
JAVA相关类位于java.util.regex包下面
类Pattern:
Pattern p = Pattern.compile(r, int);
类Matcher:
Matcher m = p.matcher(str);
测试
匹配整个正则表达式
package com.sxt.regex; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Demo01.java * @time: 2020/3/3 14:10 * @desc: | */ public class Demo01 { public static void main(String[] args){ // 在这个字符串:asdfsadf2323,是否符合制定的正则表达式:\w+ Pattern p = Pattern.compile("\\w+"); // 建立Matcher对象 Matcher m = p.matcher("asdfsadf@@2323"); // 尝试将整个字符序列与该模式匹配 // boolean yo = m.matches(); // 该方法扫描输入的序列,查找与该模式匹配的下一个子序列 while(m.find()){ // group()和group(0)都是匹配整个表达式的子字符串 System.out.println(m.group()); System.out.println(m.group(0)); } } }
测试正则表达式分组的处理
package com.sxt.regex; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @desc: | 测试正则表达式分组的处理 */ public class Demo02 { public static void main(String[] args) { // 在这个字符串:asdfsadf2323,是否符合制定的正则表达式:\w+ Pattern p = Pattern.compile("([a-z]+)([0-9]+)"); // 建立Matcher对象 Matcher m = p.matcher("asdfsa12**asd233**dsd11"); // 尝试将整个字符序列与该模式匹配 while (m.find()) { // group()和group(0)都是匹配整个表达式的子字符串 System.out.println("start---"); System.out.println("知足整个表达式的子字符串:"); System.out.println(m.group()); System.out.println("知足第1个括号中表达式的字符串:"); System.out.println(m.group(1)); System.out.println("知足第2个括号中表达式的字符串:"); System.out.println(m.group(2)); } } }
测试正则表达对象替换操做
package com.sxt.regex; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @desc: | 测试正则表达对象替换操做 */ public class Demo03 { public static void main(String[] args) { // 在这个字符串:asdfsadf2323,是否符合制定的正则表达式:\w+ Pattern p = Pattern.compile("[0-9]"); // 建立Matcher对象 Matcher m = p.matcher("asdfsa12**asd233**dsd11"); // 替换 String newStr = m.replaceAll("#"); System.out.println(newStr); } }
测试正则表达对象分割字符串的操做
package com.sxt.regex; import java.util.Arrays; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @desc: | 测试正则表达对象分割字符串的操做 */ public class Demo04 { public static void main(String[] args) { String str = "asdfsa12asd233dsd11"; // 切割 String[] arrs = str.split("\\d+"); System.out.println(Arrays.toString(arrs)); } }
package com.sxt.regex; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.MalformedURLException; import java.net.URL; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: WebSpider.java * @time: 2020/3/4 17:29 * @desc: |网络爬虫取数据 */ public class WebSpider { public static void main(String[] args) { String url = "http://www.163.com"; String destStr = getURLContent(url); // 取到的超连接的整个内容 // Pattern p = Pattern.compile("<a[\\s\\S]+?</a>"); // 取到的超连接的地址 // Pattern p = Pattern.compile("href=\"(.+?)\""); // 注意:上述?是非贪婪模式 // Matcher m = p.matcher(destStr); // while (m.find()) { // System.out.println(m.group()); // System.out.println("-----"); // System.out.println(m.group(1)); // } List<String> result = getMatherSubstrs(destStr, "href=\"(http://[\\w\\s./]+?)\""); for (String temp : result) { System.out.println(temp); } } public static String getURLContent(String loc) { /*得到url对应的网页源码内容*/ StringBuilder sb = new StringBuilder(); try { URL url = new URL(loc); BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream(), Charset.forName("gbk"))); String temp = ""; while ((temp = reader.readLine()) != null) { sb.append(temp); } } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return sb.toString(); } public static List<String> getMatherSubstrs(String destStr, String regexStr) { // 取到的超连接地址 Pattern p = Pattern.compile(regexStr); Matcher m = p.matcher(destStr); List<String> result = new ArrayList<>(); while (m.find()) { result.add(m.group(1)); } return result; } }
经常使用命令行操做
JDBC(Java Database Connection)为java开发者使用数据库提供了统一的编程接口,它由一组java类和接口组成。是java程序与数据库系统通讯的标准api。JDBC API使得开发人员能够使用纯java的方式来链接数据库,并执行操做。
访问数据库流程
Driver接口
Class.forName("com.mysql.jdbc.Driver");
Class.forName("oracle.jdbc.driver.OracleDriver")
DriverManager接口
Connection接口
Connection con = DriverManager.getConnection("jdbc:mysql://host:port/database", "user", "password");
Connection con = DriverManager.gtConnection("jdbc:oracle:thin:@host:port:database", "user", "password");
JDBC详细操做
链接测试
报错参考链接:解决方案
package com.sxt.jdbc; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Demo01.java * @time: 2020/3/5 12:48 * @desc: | 测试跟数据库创建链接 * 若是报错:参考链接:https://www.cnblogs.com/cn-chy-com/p/10145690.html */ public class Demo01 { public static void main(String[] args) { try { // 加载驱动类 Class.forName("com.mysql.cj.jdbc.Driver"); long start = System.currentTimeMillis(); // 创建链接(链接对象内部其实包含了Socket对象,是一个远程的链接。比较耗时!这是Connection对象管理的一个要点!) // 真正开发中,为了提升效率,都会使用链接池来管理链接对象! Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/testjdbc?serverTimezone=UTC", "root", "123456"); long end = System.currentTimeMillis(); System.out.println(conn); System.out.println("创建链接耗时:" + (end - start) + "ms毫秒"); } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); } } }
Statement接口
Statement测试执行sql语句以及sql注入问题
package com.sxt.jdbc; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Demo02.java * @time: 2020/3/5 12:48 * @desc: | 测试执行sql语句以及sql注入问题 */ public class Demo02 { public static void main(String[] args) { try { // 加载驱动类 Class.forName("com.mysql.cj.jdbc.Driver"); // 创建链接(链接对象内部其实包含了Socket对象,是一个远程的链接。比较耗时!这是Connection对象管理的一个要点!) // 真正开发中,为了提升效率,都会使用链接池来管理链接对象! Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/testjdbc?serverTimezone=UTC", "root", "123456"); Statement stmt = conn.createStatement(); String sql = "insert into t_user (username, pwd, regTime) values ('赵六', 6666, now())"; stmt.execute(sql); } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); } } }
sql注入问题:若要根据id删除一行记录,很容易出现数据库危险,好比要删除id=5的记录,传入的时候为id = 5 or 1 = 1
,最终致使数据库都被删除。
测试PreparedStatement的用法
package com.sxt.jdbc; import java.sql.*; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Demo01.java * @time: 2020/3/5 12:48 * @desc: | 测试PreparedStatement的基本用法 */ public class Demo03 { public static void main(String[] args) { try { // 加载驱动类 Class.forName("com.mysql.cj.jdbc.Driver"); Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/testjdbc?serverTimezone=UTC", "root", "123456"); // ?是占位符 String sql = "insert into t_user (username, pwd, regTime) values (?, ?, ?)"; PreparedStatement ps = conn.prepareStatement(sql); // 参数索引是从1开始计算,而不是0 // ps.setString(1, "傻瓜"); // ps.setString(2, "12345"); // 还能够无论类型直接setObject // ps.setObject(1, "傻瓜2"); // ps.setObject(2, "12344"); // 设置时间:注意该时间的格式应该是java.sql.Date ps.setObject(1, "傻瓜3"); ps.setObject(2, "12343"); ps.setObject(3, new java.sql.Date(System.currentTimeMillis())); System.out.println("插入一行记录"); // 返回是否有结果集 // ps.execute(); // 返回更新的行数 int count = ps.executeUpdate(); System.out.println(count); } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); } } }
关闭顺序:resultset-->statement-->connection
测试ResultSet结果集的用法
package com.sxt.jdbc; import java.sql.*; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @desc: | 测试ResultSet结果集的用法 * 记得要关闭打开的接口 */ public class Demo04 { public static void main(String[] args) { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; try { // 加载驱动类 Class.forName("com.mysql.cj.jdbc.Driver"); conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/testjdbc?serverTimezone=UTC", "root", "123456"); // ?是占位符 String sql = "select id, username, pwd from t_user where id>?"; ps = conn.prepareStatement(sql); // 把id>2的记录都取出来 ps.setObject(1, 2); rs = ps.executeQuery(); while (rs.next()) { // 数字表明哪一列 System.out.println(rs.getInt(1) + "-->" + rs.getString(2) + "-->" + rs.getString(3)); } } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); } finally { // 必定要将三个try catch分开写 if (rs != null) { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } if (ps != null) { try { ps.close(); } catch (SQLException e) { e.printStackTrace(); } } if (conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } } }
Batch批处理,尽可能使用Statement而不是PreparedStatement
package com.sxt.jdbc; import java.sql.*; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @desc: | 批处理 */ public class Demo05 { public static void main(String[] args) { Connection conn = null; Statement stmt = null; ResultSet rs = null; try { // 加载驱动类 Class.forName("com.mysql.cj.jdbc.Driver"); conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/testjdbc?serverTimezone=UTC", "root", "123456"); // 设为手动提交 conn.setAutoCommit(false); long start = System.currentTimeMillis(); stmt = conn.createStatement(); for (int i = 0; i < 20000; i++) { stmt.addBatch("insert into t_user (username, pwd, regTime) values ('li'" + ", 666666, now())"); stmt.executeBatch(); } // 提交事务 conn.commit(); long end = System.currentTimeMillis(); System.out.println("插入20000条数据,耗时(毫秒):" + (end - start)); } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); } finally { // 必定要将三个try catch分开写 if (rs != null) { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } if (stmt != null) { try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } } if (conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } } }
事务的基本概念:一组要么同时执行成功,要么同时执行失败的SQL语句。是数据库操做的一个执行单元。
事务开始于:
事务结束于:
事务的四大特性(ACID)
测试事务的基本用法
package com.sxt.jdbc; import java.sql.*; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @desc: | 测试事务的基本用法 */ public class Demo06 { public static void main(String[] args) { Connection conn = null; PreparedStatement ps1 = null; PreparedStatement ps2 = null; try { // 加载驱动类 Class.forName("com.mysql.cj.jdbc.Driver"); conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/testjdbc?serverTimezone=UTC", "root", "123456"); // JDBC默认是自动提交 conn.setAutoCommit(false); ps1 = conn.prepareStatement("insert into t_user (username, pwd) values (?, ?)"); ps1.setObject(1, "狗子"); ps1.setObject(2, "111"); ps1.execute(); System.out.println("插入一个用户1"); Thread.sleep(6000); ps2 = conn.prepareStatement("insert into t_user (username, pwd) values (?, ?, ?)"); ps2.setObject(1, "狗子2"); ps2.setObject(2, "111"); ps2.execute(); System.out.println("插入一个用户2"); conn.commit(); } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); try { conn.rollback(); } catch (SQLException ex) { ex.printStackTrace(); } } catch (InterruptedException e) { e.printStackTrace(); } finally { // 必定要将三个try catch分开写 if (ps1 != null) { try { ps1.close(); } catch (SQLException e) { e.printStackTrace(); } } if (ps2 != null) { try { ps2.close(); } catch (SQLException e) { e.printStackTrace(); } } if (conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } } }
时间类型
Date、Timestamp比较和插入随机日期
package com.sxt.jdbc; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.Random; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @desc: | 测试时间处理(java.sql.Date, java.sql.Time, java.sql.Timestamp) */ public class Demo07 { public static void main(String[] args) { Connection conn = null; PreparedStatement ps1 = null; try { // 加载驱动类 Class.forName("com.mysql.cj.jdbc.Driver"); conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/testjdbc?serverTimezone=UTC", "root", "123456"); for (int i = 0; i < 1000; i++) { ps1 = conn.prepareStatement("insert into t_user (username, pwd, regTime, lastLoginTime) values (?, ?, ?, ?)"); ps1.setObject(1, "狗子" + i); ps1.setObject(2, "111"); // 定义随机数 int rand = 10000000 + new Random().nextInt(1000000000); java.sql.Date date = new java.sql.Date(System.currentTimeMillis() - rand); ps1.setDate(3, date); // 若是须要插入制定日期,能够使用Calendar或DateFormat java.sql.Timestamp stamp = new java.sql.Timestamp(System.currentTimeMillis()); ps1.setTimestamp(4, stamp); ps1.execute(); } } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); try { conn.rollback(); } catch (SQLException ex) { ex.printStackTrace(); } } finally { // 必定要将三个try catch分开写 if (ps1 != null) { try { ps1.close(); } catch (SQLException e) { e.printStackTrace(); } } if (conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } } }
取出指定日期范围的记录
package com.sxt.jdbc; import java.sql.*; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @desc: | 测试时间处理,取出指定时间段的数据 */ public class Demo08 { public static void main(String[] args) { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; try { // 加载驱动类 Class.forName("com.mysql.cj.jdbc.Driver"); conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/testjdbc?serverTimezone=UTC", "root", "123456"); // 选择知足regTime条件的记录,Timestamp格式同理,把java.sql.Date改为java.sql.Timestamp便可getDate改为getTimestamp ps = conn.prepareStatement("select * from t_user where regTime>? and regTime<?"); java.sql.Date start = new java.sql.Date(str2Date("2020-3-1 10:23:45")); java.sql.Date end = new java.sql.Date(str2Date("2020-3-3 10:23:45")); ps.setObject(1, start); ps.setObject(2, end); rs = ps.executeQuery(); while(rs.next()){ System.out.println(rs.getInt("id") + "-->" + rs.getString("username") + "-->" + rs.getDate("regTime")); } } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); try { conn.rollback(); } catch (SQLException ex) { ex.printStackTrace(); } } finally { // 必定要将三个try catch分开写 if (rs != null) { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } if (ps != null) { try { ps.close(); } catch (SQLException e) { e.printStackTrace(); } } if (conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } } public static long str2Date(String dateStr){ /*将字符串表明的日期转为long数字(格式:yyyy-MM-dd hh:mm:ss)*/ DateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); try { return format.parse(dateStr).getTime(); } catch (ParseException e) { e.printStackTrace(); return 0; } } }
Character Large Object
用于存储大量的文本数据
大字段有些特殊,不一样数据库处理的方式不同,大字段的操做经常是以流的方式来处理的。而非通常的字段,一次便可读出数据。
Mysql中相关类型:
测试CLOB文本大对象的使用
包含:将字符串、文件内容插入数据库中的CLOB字段,将CLOB字段值取出来操做
package com.sxt.jdbc; import java.io.*; import java.sql.*; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @desc: | 测试CLOB文本大对象的使用 * 包含:将字符串、文件内容插入数据库中的CLOB字段,将CLOB字段值取出来操做 */ public class Demo09 { public static void main(String[] args) { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; try { // 加载驱动类 Class.forName("com.mysql.cj.jdbc.Driver"); conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/testjdbc?serverTimezone=UTC", "root", "123456"); ps = conn.prepareStatement("insert into t_user2 (username, myInfo) values (?, ?)"); ps.setString(1, "狗子"); // 将文本文件的内容直接输入到数据库中 // ps.setClob(2, new FileReader(new File("a1.txt"))); // 经过流的操做写入字符串内容 // ps.setClob(2, new BufferedReader(new InputStreamReader(new ByteArrayInputStream("aaaabbbb".getBytes())))); // ps.executeUpdate(); // 读取Clob字段 ps = conn.prepareStatement("select * from t_user2 where username=?"); ps.setObject(1, "狗子"); rs = ps.executeQuery(); while (rs.next()) { Clob c = rs.getClob("myInfo"); Reader r = c.getCharacterStream(); int temp = 0; while((temp = r.read()) != -1){ System.out.print((char)temp); } System.out.println(); } } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); try { conn.rollback(); } catch (SQLException ex) { ex.printStackTrace(); } } catch (IOException e) { e.printStackTrace(); } finally { // 必定要将三个try catch分开写 if (rs != null) { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } if (ps != null) { try { ps.close(); } catch (SQLException e) { e.printStackTrace(); } } if (conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } } }
Binary Large Object
用于存储大量的二进制数据
大字段有些特殊,不一样数据库处理的方式不同,大字段的操做经常是以流的方式来处理的。而非通常的字段,一次便可独处数据。
Mysql中相关类型与CLOB相似,只是将CLOB改成BLOB
测试BLOB二进制大对象的使用
package com.sxt.jdbc; import java.io.*; import java.sql.*; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @desc: | 测试BLOB二进制大对象的使用 */ public class Demo10 { public static void main(String[] args) { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; try { // 加载驱动类 Class.forName("com.mysql.cj.jdbc.Driver"); conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/testjdbc?serverTimezone=UTC", "root", "123456"); // ps = conn.prepareStatement("insert into t_user2 (username, headImg) values (?, ?)"); // ps.setString(1, "狗子2"); // 将图片文件的内容直接输入到数据库中 // ps.setBlob(2, new FileInputStream("test.png")); // ps.executeUpdate(); // 读取Blob字段 ps = conn.prepareStatement("select * from t_user2 where username=?"); ps.setObject(1, "狗子2"); rs = ps.executeQuery(); while (rs.next()) { Blob b = rs.getBlob("headImg"); InputStream is = b.getBinaryStream(); OutputStream os = new FileOutputStream("a1_input.png"); int temp = 0; while((temp = is.read()) != -1){ os.write(temp); } } } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); try { conn.rollback(); } catch (SQLException ex) { ex.printStackTrace(); } } catch (IOException e) { e.printStackTrace(); } finally { // 必定要将三个try catch分开写 if (rs != null) { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } if (ps != null) { try { ps.close(); } catch (SQLException e) { e.printStackTrace(); } } if (conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } } }
JDBC工具类
包括返回数据库驱动链接,关闭各个接口
package com.sxt.jdbc; import java.io.IOException; import java.sql.*; import java.util.Properties; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: JDBCUTIL.java * @time: 2020/3/8 19:43 * @desc: |JDBC工具类 */ public class JDBCUtil { // 能够帮助咱们读取和处理资源文件中的信息 private static Properties pros = null; static { /*静态代码块:只有在加载JDBCUtil类的时候调用一次*/ pros = new Properties(); try { pros.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("com/sxt/jdbc/db.properties")); } catch (IOException e) { e.printStackTrace(); } } public static Connection getMysqlConn() { /*获取数据库(mysql)驱动链接*/ // 加载驱动类 try { Class.forName(pros.getProperty("mysqlDriver")); return DriverManager.getConnection( pros.getProperty("mysqlURL"), pros.getProperty("mysqlUser"), pros.getProperty("mysqlPwd")); } catch (Exception e) { e.printStackTrace(); return null; } } public static Connection getOracleConn() { /*获取数据库(oracle)驱动链接*/ // 加载驱动类 try { Class.forName(pros.getProperty("oracleDriver")); return DriverManager.getConnection( pros.getProperty("oracleURL"), pros.getProperty("oracleUser"), pros.getProperty("oraclePwd")); } catch (Exception e) { e.printStackTrace(); return null; } } public static void close(ResultSet rs, Statement ps, Connection conn){ /*关闭接口方法*/ try { if (rs != null){ rs.close(); } } catch (Exception e) { e.printStackTrace(); } try { if (ps != null){ ps.close(); } } catch (Exception e) { e.printStackTrace(); } try { if (conn != null){ conn.close(); } } catch (Exception e) { e.printStackTrace(); } } public static void close(Statement ps, Connection conn){ /*关闭接口方法,重载*/ try { if (ps != null){ ps.close(); } } catch (Exception e) { e.printStackTrace(); } try { if (conn != null){ conn.close(); } } catch (Exception e) { e.printStackTrace(); } } public static void close(Connection conn){ /*关闭接口方法,重载*/ try { if (conn != null){ conn.close(); } } catch (Exception e) { e.printStackTrace(); } } }
配置文件封装
mysqlURL=jdbc:mysql://localhost:3306/testjdbc?serverTimezone=UTC #mysqlURL=jdbc:mysql://localhost:3306/sorm?serverTimezone=UTC mysqlDriver=com.mysql.cj.jdbc.Driver mysqlUser=root mysqlPwd=123456 oracleDriver=oracle.jdbc.driver.OracleDriver oracleURL=jdbc:oracle:thin:@localhost:1521:database oracleUser=scott oraclePwd=tiger
测试使用JDBCUtil工具类来简化JDBC开发
package com.sxt.jdbc; import java.sql.*; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @desc: | 测试使用JDBCUtil工具类来简化JDBC开发 */ public class Demo11 { public static void main(String[] args) { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; try { conn = JDBCUtil.getMysqlConn(); ps = conn.prepareStatement("insert into t_user (username) values (?)"); ps.setString(1, "hehe"); ps.execute(); } catch (Exception e) { e.printStackTrace(); } finally { JDBCUtil.close(rs, ps, conn); } } }
ORM的基本思想
将表中的一条记录封装到Object数组中
将表中的一条记录封装到map中
将表中的一条记录封装到javabean对象中
测试使用Object数组来封装一条记录,使用List<Object[]>存储多条记录
package com.sxt.testORM; import com.sxt.jdbc.JDBCUtil; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Demo01.java * @time: 2020/3/10 13:29 * @desc: |测试使用Object数组来封装一条记录 * 使用List<Object[]>存储多条记录 */ public class Demo01 { public static void main(String[] args) { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; List<Object[]> list = new ArrayList<>(); try { conn = JDBCUtil.getMysqlConn(); ps = conn.prepareStatement("select empname, salary, age from emp where id > ?"); ps.setObject(1, 0); rs = ps.executeQuery(); while (rs.next()) { // System.out.println(rs.getString(1) + "-->" + rs.getDouble(2) + "-->" + rs.getInt(3)); Object[] objs = new Object[3]; objs[0] = rs.getObject(1); objs[1] = rs.getObject(2); objs[2] = rs.getObject(3); list.add(objs); } } catch (SQLException e) { e.printStackTrace(); } finally { JDBCUtil.close(rs, ps, conn); } for (Object[] objs : list) { System.out.println(objs[0] + "-->" + objs[1] + "-->" + objs[2]); } } }
测试使用Map来封装一条记录,使用List<Map>
存储多条记录(也可用Map<Map>
)
package com.sxt.testORM; import com.sxt.jdbc.JDBCUtil; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @desc: |测试使用Map来封装一条记录 * 使用List<Map>存储多条记录(也可用Map<Map>) */ public class Demo02 { public static void main(String[] args) { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; // 使用一个Map封装一条记录 List<Map<String, Object>> list = new ArrayList<>(); try { conn = JDBCUtil.getMysqlConn(); ps = conn.prepareStatement("select empname, salary, age from emp where id > ?"); ps.setObject(1, 0); rs = ps.executeQuery(); while (rs.next()) { // System.out.println(rs.getString(1) + "-->" + rs.getDouble(2) + "-->" + rs.getInt(3)); Map<String, Object> row = new HashMap<>(); row.put("empname", rs.getString(1)); row.put("salary", rs.getString(2)); row.put("age", rs.getString(3)); list.add(row); } } catch (SQLException e) { e.printStackTrace(); } finally { JDBCUtil.close(rs, ps, conn); } // 遍历List和Map for (Map<String, Object> row : list) { for (String key : row.keySet()) { System.out.print(key + "-->" + row.get(key) + "\t\t"); } System.out.println(); } } }
使用Javabean对象来封装一条记录,使用List<Javabean>
存储多条记录
package com.sxt.testORM; import com.sxt.jdbc.JDBCUtil; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @desc: |使用Javabean对象来封装一条记录 * 使用List<Javabean>存储多条记录 */ public class Demo03 { public static void main(String[] args) { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; List<Emp> list = new ArrayList<>(); try { conn = JDBCUtil.getMysqlConn(); ps = conn.prepareStatement("select empname, salary, age from emp where id > ?"); ps.setObject(1, 0); rs = ps.executeQuery(); while (rs.next()) { // System.out.println(rs.getString(1) + "-->" + rs.getDouble(2) + "-->" + rs.getInt(3)); Emp emp = new Emp(rs.getString(1), rs.getInt(2), rs.getDouble(3)); list.add(emp); } } catch (SQLException e) { e.printStackTrace(); } finally { JDBCUtil.close(rs, ps, conn); } for (Emp e: list) { System.out.println(e); } } }
其中须要为每个表定义相同结构的类
Emp
package com.sxt.testORM; import java.sql.Date; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Emp.java * @time: 2020/3/10 14:35 * @desc: |表结构和类对应 */ public class Emp { private Integer id; private String empname; private Integer age; private Double salary; private Date birthday; private Integer deptId; public Emp(String empname, Integer age, Double salary) { this.empname = empname; this.age = age; this.salary = salary; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getEmpname() { return empname; } public void setEmpname(String empname) { this.empname = empname; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Double getSalary() { return salary; } public void setSalary(Double salary) { this.salary = salary; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public Integer getDeptId() { return deptId; } public void setDeptId(Integer deptId) { this.deptId = deptId; } public Emp(String empname, Integer age, Double salary, Date birthday, Integer deptId) { this.empname = empname; this.age = age; this.salary = salary; this.birthday = birthday; this.deptId = deptId; } public Emp(Integer id, String empname, Integer age, Double salary, Date birthday, Integer deptId) { this.id = id; this.empname = empname; this.age = age; this.salary = salary; this.birthday = birthday; this.deptId = deptId; } public Emp() { } @Override public String toString() { return empname + "-->" + age + "-->" + salary; } }
Dept
package com.sxt.testORM; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Dept.java * @time: 2020/3/10 14:38 * @desc: | */ public class Dept { private Integer id; private String dname; private String address; public Dept() { } public Dept(String dname, String address) { this.dname = dname; this.address = address; } public Dept(Integer id, String dname, String address) { this.id = id; this.dname = dname; this.address = address; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getDname() { return dname; } public void setDname(String dname) { this.dname = dname; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } }
Simple Object Relationship Mapping
咱们但愿设计一个能够实现对象和SQL自动映射的框架,可是总体用法和设计比Hibernate简单。砍掉没必要要的功能。
会穿插使用设计模式
从对象到sql
从sql到对象
List<Javabean>
核心架构:
架构图
核心bean,封装相关数据
针对SORM框架的说明:
bean
ColumnInfo
package com.sxt.SORM.bean; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: ColumnInfo.java * @time: 2020/3/11 13:46 * @desc: |封装表中一个字段的信息 */ public class ColumnInfo { // 字段名称 private String name; // 字段数据类型 private String dataType; // 字段的键类型(0普通键;1主键;2外键) private int keyType; public ColumnInfo() { } public ColumnInfo(String name, String dataType, int keyType) { this.name = name; this.dataType = dataType; this.keyType = keyType; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDataType() { return dataType; } public void setDataType(String dataType) { this.dataType = dataType; } public int getKeyType() { return keyType; } public void setKeyType(int keyType) { this.keyType = keyType; } }
Configuration
package com.sxt.SORM.bean; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Configuration.java * @time: 2020/3/11 13:55 * @desc: |管理配置信息 */ public class Configuration { // 正在使用哪一个数据库 private String usingDb; // jdbc的url private String URL; // 驱动类 private String driver; // 数据库的用户名 private String user; // 数据库的密码 private String pwd; // 项目的源码路径 private String srcPath; // 扫描生成java类的包(po的意思是Persistence Object持久化对象) private String poPackage; public Configuration() { } public Configuration(String usingDb, String URL, String driver, String user, String pwd, String srcPath, String poPackage) { this.usingDb = usingDb; this.URL = URL; this.driver = driver; this.user = user; this.pwd = pwd; this.srcPath = srcPath; this.poPackage = poPackage; } public String getUsingDb() { return usingDb; } public void setUsingDb(String usingDb) { this.usingDb = usingDb; } public String getURL() { return URL; } public void setURL(String URL) { this.URL = URL; } public String getDriver() { return driver; } public void setDriver(String driver) { this.driver = driver; } public String getUser() { return user; } public void setUser(String user) { this.user = user; } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } public String getSrcPath() { return srcPath; } public void setSrcPath(String srcPath) { this.srcPath = srcPath; } public String getPoPackage() { return poPackage; } public void setPoPackage(String poPackage) { this.poPackage = poPackage; } }
JavaFieldGetSet
package com.sxt.SORM.bean; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: JavaFieldGetSet.java * @time: 2020/3/11 18:24 * @desc: |封装了java属性和get、set方法的源代码 */ public class JavaFieldGetSet { // 属性源码信息。如:private int userId; private String fieldInfo; // get方法的源码信息。如:public int getUserId; private String getInfo; // set方法的源码信息。如:public void setUserId(int id){this.id = id;} private String setInfo; public JavaFieldGetSet() { } public JavaFieldGetSet(String fieldInfo, String getInfo, String setInfo) { this.fieldInfo = fieldInfo; this.getInfo = getInfo; this.setInfo = setInfo; } public String getFieldInfo() { return fieldInfo; } public void setFieldInfo(String fieldInfo) { this.fieldInfo = fieldInfo; } public String getGetInfo() { return getInfo; } public void setGetInfo(String getInfo) { this.getInfo = getInfo; } public String getSetInfo() { return setInfo; } public void setSetInfo(String setInfo) { this.setInfo = setInfo; } @Override public String toString() { // System.out.println(fieldInfo); // System.out.println(getInfo); // System.out.println(setInfo); return super.toString(); } }
TableInfo
package com.sxt.SORM.bean; import java.util.List; import java.util.Map; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: TableInfo.java * @time: 2020/3/11 13:56 * @desc: |存储表结构信息 */ public class TableInfo { // 表名 private String tname; // 全部字段的信息 private Map<String, ColumnInfo> columns; // 惟一主键(目前只能处理表中有且只有一个的状况) private ColumnInfo onlyPriKey; // 若是联合主键,则在这里存储 private List<ColumnInfo> priKeys; public TableInfo() { } public TableInfo(String tname, List<ColumnInfo> priKeys, Map<String, ColumnInfo> columns) { this.tname = tname; this.columns = columns; this.priKeys = priKeys; } public String getTname() { return tname; } public void setTname(String tname) { this.tname = tname; } public Map<String, ColumnInfo> getColumns() { return columns; } public void setColumns(Map<String, ColumnInfo> columns) { this.columns = columns; } public ColumnInfo getOnlyPriKey() { return onlyPriKey; } public void setOnlyPriKey(ColumnInfo onlyPriKey) { this.onlyPriKey = onlyPriKey; } public List<ColumnInfo> getPriKeys() { return priKeys; } public void setPriKeys(List<ColumnInfo> priKeys) { this.priKeys = priKeys; } }
core
Query
package com.sxt.SORM.core; import java.util.List; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Query.java * @time: 2020/3/10 17:31 * @desc: |负责查询(对外提供服务的核心类) */ public interface Query { /** * 直接执行一个DML语句 * * @param sql sql语句 * @param params 参数 * @return 执行sql语句后影响记录的行数 */ public int executeDML(String sql, Object[] params); /** * 将一个对象存储到数据库中 * * @param obj 要存储的对象 */ public void insert(Object obj); /** * 删除clazz表示类对应的表中的记录(指定主键id的记录) * 把对象中不为null的属性往数据库中存储!若是数字为null则放0 * @param clazz 跟表对应的类的Class对象 * @param id 主键的值 */ // delete from User where id = 2; public void delete(Class clazz, Object id); /** * 删除对象在数据库中对应的记录(对象所在类对应到表,对象的主键对应到的记录) * * @param obj */ public void delete(Object obj); /** * 更新对象对应的记录,而且只更新指定的字段的值 * * @param obj 索要更新的对象 * @param fieldNames 更新的属性列表 * @return 执行sql语句后影响记录的行数 */ // update user set uname=?, pwe=? public int update(Object obj, String[] fieldNames); /** * 查询返回多行记录,并将每行记录封装到clazz指定的类的对象中 * * @param sql 查询语句 * @param clazz 封装数据的javabean类的Class对象 * @param params sql的参数 * @return 返回查询到的结果 */ public List queryRows(String sql, Class clazz, Object[] params); /** * 查询返回一行记录,并将该记录封装到clazz指定的类的对象中 * * @param sql 查询语句 * @param clazz 封装数据的javabean类的Class对象 * @param params sql的参数 * @return 返回查询到的结果 */ public Object queryUniqueRows(String sql, Class clazz, Object[] params); /** * 查询返回一个值(一行一列),并将该值返回 * * @param sql 查询语句 * @param params sql的参数 * @return 返回查询到的结果 */ public Object queryValue(String sql, Object[] params); /** * 查询返回一个数字(一行一列),并将该值返回 * * @param sql 查询语句 * @param params sql的参数 * @return 返回查询到的数字 */ public Number queryNumber(String sql, Object[] params); }
MysqlQuery
package com.sxt.SORM.core; import com.sxt.SORM.bean.ColumnInfo; import com.sxt.SORM.bean.TableInfo; import com.sxt.SORM.po.Emp; import com.sxt.SORM.utils.JDBCUtils; import com.sxt.SORM.utils.ReflectUtils; import com.sxt.SORM.vo.EmpVO; import java.lang.reflect.Field; import java.sql.*; import java.util.ArrayList; import java.util.List; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: MysqlQuery.java * @time: 2020/3/13 16:54 * @desc: |负责针对mysql数据库的查询 */ public class MysqlQuery implements Query { public static void main(String[] args) { Object obj = new MysqlQuery().queryValue("select count(*) from emp where salary>?", new Object[]{1000}); System.out.println(obj); } /** * 复杂多行查询测试 */ public static void testQueryRows() { List<Emp> list = new MysqlQuery().queryRows("select id,empname,age from emp where age>? and salary<?", Emp.class, new Object[]{1, 9000}); for (Emp e : list) { System.out.println(e.getEmpname()); } String sql2 = "select e.id,e.empname,salary+bonus 'xinshui',age,d.dname 'deptName',d.address 'deptAddr' from emp e" + " " + "join dept d on e.deptId=d.id;"; List<EmpVO> list2 = new MysqlQuery().queryRows(sql2, EmpVO.class, null); for (EmpVO e : list2) { System.out.println(e.getEmpname() + "-" + e.getDeptAddr() + "-" + e.getXinshui()); } } /** * 增删改操做测试 */ public static void testDML() { Emp e = new Emp(); e.setEmpname("Tom"); e.setBirthday(new java.sql.Date(System.currentTimeMillis())); e.setAge(30); e.setSalary(8888.0); e.setId(1); // new MysqlQuery().delete(e); // new MysqlQuery().insert(e); new MysqlQuery().update(e, new String[]{"empname", "age", "salary"}); } @Override public int executeDML(String sql, Object[] params) { Connection conn = DBManager.getConn(); int count = 0; PreparedStatement ps = null; try { ps = conn.prepareStatement(sql); // 给sql设置参数,就是?位置的参数 JDBCUtils.handleParams(ps, params); count = ps.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); } finally { DBManager.close(ps, conn); } return count; } @Override public void insert(Object obj) { // obj --> 表中。 insert into 表名(id, name, pwd) values (?, ?, ?) Class c = obj.getClass(); // 存储sql的参数对象 List<Object> params = new ArrayList<>(); TableInfo tableInfo = TableContext.poClassTableMap.get(c); StringBuilder sql = new StringBuilder("insert into " + tableInfo.getTname() + " ("); // 计算不为空的属性值 int countNotNullField = 0; // 目前只能处理数据库来维护自增的方式 Field[] fs = c.getDeclaredFields(); for (Field f : fs) { String fieldName = f.getName(); Object fieldValue = ReflectUtils.invokeGet(fieldName, obj); if (fieldValue != null) { // 若是该属性值不为空 countNotNullField++; sql.append(fieldName + ","); params.add(fieldValue); } } // 把最后一个属性后面的,换成) sql.setCharAt(sql.length() - 1, ')'); sql.append(" values ("); for (int i = 0; i < countNotNullField; i++) { sql.append("?,"); } sql.setCharAt(sql.length() - 1, ')'); executeDML(sql.toString(), params.toArray()); } @Override public void delete(Class clazz, Object id) { // Emp.class, 2 --> delete from emp where id=2 // 经过Class对象找TableInfo TableInfo tableInfo = TableContext.poClassTableMap.get(clazz); // 得到主键 ColumnInfo onlyPriKey = tableInfo.getOnlyPriKey(); String sql = "delete from " + tableInfo.getTname() + " where " + onlyPriKey.getName() + "=?;"; executeDML(sql, new Object[]{id}); } @Override public void delete(Object obj) { Class c = obj.getClass(); TableInfo tableInfo = TableContext.poClassTableMap.get(c); // 得到主键 ColumnInfo onlyPriKey = tableInfo.getOnlyPriKey(); // 经过反射机制,调用属性对应的get方法或set方法 Object priKeyValue = ReflectUtils.invokeGet(onlyPriKey.getName(), obj); delete(obj.getClass(), priKeyValue); } @Override public int update(Object obj, String[] fieldNames) { // obj{"uname", "pwd} --> update 表名 set uname=?, pwd=? where id=? Class c = obj.getClass(); List<Object> params = new ArrayList<>(); TableInfo tableInfo = TableContext.poClassTableMap.get(c); ColumnInfo priKey = tableInfo.getOnlyPriKey(); StringBuilder sql = new StringBuilder("update " + tableInfo.getTname() + " set "); for (String fname : fieldNames) { Object fvalue = ReflectUtils.invokeGet(fname, obj); params.add(fvalue); sql.append(fname + "=?,"); } sql.setCharAt(sql.length() - 1, ' '); sql.append(" where "); sql.append(priKey.getName() + "=?"); params.add(ReflectUtils.invokeGet(priKey.getName(), obj)); return executeDML(sql.toString(), params.toArray()); } @Override public List queryRows(String sql, Class clazz, Object[] params) { Connection conn = DBManager.getConn(); // 存放查询结果的容器 List list = null; PreparedStatement ps = null; ResultSet rs = null; try { ps = conn.prepareStatement(sql); // 给sql设置参数,就是?位置的参数 JDBCUtils.handleParams(ps, params); rs = ps.executeQuery(); ResultSetMetaData metaData = rs.getMetaData(); // 多行 while (rs.next()) { if (list == null) { list = new ArrayList(); } // 调用javabean的无参构造器 Object rowObj = clazz.newInstance(); // 多列 select username, pwd, age from user where id>? and age>? for (int i = 0; i < metaData.getColumnCount(); i++) { // username String columnName = metaData.getColumnLabel(i + 1); Object columnValue = rs.getObject(i + 1); // 调用rowObj对象的setUsername(String uname)方法,将columnValue的值设置进去 ReflectUtils.invokeSet(rowObj, columnName, columnValue); } list.add(rowObj); } } catch (Exception e) { e.printStackTrace(); } finally { DBManager.close(ps, conn); } return list; } @Override public Object queryUniqueRows(String sql, Class clazz, Object[] params) { List list = queryRows(sql, clazz, params); return (list == null && list.size() > 0) ? null : list.get(0); } @Override public Object queryValue(String sql, Object[] params) { Connection conn = DBManager.getConn(); // 存储查询结果的对象 Object value = null; PreparedStatement ps = null; ResultSet rs = null; try { ps = conn.prepareStatement(sql); // 给sql设置参数,就是?位置的参数 JDBCUtils.handleParams(ps, params); rs = ps.executeQuery(); // 多行 while (rs.next()) { // select count(*) from user value = rs.getObject(1); } } catch (Exception e) { e.printStackTrace(); } finally { DBManager.close(ps, conn); } return value; } @Override public Number queryNumber(String sql, Object[] params) { return (Number) queryValue(sql, params); } }
TypeConvertor
package com.sxt.SORM.core; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: TypeConvertor.java * @time: 2020/3/11 13:39 * @desc: |负责java数据类型和数据库数据类型的互相转换 */ public interface TypeConvertor { /** * 将数据库数据类型转化成java的数据类型 * @param columnType 数据库字段的数据类型 * @return java的数据类型 */ public String databaseType2JavaType(String columnType); /** * 将java数据类型转化为数据库数据类型 * @param javaDataType java数据类型 * @return 数据库数据类型 */ public String javaType2DatabaseType(String javaDataType); }
MySqlTypeConvertor
package com.sxt.SORM.core; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: MySqlTypeConvertor.java * @time: 2020/3/11 18:16 * @desc: |mysql数据类型和java数据类型的转换 */ public class MySqlTypeConvertor implements TypeConvertor { @Override public String databaseType2JavaType(String columnType) { // varchar --> String if ("varchar".equalsIgnoreCase(columnType) || "char".equalsIgnoreCase(columnType)) { return "String"; } else if ("int".equalsIgnoreCase(columnType) || "tinyint".equalsIgnoreCase(columnType) || "smallint".equalsIgnoreCase(columnType) || "integer".equalsIgnoreCase(columnType)) { return "Integer"; } else if ("bigint".equalsIgnoreCase(columnType)) { return "long"; } else if ("double".equalsIgnoreCase(columnType) || "float".equalsIgnoreCase(columnType)) { return "Double"; } else if ("clob".equalsIgnoreCase(columnType)) { return "java.sql.Clob"; } else if ("blob".equalsIgnoreCase(columnType)) { return "java.sql.Blob"; }else if("date".equalsIgnoreCase(columnType)){ return "java.sql.Date"; }else if("time".equalsIgnoreCase(columnType)){ return "java.sql.Time"; }else if("timestamp".equalsIgnoreCase(columnType)){ return "java.sql.Timestamp"; } return null; } @Override public String javaType2DatabaseType(String javaDataType) { return null; } }
DBManager
package com.sxt.SORM.core; import com.sxt.SORM.bean.Configuration; import java.io.IOException; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; import java.util.Properties; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: DBManager.java * @time: 2020/3/11 13:43 * @desc: |根据配置信息,维持链接对象的管理(增长链接池功能) */ public class DBManager { private static Configuration conf; static { // 静态代码块 Properties pros = new Properties(); try { pros.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("com/sxt/SORM/db.properties")); } catch (IOException e) { e.printStackTrace(); } conf = new Configuration(); conf.setDriver(pros.getProperty("driver")); conf.setPoPackage(pros.getProperty("poPackage")); conf.setPwd(pros.getProperty("pwd")); conf.setSrcPath(pros.getProperty("srcPath")); conf.setURL(pros.getProperty("URL")); conf.setUser(pros.getProperty("user")); conf.setUsingDb(pros.getProperty("usingDB")); } public static Connection getConn() { /*获取数据库(mysql)驱动链接*/ // 加载驱动类 try { Class.forName(conf.getDriver()); // 直接创建链接,后期增长链接池处理,提升效率! return DriverManager.getConnection(conf.getURL(), conf.getUser(), conf.getPwd()); } catch (Exception e) { e.printStackTrace(); return null; } } public static void close(ResultSet rs, Statement ps, Connection conn) { /*关闭接口方法*/ try { if (rs != null) { rs.close(); } } catch (Exception e) { e.printStackTrace(); } try { if (ps != null) { ps.close(); } } catch (Exception e) { e.printStackTrace(); } try { if (conn != null) { conn.close(); } } catch (Exception e) { e.printStackTrace(); } } public static void close(Statement ps, Connection conn) { /*关闭接口方法,重载*/ try { if (ps != null) { ps.close(); } } catch (Exception e) { e.printStackTrace(); } try { if (conn != null) { conn.close(); } } catch (Exception e) { e.printStackTrace(); } } public static void close(Connection conn) { /*关闭接口方法,重载*/ try { if (conn != null) { conn.close(); } } catch (Exception e) { e.printStackTrace(); } } public static Configuration getConf(){ return conf; } }
TableContext
package com.sxt.SORM.core; import com.sxt.SORM.bean.ColumnInfo; import com.sxt.SORM.bean.TableInfo; import com.sxt.SORM.utils.JavaFileUtils; import com.sxt.SORM.utils.StringUtils; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: TableContext.java * @time: 2020/3/11 13:42 * @desc: |负责获取管理数据库全部表结构和类结构的关系,并能够根据表结构生成类结结构 */ public class TableContext { // 表名为key,表信息对象为value public static Map<String, TableInfo> tables = new HashMap<>(); // 将po的calss对象和表信息对象关联起来,便于重用。 public static Map<Class, TableInfo> poClassTableMap = new HashMap<>(); private TableContext() { } static { try { // 初始化得到的表信息 Connection conn = DBManager.getConn(); DatabaseMetaData dbmd = conn.getMetaData(); ResultSet tableSet = dbmd.getTables("", "%", "%", new String[]{"TABLE"}); while (tableSet.next()) { // 循环每一个表名 String tableName = (String) tableSet.getObject("TABLE_NAME"); TableInfo ti = new TableInfo(tableName, new ArrayList<ColumnInfo>(), new HashMap<String, ColumnInfo>()); tables.put(tableName, ti); // 查询表中的全部字段 ResultSet set = dbmd.getColumns("", "%", tableName, "%"); while (set.next()) { // 循环每一个列名 ColumnInfo ci = new ColumnInfo(set.getString("COLUMN_NAME"), set.getString("TYPE_NAME"), 0); ti.getColumns().put(set.getString("COLUMN_NAME"), ci); } // 查询表中的主键 // System.out.println(tableName); ResultSet set2 = dbmd.getPrimaryKeys("", "%", tableName); while (set2.next()) { ColumnInfo ci2 = (ColumnInfo) ti.getColumns().get(set2.getObject("COLUMN_NAME")); // 设置为主键类型 ci2.setKeyType(1); ti.getPriKeys().add(ci2); } if (ti.getPriKeys().size() > 0) { // 取惟一主键。方便使用。若是是联合主键。则为空! ti.setOnlyPriKey(ti.getPriKeys().get(0)); } } } catch (Exception e) { e.printStackTrace(); } // 更新类结构 updateJavaPOFile(); // 加载po包下面的全部类,便于重用,提升效率! loadPOTables(); } /** * 根据表结构,更新配置的po包下面的java类 */ public static void updateJavaPOFile() { Map<String, TableInfo> map = TableContext.tables; for (TableInfo t : map.values()) { JavaFileUtils.createJavaPOFile(t, new MySqlTypeConvertor()); } } /** * 加载po包下面的类 */ public static void loadPOTables() { for (TableInfo tableInfo : tables.values()) { try { Class c = Class.forName(DBManager.getConf().getPoPackage() + "." + StringUtils.firstChar2UpperCase(tableInfo.getTname())); poClassTableMap.put(c, tableInfo); } catch (ClassNotFoundException e) { e.printStackTrace(); } } } public static void main(String[] args) { Map<String, TableInfo> tables = TableContext.tables; System.out.println(tables); } }
utils
JavaFileUtils
package com.sxt.SORM.utils; import com.sxt.SORM.bean.ColumnInfo; import com.sxt.SORM.bean.JavaFieldGetSet; import com.sxt.SORM.bean.TableInfo; import com.sxt.SORM.core.DBManager; import com.sxt.SORM.core.MySqlTypeConvertor; import com.sxt.SORM.core.TableContext; import com.sxt.SORM.core.TypeConvertor; import java.io.*; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: JavaFileUtils.java * @time: 2020/3/11 13:44 * @desc: | 封装了生成java文件(源代码)经常使用操做 */ public class JavaFileUtils { /** * 根据字段信息生成java属性信息。如varchar username --> private String username;以及相应的set和get方法源码 * * @param column 字段信息 * @param convertor 类型转化器 * @return java属性和set/get方法源码 */ public static JavaFieldGetSet createFieldGetSetSRC(ColumnInfo column, TypeConvertor convertor) { JavaFieldGetSet jfgs = new JavaFieldGetSet(); String javaFieldType = convertor.databaseType2JavaType(column.getDataType()); jfgs.setFieldInfo("\tprivate " + javaFieldType + " " + column.getName() + ";\n"); // public String getUsername(){return username;} StringBuilder getSrc = new StringBuilder(); getSrc.append("\tpublic " + javaFieldType + " get" + StringUtils.firstChar2UpperCase(column.getName()) + "(){\n"); getSrc.append("\t\treturn " + column.getName() + ";\n"); getSrc.append("\t}\n"); jfgs.setGetInfo(getSrc.toString()); // public void setUsername(String username){this.username = username;} StringBuilder setSrc = new StringBuilder(); setSrc.append("\tpublic void set" + StringUtils.firstChar2UpperCase(column.getName()) + "("); setSrc.append(javaFieldType + " " + column.getName() + "){\n"); setSrc.append("\t\tthis." + column.getName() + " = " + column.getName() + ";\n"); setSrc.append("\t}\n"); jfgs.setSetInfo(setSrc.toString()); return jfgs; } /** * 根据表信息生成java类的源代码 * * @param tableInfo 表信息 * @param convertor 数据类型转化器 * @return java类的源代码 */ public static String createJavaSrc(TableInfo tableInfo, TypeConvertor convertor) { Map<String, ColumnInfo> columns = tableInfo.getColumns(); List<JavaFieldGetSet> javaFields = new ArrayList<>(); for (ColumnInfo c : columns.values()) { javaFields.add(createFieldGetSetSRC(c, convertor)); } StringBuilder src = new StringBuilder(); // 生成package语句 src.append("package " + DBManager.getConf().getPoPackage() + ";\n\n"); // 生成import语句 src.append("import java.sql.*;\n"); src.append("import java.util.*;\n\n"); // 生成类声明语句 src.append("public class " + StringUtils.firstChar2UpperCase(tableInfo.getTname()) + " {\n\n"); // 生成属性列表 for (JavaFieldGetSet f : javaFields) { src.append(f.getFieldInfo()); } src.append("\n\n"); // 生成set方法列表 for (JavaFieldGetSet f : javaFields) { src.append(f.getSetInfo()); } // 生成get方法列表 for (JavaFieldGetSet f : javaFields) { src.append(f.getGetInfo()); } // 生成类结束 src.append("}\n"); // System.out.println(src); return src.toString(); } public static void createJavaPOFile(TableInfo tableInfo, TypeConvertor convertor) { String src = createJavaSrc(tableInfo, convertor); String srcPath = DBManager.getConf().getSrcPath() + "\\"; String packagePath = DBManager.getConf().getPoPackage().replaceAll("\\.", "/"); // 修正poPackage路径,由于没有从新建立项目 String[] packagePath_list = packagePath.split("/"); packagePath = packagePath_list[packagePath_list.length - 1]; File f = new File(srcPath + packagePath); // System.out.println(f.getAbsolutePath()); if (!f.exists()) { // 指定目录不存在则帮助用户创建该目录 f.mkdirs(); } BufferedWriter bw = null; try { bw = new BufferedWriter(new FileWriter(f.getAbsolutePath() + "/" + StringUtils.firstChar2UpperCase(tableInfo.getTname()) + ".java")); bw.write(src); System.out.println("创建表" + tableInfo.getTname() + "对应的java类"); bw.flush(); } catch (Exception e) { e.printStackTrace(); } finally { try { if (bw != null) { bw.close(); } } catch (IOException e) { e.printStackTrace(); } } } public static void main(String[] args) { // 测试每个表的field,set、get方法源码生成 // ColumnInfo ci = new ColumnInfo("username", "int", 0); // JavaFieldGetSet f = createFieldGetSetSRC(ci, new MySqlTypeConvertor()); // System.out.println(f); // System.out.println("\n--------------------" + "分割线" + "--------------------\n"); // 测试每个表的从头至尾彻底源码生成 // Map<String, TableInfo> map = TableContext.tables; // TableInfo t = map.get("emp"); // createJavaSrc(t, new MySqlTypeConvertor()); Map<String, TableInfo> map = TableContext.tables; // TableInfo t = map.get("emp"); for(TableInfo t: map.values()) { createJavaPOFile(t, new MySqlTypeConvertor()); } } }
JDBCUtils
package com.sxt.SORM.utils; import java.sql.PreparedStatement; import java.sql.SQLException; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: JDBCUtils.java * @time: 2020/3/11 13:43 * @desc: | 封装了JDBC查询经常使用的操做 */ public class JDBCUtils { /** * 给sql设置参数,就是?位置的参数 * @param ps 预编译sql语句对象 * @param params 参数 */ public static void handleParams(PreparedStatement ps, Object[] params) { if (params != null) { for (int i = 0; i < params.length; i++) { try { ps.setObject(1 + i, params[i]); } catch (SQLException e) { e.printStackTrace(); } } } } }
StringUtils
package com.sxt.SORM.utils; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: StringUtils.java * @time: 2020/3/11 13:44 * @desc: | 封装了字符串经常使用的操做 */ public class StringUtils { /** * 将目标字符串首字母变为大写 * @param str 目标字符串 * @return 首字母变为大写的字符串 */ public static String firstChar2UpperCase(String str){ // abcd-->Abcd return str.toUpperCase().substring(0, 1) + str.substring(1); } }
ReflectUtils
package com.sxt.SORM.utils; import java.lang.reflect.Method; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: ReflectUtils.java * @time: 2020/3/11 13:44 * @desc: | 封装了反射的经常使用操做 */ public class ReflectUtils { /** * 调用obj对象对应属性fieldName的get方法 * * @param fieldName 属性名 * @param obj Object对象 * @return */ public static Object invokeGet(String fieldName, Object obj) { // 经过反射机制,调用属性对应的get方法或set方法 try { Class c = obj.getClass(); Method m = c.getDeclaredMethod("get" + StringUtils.firstChar2UpperCase(fieldName), null); return m.invoke(obj, null); } catch (Exception e) { e.printStackTrace(); return null; } } public static void invokeSet(Object obj, String columnName, Object columnValue) { try { if (columnValue != null) { Method m = obj.getClass().getDeclaredMethod("set" + StringUtils.firstChar2UpperCase(columnName), columnValue.getClass()); m.invoke(obj, columnValue); } } catch (Exception e) { e.printStackTrace(); } } }
po(自动生成的代码保存位置)
Dept
package com.sxt.SORM.po; public class Dept { private String address; private Integer id; private String dname; public void setAddress(String address){ this.address = address; } public void setId(Integer id){ this.id = id; } public void setDname(String dname){ this.dname = dname; } public String getAddress(){ return address; } public Integer getId(){ return id; } public String getDname(){ return dname; } }
Emp
package com.sxt.SORM.po; public class Emp { private String empname; private java.sql.Date birthday; private Double bonus; private Integer deptId; private Integer id; private Double salary; private Integer age; public String getEmpname() { return empname; } public void setEmpname(String empname) { this.empname = empname; } public java.sql.Date getBirthday() { return birthday; } public void setBirthday(java.sql.Date birthday) { this.birthday = birthday; } public Double getBonus() { return bonus; } public void setBonus(Double bonus) { this.bonus = bonus; } public Integer getDeptId() { return deptId; } public void setDeptId(Integer deptId) { this.deptId = deptId; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public Double getSalary() { return salary; } public void setSalary(Double salary) { this.salary = salary; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } }
vo(复杂查询生成的类所保存的位置)
EmpVO
package com.sxt.SORM.vo; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: EmpVO.java * @time: 2020/3/15 12:44 * @desc: | */ public class EmpVO { // select e.id,e.empname,salary+bonus 'xinshui',age,d.dname 'deptName',d.address 'deptAddr' from emp e // join dept d on e.deptId=d.id; private Integer id; private String empname; private Double xinshui; private Integer age; private String deptName; private String deptAddr; public EmpVO() { } public EmpVO(Integer id, String empname, Double xinshui, Integer age, String deptName, String deptAddr) { this.id = id; this.empname = empname; this.xinshui = xinshui; this.age = age; this.deptName = deptName; this.deptAddr = deptAddr; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getEmpname() { return empname; } public void setEmpname(String empname) { this.empname = empname; } public Double getXinshui() { return xinshui; } public void setXinshui(Double xinshui) { this.xinshui = xinshui; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getDeptName() { return deptName; } public void setDeptName(String deptName) { this.deptName = deptName; } public String getDeptAddr() { return deptAddr; } public void setDeptAddr(String deptAddr) { this.deptAddr = deptAddr; } }
配置文件(db.properties)
usingDB=mysql URL=jdbc:mysql://localhost:3306/sorm?serverTimezone=UTC driver=com.mysql.cj.jdbc.Driver user=root pwd=123456 srcPath=F:/BookStudy/else/JAVAPro/src/com/sxt/SORM poPackage=com.sxt.SORM.po
README(说明文件)
1. 在src下创建db.properties 2. 每张表只有一个主键,不能处理多个主键的状况 3. po尽可能使用包装类,不要使用基本数据类型 4. 目前只能处理数据库来维护自增的方式
Query
package com.sxt.SORM.core; import com.sxt.SORM.bean.ColumnInfo; import com.sxt.SORM.bean.TableInfo; import com.sxt.SORM.utils.JDBCUtils; import com.sxt.SORM.utils.ReflectUtils; import java.lang.reflect.Field; import java.sql.*; import java.util.ArrayList; import java.util.List; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Query.java * @time: 2020/3/10 17:31 * @desc: |负责查询(对外提供服务的核心类) */ public abstract class Query implements Cloneable { /** * 采用模板方法模式将JDBC操做封装成模板,变于重用 * * @param sql sql语句 * @param params sql的参数 * @param clazz 记录要封装到的java类 * @param back CallBack的实现类,实现回调 * @return 返回查询结果 */ public Object executeQueryTemplate(String sql, Object[] params, Class clazz, CallBack back) { Connection conn = DBManager.getConn(); // 存放查询结果的容器 PreparedStatement ps = null; ResultSet rs = null; try { ps = conn.prepareStatement(sql); // 给sql设置参数,就是?位置的参数 JDBCUtils.handleParams(ps, params); rs = ps.executeQuery(); ResultSetMetaData metaData = rs.getMetaData(); return back.doExecute(conn, ps, rs); } catch (Exception e) { e.printStackTrace(); return null; } finally { DBManager.close(ps, conn); } } /** * 直接执行一个DML语句 * * @param sql sql语句 * @param params 参数 * @return 执行sql语句后影响记录的行数 */ public int executeDML(String sql, Object[] params) { Connection conn = DBManager.getConn(); int count = 0; PreparedStatement ps = null; try { ps = conn.prepareStatement(sql); // 给sql设置参数,就是?位置的参数 JDBCUtils.handleParams(ps, params); count = ps.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); } finally { DBManager.close(ps, conn); } return count; } /** * 将一个对象存储到数据库中 * * @param obj 要存储的对象 */ public void insert(Object obj) { // obj --> 表中。 insert into 表名(id, name, pwd) values (?, ?, ?) Class c = obj.getClass(); // 存储sql的参数对象 List<Object> params = new ArrayList<>(); TableInfo tableInfo = TableContext.poClassTableMap.get(c); StringBuilder sql = new StringBuilder("insert into " + tableInfo.getTname() + " ("); // 计算不为空的属性值 int countNotNullField = 0; // 目前只能处理数据库来维护自增的方式 Field[] fs = c.getDeclaredFields(); for (Field f : fs) { String fieldName = f.getName(); Object fieldValue = ReflectUtils.invokeGet(fieldName, obj); if (fieldValue != null) { // 若是该属性值不为空 countNotNullField++; sql.append(fieldName + ","); params.add(fieldValue); } } // 把最后一个属性后面的,换成) sql.setCharAt(sql.length() - 1, ')'); sql.append(" values ("); for (int i = 0; i < countNotNullField; i++) { sql.append("?,"); } sql.setCharAt(sql.length() - 1, ')'); executeDML(sql.toString(), params.toArray()); } /** * 删除clazz表示类对应的表中的记录(指定主键id的记录) * 把对象中不为null的属性往数据库中存储!若是数字为null则放0 * * @param clazz 跟表对应的类的Class对象 * @param id 主键的值 */ // delete from User where id = 2; public void delete(Class clazz, Object id) { // Emp.class, 2 --> delete from emp where id=2 // 经过Class对象找TableInfo TableInfo tableInfo = TableContext.poClassTableMap.get(clazz); // 得到主键 ColumnInfo onlyPriKey = tableInfo.getOnlyPriKey(); String sql = "delete from " + tableInfo.getTname() + " where " + onlyPriKey.getName() + "=?;"; executeDML(sql, new Object[]{id}); } /** * 删除对象在数据库中对应的记录(对象所在类对应到表,对象的主键对应到的记录) * * @param obj */ public void delete(Object obj) { Class c = obj.getClass(); TableInfo tableInfo = TableContext.poClassTableMap.get(c); // 得到主键 ColumnInfo onlyPriKey = tableInfo.getOnlyPriKey(); // 经过反射机制,调用属性对应的get方法或set方法 Object priKeyValue = ReflectUtils.invokeGet(onlyPriKey.getName(), obj); delete(obj.getClass(), priKeyValue); } /** * 更新对象对应的记录,而且只更新指定的字段的值 * * @param obj 索要更新的对象 * @param fieldNames 更新的属性列表 * @return 执行sql语句后影响记录的行数 */ // update user set uname=?, pwe=? public int update(Object obj, String[] fieldNames) { // obj{"uname", "pwd} --> update 表名 set uname=?, pwd=? where id=? Class c = obj.getClass(); List<Object> params = new ArrayList<>(); TableInfo tableInfo = TableContext.poClassTableMap.get(c); ColumnInfo priKey = tableInfo.getOnlyPriKey(); StringBuilder sql = new StringBuilder("update " + tableInfo.getTname() + " set "); for (String fname : fieldNames) { Object fvalue = ReflectUtils.invokeGet(fname, obj); params.add(fvalue); sql.append(fname + "=?,"); } sql.setCharAt(sql.length() - 1, ' '); sql.append(" where "); sql.append(priKey.getName() + "=?"); params.add(ReflectUtils.invokeGet(priKey.getName(), obj)); return executeDML(sql.toString(), params.toArray()); } /** * 查询返回多行记录,并将每行记录封装到clazz指定的类的对象中 * * @param sql 查询语句 * @param clazz 封装数据的javabean类的Class对象 * @param params sql的参数 * @return 返回查询到的结果 */ public List queryRows(final String sql, final Class clazz, final Object[] params) { // 存放查询结果的容器 return (List) executeQueryTemplate(sql, params, clazz, new CallBack() { @Override public Object doExecute(Connection conn, PreparedStatement ps, ResultSet rs) { List list = null; try { ResultSetMetaData metaData = rs.getMetaData(); // 多行 while (rs.next()) { if (list == null) { list = new ArrayList(); } // 调用javabean的无参构造器 Object rowObj = clazz.newInstance(); // 多列 select username, pwd, age from user where id>? and age>? for (int i = 0; i < metaData.getColumnCount(); i++) { // username String columnName = metaData.getColumnLabel(i + 1); Object columnValue = rs.getObject(i + 1); // 调用rowObj对象的setUsername(String uname)方法,将columnValue的值设置进去 ReflectUtils.invokeSet(rowObj, columnName, columnValue); } list.add(rowObj); } } catch (Exception e) { e.printStackTrace(); } return list; } }); } /** * 查询返回一行记录,并将该记录封装到clazz指定的类的对象中 * * @param sql 查询语句 * @param clazz 封装数据的javabean类的Class对象 * @param params sql的参数 * @return 返回查询到的结果 */ public Object queryUniqueRows(String sql, Class clazz, Object[] params) { List list = queryRows(sql, clazz, params); return (list != null || list.size() > 0) ? list.get(0) : null; } /** * 根据主键的值直接查找对应的对象 * @param clazz * @param id * @return */ public Object queryById(Class clazz, Object id){ // select * from emp where id=? TableInfo tableInfo = TableContext.poClassTableMap.get(clazz); ColumnInfo onlyPriKey = tableInfo.getOnlyPriKey(); String sql = "select * from " + tableInfo.getTname() + " where " + onlyPriKey.getName() + "=?"; return queryUniqueRows(sql, clazz, new Object[]{id}); } /** * 查询返回一个值(一行一列),并将该值返回 * * @param sql 查询语句 * @param params sql的参数 * @return 返回查询到的结果 */ public Object queryValue(String sql, Object[] params) { return executeQueryTemplate(sql, params, null, new CallBack() { @Override public Object doExecute(Connection conn, PreparedStatement ps, ResultSet rs) { Object value = null; try { // 多行 while (rs.next()) { // select count(*) from user value = rs.getObject(1); } } catch (Exception e) { e.printStackTrace(); } return value; } }); } /** * 查询返回一个数字(一行一列),并将该值返回 * * @param sql 查询语句 * @param params sql的参数 * @return 返回查询到的数字 */ public Number queryNumber(String sql, Object[] params) { return (Number) queryValue(sql, params); } /** * 分页查询 * * @param pageNum 第几页数据 * @param size 每页显示多少记录 * @return */ public abstract Object queryPagenate(int pageNum, int size); @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } }
MysqlQuery
package com.sxt.SORM.core; import com.sxt.SORM.po.Emp; import com.sxt.SORM.vo.EmpVO; import java.util.List; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: MysqlQuery.java * @time: 2020/3/13 16:54 * @desc: |负责针对mysql数据库的查询 */ public class MysqlQuery extends Query { public static void main(String[] args) { Object obj = new MysqlQuery().queryValue("select count(*) from emp where salary>?", new Object[]{1000}); System.out.println(obj); } /** * 复杂多行查询测试 */ public static void testQueryRows() { List<Emp> list = new MysqlQuery().queryRows("select id,empname,age from emp where age>? and salary<?", Emp.class, new Object[]{1, 9000}); for (Emp e : list) { System.out.println(e.getEmpname()); } String sql2 = "select e.id,e.empname,salary+bonus 'xinshui',age,d.dname 'deptName',d.address 'deptAddr' from emp e" + " " + "join dept d on e.deptId=d.id;"; List<EmpVO> list2 = new MysqlQuery().queryRows(sql2, EmpVO.class, null); for (EmpVO e : list2) { System.out.println(e.getEmpname() + "-" + e.getDeptAddr() + "-" + e.getXinshui()); } } /** * 增删改操做测试 */ public static void testDML() { Emp e = new Emp(); e.setEmpname("Tom"); e.setBirthday(new java.sql.Date(System.currentTimeMillis())); e.setAge(30); e.setSalary(8888.0); e.setId(1); // new MysqlQuery().delete(e); // new MysqlQuery().insert(e); new MysqlQuery().update(e, new String[]{"empname", "age", "salary"}); } @Override public Object queryPagenate(int pageNum, int size) { return null; } }
修改db.properties,增长queryClass的路径
queryClass=com.sxt.SORM.core.MysqlQuery
修改Configuration,增长queryClass的属性,getset方法
// 项目使用的查询类的路径 private String queryClass; public String getQueryClass() { return queryClass; } public void setQueryClass(String queryClass) { this.queryClass = queryClass; }
Query实现implements Cloneable接口
public abstract class Query implements Cloneable protected Object clone() throws CloneNotSupportedException { return super.clone(); }
QueryFactory
package com.sxt.SORM.core; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: QueryFactory.java * @time: 2020/3/11 13:33 * @desc: |建立Query对象的工厂类:单例+克隆+工厂 */ public class QueryFactory { private static QueryFactory factory = new QueryFactory(); // 原型对象 private static Query prototypeObj; static{ try { // 加载指定的Query类 Class c = Class.forName(DBManager.getConf().getQueryClass()); prototypeObj = (Query) c.newInstance(); } catch (Exception e) { e.printStackTrace(); } } // 私有构造器 private QueryFactory(){} public static Query createQuery(){ try { return (Query) prototypeObj.clone(); } catch (Exception e) { e.printStackTrace(); return null; } } }
客户端调用测试类
package com.sxt.SORM.test; import com.sxt.SORM.core.MysqlQuery; import com.sxt.SORM.core.Query; import com.sxt.SORM.core.QueryFactory; import com.sxt.SORM.vo.EmpVO; import java.util.List; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Test.java * @time: 2020/3/17 12:55 * @desc: |客户端调用测试类 */ public class Test { public static void main(String[] args){ Query q = QueryFactory.createQuery(); String sql2 = "select e.id,e.empname,salary+bonus 'xinshui',age,d.dname 'deptName',d.address 'deptAddr' from emp e" + " " + "join dept d on e.deptId=d.id;"; List<EmpVO> list2 = q.queryRows(sql2, EmpVO.class, null); for (EmpVO e : list2) { System.out.println(e.getEmpname() + "-" + e.getDeptAddr() + "-" + e.getXinshui()); } } }
Connection Pool
就是将Connection对象放入List中,反复重用!
链接池的初始化:事先放入多个链接对象
从链接池中取链接对象
关闭链接
不是真正关闭链接,而是将用完的链接放入链接池中。
市面上的链接池产品:
代码
配置文件新增链接池参数
poolMinSize=10 poolMaxSize=100
Configuration增长上述参数的属性和getset方法
// 链接池最小限制 private int poolMinSize; // 链接池最大限制 private int poolMaxSize; public int getPoolMinSize() { return poolMinSize; } public void setPoolMinSize(int poolMinSize) { this.poolMinSize = poolMinSize; } public int getPoolMaxSize() { return poolMaxSize; } public void setPoolMaxSize(int poolMaxSize) { this.poolMaxSize = poolMaxSize; }
新增链接池类:DBConnPool
package com.sxt.SORM.pool; import com.sxt.SORM.core.DBManager; import java.sql.Connection; import java.util.ArrayList; import java.util.List; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: DBConnPool.java * @time: 2020/3/17 14:03 * @desc: |链接池的类 */ public class DBConnPool { // 最大链接数 private static final int POOL_MAX_SIZE = DBManager.getConf().getPoolMaxSize(); // 最小链接数 private static final int POOL_MIN_SIZE = DBManager.getConf().getPoolMinSize(); // 链接池对象 private List<Connection> pool; public DBConnPool() { initPool(); } /** * 初始化链接池,使池中的链接数达到最小值 */ public void initPool() { if (pool == null) { pool = new ArrayList<Connection>(); } while (pool.size() < DBConnPool.POOL_MIN_SIZE) { pool.add(DBManager.createConn()); System.out.println("初始化池,池中链接数:" + pool.size()); } } /** * 从链接池中取出一个链接 */ public synchronized Connection getConnection() { int last_index = pool.size() - 1; // 得到一个链接 Connection conn = pool.get(last_index); pool.remove(last_index); return conn; } /** * 将链接放回池中 * * @param conn */ public synchronized void close(Connection conn) { if (pool.size() >= POOL_MAX_SIZE) { try { if (conn != null) { conn.close(); } } catch (Exception e) { e.printStackTrace(); } } else { pool.add(conn); } } }
修改DBManager方法,把原来获取链接的方式,改成使用链接池,关闭链接的方式也作一样的修改
package com.sxt.SORM.core; import com.sxt.SORM.bean.Configuration; import com.sxt.SORM.pool.DBConnPool; import java.io.IOException; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; import java.util.Properties; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: DBManager.java * @time: 2020/3/11 13:43 * @desc: |根据配置信息,维持链接对象的管理(增长链接池功能) */ public class DBManager { // 配置信息 private static Configuration conf; // 链接池对象 private static DBConnPool pool; static { // 静态代码块 Properties pros = new Properties(); try { pros.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("com/sxt/SORM/db.properties")); } catch (IOException e) { e.printStackTrace(); } conf = new Configuration(); conf.setDriver(pros.getProperty("driver")); conf.setPoPackage(pros.getProperty("poPackage")); conf.setPwd(pros.getProperty("pwd")); conf.setSrcPath(pros.getProperty("srcPath")); conf.setURL(pros.getProperty("URL")); conf.setUser(pros.getProperty("user")); conf.setUsingDb(pros.getProperty("usingDB")); conf.setQueryClass(pros.getProperty("queryClass")); conf.setPoolMaxSize(Integer.parseInt(pros.getProperty("poolMaxSize"))); conf.setPoolMinSize(Integer.parseInt(pros.getProperty("poolMinSize"))); // 加载TableContext System.out.println(TableContext.class); } public static Connection getConn() { /*获取数据库(mysql)驱动链接*/ // 加载驱动类 /* 第一种方法:直接取 try { Class.forName(conf.getDriver()); // 直接创建链接,后期增长链接池处理,提升效率! return DriverManager.getConnection(conf.getURL(), conf.getUser(), conf.getPwd()); } catch (Exception e) { e.printStackTrace(); return null; } */ // 第二种方法,经过链接池 if(pool == null){ pool = new DBConnPool(); } return pool.getConnection(); } /** * 建立新的Connection链接 * * @return */ public static Connection createConn() { /*获取数据库(mysql)驱动链接*/ // 加载驱动类 try { Class.forName(conf.getDriver()); // 直接创建链接,后期增长链接池处理,提升效率! return DriverManager.getConnection(conf.getURL(), conf.getUser(), conf.getPwd()); } catch (Exception e) { e.printStackTrace(); return null; } } public static void close(ResultSet rs, Statement ps, Connection conn) { /**关闭接口方法*/ try { if (rs != null) { rs.close(); } } catch (Exception e) { e.printStackTrace(); } try { if (ps != null) { ps.close(); } } catch (Exception e) { e.printStackTrace(); } try { // if (conn != null) { // conn.close(); // } pool.close(conn); } catch (Exception e) { e.printStackTrace(); } } public static void close(Statement ps, Connection conn) { /**关闭接口方法,重载*/ try { if (ps != null) { ps.close(); } } catch (Exception e) { e.printStackTrace(); } try { // if (conn != null) { // conn.close(); // } pool.close(conn); } catch (Exception e) { e.printStackTrace(); } } public static void close(Connection conn) { /*关闭接口方法,重载*/ try { // if (conn != null) { // conn.close(); // } pool.close(conn); } catch (Exception e) { e.printStackTrace(); } } public static Configuration getConf() { return conf; } }
客户端测试
package com.sxt.SORM.test; import com.sxt.SORM.core.Query; import com.sxt.SORM.core.QueryFactory; import com.sxt.SORM.vo.EmpVO; import java.util.List; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Test2.java * @time: 2020/3/17 16:40 * @desc: |测试链接池的调用效率 */ public class Test2 { public static void test1(){ Query q = QueryFactory.createQuery(); String sql2 = "select e.id,e.empname,salary+bonus 'xinshui',age,d.dname 'deptName',d.address 'deptAddr' from emp e" + " " + "join dept d on e.deptId=d.id;"; List<EmpVO> list2 = q.queryRows(sql2, EmpVO.class, null); for (EmpVO e : list2) { System.out.println(e.getEmpname() + "-" + e.getDeptAddr() + "-" + e.getXinshui()); } } public static void main(String[] args){ long a = System.currentTimeMillis(); for (int i = 0; i < 3000; i++) { test1(); } long b = System.currentTimeMillis(); // 不加链接池的耗时:13077ms,增长链接池以后,耗时为2478 System.out.println(b-a); } }
idea导出参考链接:https://blog.csdn.net/rico_rico/article/details/84936785
javadoc导出参考链接:https://blog.csdn.net/qq_29347295/article/details/78635861
其中编码须要改成:-encoding utf-8 -charset utf-8
测试使用
配置配置文件
usingDB=mysql URL=jdbc:mysql://localhost:3306/sorm?serverTimezone=UTC driver=com.mysql.cj.jdbc.Driver user=root pwd=123456 srcPath=F:/BookStudy/else/SORMDemo/src poPackage=po queryClass=com.sxt.SORM.core.MysqlQuery poolMinSize=10 poolMaxSize=100
测试po类的生成,增删改查
package test; import com.sxt.SORM.core.Query; import com.sxt.SORM.core.QueryFactory; import po.Emp; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Test.java * @time: 2020/3/17 17:38 * @desc: | */ public class Test { public static void main(String[] args) { // 经过这个方法能够生成po类 // TableContext.updateJavaPOFile(); // add(); // select(); // delete(); update(); } public static void add() { // 测试插入对象 Emp e = new Emp(); e.setAge(18); e.setEmpname("我"); e.setSalary(2000.0); Query q = QueryFactory.createQuery(); q.insert(e); } public static void delete(){ // 测试删除对象 Emp e = new Emp(); e.setId(12); Query q = QueryFactory.createQuery(); q.delete(e); } public static void update(){ // 测试删除对象 Emp e = new Emp(); e.setId(1); e.setAge(1); Query q = QueryFactory.createQuery(); q.update(e, new String[]{"age"}); } public static void select(){ // 测试查询 Query q = QueryFactory.createQuery(); Number n = q.queryNumber("select count(*) from emp where salary>?", new Object[]{100}); System.out.println(n); } }
关于连表查询,我看操做实在是过于复杂,还要本身创建EmpVO,想一想就算了。
个人CSDN:https://blog.csdn.net/qq_21579045
个人博客园:https://www.cnblogs.com/lyjun/
个人Github:https://github.com/TinyHandsome
纸上得来终觉浅,绝知此事要躬行~
欢迎你们过来OB~
by 李英俊小朋友