-
JAVA DAO
2013-04-16 19:49:56DAO的组成 1.实体 一个java类,这个类与数据库中的表对应。 比如,table_user表与User类对应: 对应关系指的是: table_user表名与User类名对应 table_user表的列(column)与User类的属性对应...DAO的组成
1.实体
一个java类,这个类与数据库中的表对应。
比如,table_user表与User类对应:
对应关系指的是:
table_user表名与User类名对应
table_user表的列(column)与User类的属性对应table_user表中的一条记录与User类的一个实例对应
2.数据库
数据库的创建,链接。
3.dao接口
声明一系列方法(即对数据库进行哪些操作--crud),
这些方法应该与具体的技术无关。
3.dao实现实现dao接口的一个具体类DaoImpl
4.dao的代理
对象访问的管理
5.工厂
提供符合接口定义的对象,调用者不用关心对象的创建细节。也就是说,通过工厂,可以将调用者与要调用的对象解耦了。
显示层->DAO.HTML:
<html> <head><title>DAO</title></head> <body> <form action="createEmp.jsp" method="post"> <table> <tr> <td>用户名:</td> <td><input type="text" name="user" width="20px"/></td> </tr> <tr> <td>密码:</td> <td><input type="password" name="password"/></td> </tr> <tr> <td>邮箱:</td> <td><input type="text" name="email"/></td> </tr> <tr> <td><input type="submit" value=" 注册"/></td> <td><input type="reset" value="重置"/></td> </tr> </table> </form> </body> </html>
控制层->createEmp.jsp
<%@page contentType="text/html" pageEncoding="GBK"%> <%@page import="DAO.VO.Emp"%> <html> <head><title>createEmp</title></head> <body> <center>hello</center> <jsp:useBean id="emp" class="DAO.VO.Emp" /> <jsp:useBean id="factory" class="DAO.Factory.EmpDAOFactory" /> <% String user = request.getParameter("user"); String pass = request.getParameter("password"); String email = request.getParameter("email"); emp = new Emp(user,pass,email); /*emp.setUser(user); emp.setPassword(pass); emp.setEmail(email);*/ factory.instance().createEmp(emp); %> <%="user->"+user%><br /> <%="pass->"+pass%><br /> <%="email->"+email%><br /> </body> </html>
实体VO->emp.java:package DAO.VO; public class Emp { private int id; private String user; private String password; private String email; public Emp(){ } public Emp(String user,String password,String email){ this.user = user; this.password = password; this.email = email; } public Emp(int id,String user,String password,String email){ this.id = id; this.user = user; this.password = password; this.email = email; } public void setID(int id){ this.id = id; } public void setUser(String user){ this.user = user; } public void setPassword(String password){ this.password = password; } public void setEmail(String email){ this.email = email; } public int getID(){ return this.id; } public String getUser(){ return user; } public String getPassword(){ return password; } public String getEmail(){ return email; } /*public static void main(String[] args){ Emp e = new Emp(); e.setID(2); e.setUser("hua"); e.setPassword("aaaaa.0"); e.setEmail("980914629@qq.com"); println("ID:"+e.getID()); println("User:"+e.getUser()); println("Password:"+e.getPassword()); println("Email:"+e.getEmail()); } public static void println(Object obj){ System.out.println(obj); }*/ }
数据库->DatabaseConnection.java:package DAO.DBC; import java.sql.*; public class DatabaseConnection { private static final String DRIVER = "org.gjt.mm.mysql.Driver"; private static final String DBURL = "jdbc:mysql://localhost:3306/emp"; private static final String DBUSER = "scott"; private static final String DBPASSWORD = "tiger"; private static Connection conn; public DatabaseConnection()throws Exception{ Class.forName(DRIVER);//驱动加载 conn = DriverManager.getConnection(DBURL,DBUSER,DBPASSWORD);//连接数据库 } public Connection getConnection(){ return conn; } public void close()throws Exception{ conn.close(); } /*public static void main(String[] args)throws Exception { DatabaseConnection dc = new DatabaseConnection(); dc.connection(); printf(dc.getConnection()); Connection conn = dc.getConnection(); Statement state = conn.createStatement(); state.executeUpdate("use study");//首先要使用哪个数据库 ResultSet result = state.executeQuery("select * from emp"); while(result.next()){ printf(result.getObject("id")); printf(result.getObject("user")); printf(result.getObject("password")); printf(result.getObject("email")); } dc.close(); } public static void printf(Object obj){ System.out.println(obj); }*/ }
DAO接口->IEmpDAO.java:package DAO.IEmpDAO; import DAO.VO.*; import java.util.*; public interface IEmpDAO { public boolean createEmp(Emp emp)throws Exception; public List<Emp> findAll(String keyWord)throws Exception; public Emp findByID(int id)throws Exception; }
DAO实现类->EmpDAOImpl.java:package DAO.EmpDAOImpl; import DAO.VO.*; import DAO.IEmpDAO.*; import java.util.*; import java.sql.*; public class EmpDAOImpl implements IEmpDAO { private Connection conn; PreparedStatement preStatement; ResultSet result; public EmpDAOImpl(Connection conn){ preStatement = null; result = null; this.conn = conn; } public boolean createEmp(Emp e)throws Exception{ preStatement = conn.prepareStatement("INSERT INTO emp(user,password,email) VALUES(?,?,?)"); preStatement.setString(1,e.getUser()); preStatement.setString(2,e.getPassword()); preStatement.setString(3,e.getEmail()); preStatement.execute("use study");//先使用哪个数据库 preStatement.execute(); preStatement.close(); return true; } public List<Emp> findAll(String keyWord)throws Exception{ List <Emp> emps = new ArrayList<Emp>(); preStatement = conn.prepareStatement("select * from emp where user like ? or password like ?"); preStatement.setString(1,"%"+keyWord+"%"); preStatement.setString(2,"%"+keyWord+"%"); preStatement.execute("use study");//先使用哪个数据库 result = preStatement.executeQuery(); while(result.next()){ Emp emp = new Emp(result.getInt("id"), result.getString("user"), result.getString("password"), result.getString("email") ); emps.add(emp); } preStatement.close(); return emps; } public Emp findByID(int id)throws Exception{ Emp emp = null; preStatement = conn.prepareStatement("select * from emp where id=?"); preStatement.setInt(1,id); result = preStatement.executeQuery(); while(result.next()){ emp = new Emp(result.getInt("id"), result.getString("user"), result.getString("password"), result.getString("email") ); } preStatement.close(); return emp; } public boolean findEmp(String user)throws Exception{ List <Emp> emps = new ArrayList<Emp>(); preStatement = conn.prepareStatement("select * from emp where user=?"); preStatement.setString(1,user); preStatement.execute("use study"); result = preStatement.executeQuery(); while(result.next()){ String userTemp = result.getString("user"); if(user.equals(userTemp)){ preStatement.close(); return true; } } preStatement.close(); return false; } /*public static void main(String[] args)throws Exception{ EmpDAOImpl edi = new EmpDAOImpl(new DatabaseConnection().getConnection()); edi.createEmp(new Emp("hua1","aaaaa.0","435501646@qq.com")); List <Emp> emps = edi.findAll("hu"); for(int i=0;i<emps.size();i++){ printf(emps.get(i).getID()+" "); printf(emps.get(i).getUser()+" "); printf(emps.get(i).getPassword()+" "); printfln(emps.get(i).getEmail()); } Emp emp; emp = edi.findByID(5); printf(emp.getID()+" "); printf(emp.getUser()+" "); printf(emp.getPassword()+" "); printfln(emp.getEmail()); } public static void printf(Object obj){ System.out.print(obj); } public static void printfln(Object obj){ System.out.println(obj); }*/ }
DAO代理->EmpDAOProxy.java:package DAO.EmpProxy; import DAO.VO.*; import DAO.IEmpDAO.*; import DAO.DBC.*; import DAO.EmpDAOImpl.*; import java.util.*; public class EmpDAOProxy implements IEmpDAO { private DatabaseConnection dc; private EmpDAOImpl edi; public EmpDAOProxy()throws Exception{ dc = new DatabaseConnection(); edi = new EmpDAOImpl(dc.getConnection()); } public boolean createEmp(Emp emp){ try { if(!edi.findEmp(emp.getUser())) edi.createEmp(emp); else return false; } catch (Exception e) { } finally { try { dc.close(); } catch (Exception e) { } } return true; } public List<Emp> findAll(String keyWord){ List<Emp> emps = new ArrayList<Emp>(); try { emps = edi.findAll(keyWord); } catch (Exception e) { } return emps; } public Emp findByID(int id){ Emp emp = null; try { emp = edi.findByID(id); } catch (Exception e) { } return emp; } /*public static void main(String[] args){ System.out.println("Hello World!"); }*/ public static void printf(Object obj){ System.out.print(obj); } public static void printfln(Object obj){ System.out.println(obj); } }
DAO工厂->EmpDAOFactory.java:package DAO.Factory; import DAO.VO.*; import DAO.EmpProxy.*; public class EmpDAOFactory { public static EmpDAOProxy instance()throws Exception{ return new EmpDAOProxy(); } }
我觉得对于初学者,如果是为了测试一下这种的设计模式,最后一步一步来,免得出麻烦,搞到头都大,像我那些注释的那样,都是一步一步来的,虽然可能有点慢,但是自己会更加注意那些细节,而且如果一下子写完的话,如果出错了,那时候头就大了,
不要看到那些代码都是一下子出现你面前,你就要一下子写完它,应该理解之后,再一步一步慢慢写,这样才能有好的收获的。
<pre name="code" class="java"><pre name="code" class="java"><pre name="code" class="java"><pre name="code" class="java"><pre name="code" class="java"><pre>
-
java DAO
2013-04-10 17:30:02J2EE组件层次 客户端->表示层—>表示层-->业务层--->数据层---->数据库 DAO属于J2EE数据层的操作,即在DAO中封装了一个表在一个项目中所应该具有的全部操作。J2EE组件层次
客户端->表示层—>表示层-->业务层--->数据层---->数据库
DAO属于J2EE数据层的操作,即在DAO中封装了一个表在一个项目中所应该具有的全部操作。
-
Java Dao模式
2016-11-15 09:58:55Java Dao模式什么是DAO
DAO是Data Access Object数据访问接口,数据访问:故名思义就是与数据库打交道。夹在业务逻辑与数据库资源中间。
DAO的功能:
1. DAO用来封装Data Source的..就比如,Connection conn = DriverManager.getConnection(...) . . . . . .
就可以把DriverManager. username, passpword这一些放在DAO中
以后要更改 数 据 库 的类型.比如要把SQL Server换成Oracle的话..只需要更改DAO里面的getConnection()里面的连接字符串之类的..
2. DAO也是把对数据库的操作(比如最基本的更新, 添加等操作)全部封装在里面..
比如说你要你要插入一个新的用户..那么.在DAO中我们只需要提供一个insertUser(User user)这一个方法就可以了..具体的操作是在DaoImpl中实现的...
那么对于要调用DAO的时候.我们只要知道insertUser(User)是用来插入一个新的用户...而不需要知道是如何实现的。
一个典型的 DAO 实现有以下组件:
一个 DAO 工厂类
一个 DAO 接口
一个实现了 DAO 接口的具体类
数据传输对象(实体对象 , 比如 pet, dog, Penguin 等)
在设计 DAO 时,首先要思考以下问题:
程序如何开始?
程序开始需要干什么?
程序的过程?
程序如何结束?
程序结束又需要干什么?
Dao是否要负责程序的开始和结束
设计Dao模式
Dao接口: 位于dao包中, 把对数据库操作的所有方法定义在该接口中
Dao实现类:位于 dao.impl 包中 , 针对不同的数据库(比如SQLServer , Oracle 等不同数据库)给出Dao接口中定义的方法的具体实现
实体类: 位于 entity包中,作用是传递数据
通常还会增加一个数据库工具类,用于连接数据库和关闭资源等 -
javaDAO模式学习总结
2017-11-02 09:38:13javaDAO模式学习总结-戚爱斌 DAO模式入门 1.什么是DAO模式 DAO模式是标准的J2EE设计模式之一.开发人员使用这个模式把底层的数据访问操作和上层的业务逻辑分开,此模式的主要作用是封装对数据库的各种操作; 2.DAO...DAO模式入门
1.什么是DAO模式
DAO模式是标准的J2EE设计模式之一.开发人员使用这个模式把底层的数据访问操作和上层的业务逻辑分开,此模式的主要作用是封装对数据库的各种操作;
2.DAO模式的组成部分
- VO:值对象,此对象只包含属性,而没有方法;代表数据库中表中的一条记录,一个VO与一个表是相对应的
- DAO接口:定义对某个VO的所有操作
- DAO实现类:DAO接口的具体实现
- DAO工厂类:用来创建出DAO对象(可以没有)
3.案例代码
项目结构
说明
- Book:图书表的VO类
- BaseDao:所有DAO的父类,封装了所有DAO中可以使用的的通用方法
- BookDao:图书的数据访问接口,定义了对图书表操作的所有方法
- BookDaoImp:BookDao的实现类;
- DaoTest:测试方法
4.部分代码
book.java
package com.oracle.vo; public class Book { private Integer isbn; //图书编号 private String bookName;//书名 private Integer price;//价格 @Override public String toString() { return "Book [isbn=" + isbn + ", bookName=" + bookName + ", price=" + price + "]"; } public Integer getIsbn() { return isbn; } public void setIsbn(Integer isbn) { this.isbn = isbn; } public String getBookName() { return bookName; } public void setBookName(String bookName) { this.bookName = bookName; } public Integer getPrice() { return price; } public void setPrice(Integer price) { this.price = price; } public Book(String bookName, Integer price) { super(); this.bookName = bookName; this.price = price; } public Book() { super(); } }
BaseDao.java/** * 所有Dao的父类 */ package com.oracle.dao; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.*; public class BaseDao { //获得连接 public Connection getConnection() { Connection conn=null; try { conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/books","root","tiger"); } catch (SQLException e) { e.printStackTrace(); } return conn; } /** * 关闭资源 * @param auto,jdk7后的接口 */ public void close(AutoCloseable auto) { if(auto!=null) { try { auto.close(); } catch (Exception e) { e.printStackTrace(); } } } /** * 动态执行sql * @param sql:预编译的sql * @param objs:可变参数 */ public void executeSql(String sql,Object...objs) { //获得连接 Connection conn=this.getConnection(); PreparedStatement ps=null; try { ps=conn.prepareStatement(sql); //设置参数 for(int i=0;i<objs.length;i++) { ps.setObject(i+1, objs[i]); } //执行sql ps.execute(); }catch(Exception e) { e.printStackTrace(); }finally { this.close(ps); this.close(conn); } } /** * 执行一条select语名,并且将返回结果封装到List中,每条记录对一个Map * @param sql:sql查询语句,可带参数(?) * @param objs:可变参数 * @return */ public List<Map<String,Object>> executeQuery(String sql,Object...objs){ List<Map<String,Object>> list=new ArrayList<Map<String,Object>>(); Connection conn=this.getConnection(); PreparedStatement ps=null; ResultSet rs=null; try { ps=conn.prepareStatement(sql); for(int i=0;i<objs.length;i++) { ps.setObject(i+1, objs[i]); } //执行查询 rs=ps.executeQuery(); //获得元数据 ResultSetMetaData rsmd=rs.getMetaData(); //将每条记录转成一个Map,key是列名,value是字段值 while(rs.next()) { Map<String,Object> map=new HashMap<String,Object>(); for(int i=1;i<=rsmd.getColumnCount();i++) { map.put(rsmd.getColumnLabel(i), rs.getObject(i)); } list.add(map); } }catch(Exception e) { e.printStackTrace(); }finally { this.close(rs); this.close(ps); this.close(conn); } return list; } }
BookDao.javapackage com.oracle.dao; import java.util.List; import com.oracle.vo.Book; public interface BookDao { //插入图书 public void save(Book book); //修改图书 public void update(Book book); //删除图书 public void delete(int isbn); //查询所有图书 public List<Book> getAll(); //根据图书编号获得图书 public Book getBookById(int isbn); //分页查询图书 public List<Book> getAllByPage(int pageNumber,int pageSize); }
BookDaoImpl.javapackage com.oracle.dao; import java.util.ArrayList; import java.util.List; import java.util.Map; import com.oracle.vo.Book; public class BookDaoImpl extends BaseDao implements BookDao { @Override /** * 插入图书 */ public void save(Book book) { this.executeSql("insert into book values(null,?,?)", book.getBookName(),book.getPrice()); } @Override /** * 修改图书 */ public void update(Book book) { this.executeSql("update book set bookName=?,price=? where isbn=?", book.getBookName(),book.getPrice(),book.getIsbn()); } @Override /** * 删除图书 */ public void delete(int isbn) { this.executeSql("delete from book where isbn=?", isbn); } @Override /** * 获得所有的图书 */ public List<Book> getAll() { return this.convert(this.executeQuery("select isbn,bookName,price from book")); } @Override /** * 根据主键获得唯一的图书 */ public Book getBookById(int isbn) { List<Book> list=this.convert(this.executeQuery("select isbn,bookName,price from book where isbn=?",isbn)); return list.isEmpty()?null:list.get(0); } @Override /** * 分页查询 */ public List<Book> getAllByPage(int pageNumber, int pageSize) { return this.convert(this.executeQuery("select isbn,bookName,price from book order by isbn limit ?,?",(pageNumber-1)*pageSize,pageSize)); } /** * 将Map转成Book * @param list * @return */ private List<Book> convert(List<Map<String,Object>> list){ List<Book> bList=new ArrayList<Book>(); for(Map<String,Object> map:list) { Book b=new Book(); b.setIsbn((Integer)map.get("isbn")); b.setBookName(map.get("bookName").toString()); b.setPrice((Integer)map.get("price")); bList.add(b); } return bList; } }
DaoTest.javapackage com.oracle.test; import java.util.List; import com.oracle.dao.BookDao; import com.oracle.dao.BookDaoImpl; import com.oracle.vo.Book; public class DaoTest { public static void main(String[] args) { BookDao dao = new BookDaoImpl(); // 插入图书测试 Book book = new Book("把球交给薛庭政", 3); dao.save(book); //修改图书 book.setIsbn(5600); book.setBookName("大话数据结构"); dao.update(book); // 删除图书 dao.delete(569); // 查询所有图书 List<Book> list = dao.getAll(); for (Book b : list) { System.out.println(b); } System.out.println("---------"); // 查询一本图书 System.out.println(dao.getBookById(666)); //分页查询 list = dao.getAllByPage(2, 5); for (Book b : list) { System.out.println(b); } } }
源码下载
-
java DAO设计模式
2016-03-14 22:37:25java DAO设计模式 分类: dao [html] view plain copy print? DAO 数据访问对象 属于JAVAEE的数据层的操作 用来完成数据库的访问,实现基本的CURD数据库... -
JavaDAO设计模式学习总结
2018-11-16 21:52:05JavaDAO模式基础 1.DAO模式理解 DAO模式是J2EE设计模式之一,开发人员为了降低耦合性,把底层的数据访问操作和上层的业务逻辑分开,此设计模式的主要作用是封装对数据库的操作; ... -
javadao层的编写
2014-05-02 18:19:47Java的dao层和service层,很不错的哦! -
java DAO模式
2018-03-19 19:08:25DAO(DataAccessObjects , 数据存储对象)位于业务逻辑和持久化数据之间,实现对持久化数据的访问。通俗来讲,就是将数据库操作都封装起来,对外提供相应的接口 2. 在面向对象设计过程中,有一些“套路”用于解决... -
java DAO模式 求大神详解 不胜感激
2015-11-09 15:42:26求哪位大神 指导一下 java Dao. 上课没听懂 ,不太会 -
Java DAO浅析
2017-01-04 22:46:35DAO模式一、概念DAO(Data Access Object)模式实际上是两个模式的组合,即Data Accessor 模式和 Active Domain Object 模式,其中 Data Accessor 模式实现了数据访问和业务逻辑的分离,而Active Domain Object 模式,... -
java dao pattern model
2016-09-09 16:00:22转载:http://tutorials.jenkov.com/java-persistence/dao-design-pattern.html http://tutorials.jenkov.com/java-persistence/dao-design-problems.html http://www.oracle.com/technetwork/java/dao-138818.html -
Java DAO、Service、web理解之DAO层
2019-06-08 21:13:45DAO 模式 DAO (Data Access Object数据存取对象)是指位于业务逻辑和持久化数据之间实现对持久化数据的访问。通俗来讲,就是将数据库操作都封装起来。(接口设计+SQL编写,不涉及业务代码) DAO 包含的模块: dao ... -
Java DAO 转 JSON
2018-03-19 14:47:37import com.fasterxml.jackson.databind.ObjectMapper; ObjectMapper mapper = new ObjectMapper(); logger.info("注册传入JSON" + mapper.writeValueAsString(users)); -
Java DAO是啥?
2017-02-15 14:21:48DAO是啥? -
java Dao层与service层分析案例
2018-11-26 16:14:07之前不知道java分dao层与service层有什么用,直到进行业务逻辑编写发现分层简直太好了!Dao层是直接连接数据库的最底层,可以直接操作数据库,进行增删改查,service操作数据时直接调用Dao层的接口,无需知道具体... -
Java DAO模式 VO类设计
2018-04-17 23:05:36程序严格来讲分为四个层次:显示层、控制层、业务层、数据层,不同层次之间一定要进行数据的传递,即需要...java的(PO,VO,TO,BO,DAO,POJO)解释:https://www.cnblogs.com/yxnchinahlj/archive/2012/02/24/2366110.ht... -
java dao 设计模式
2012-11-15 21:05:30在JAVA开发中,随 着软件分层设计的流行及广泛的应用,对于DAO设 计模式大家已经不再陌生了,DAO层 已经在软件系统的开发中成为必不可少的一层,将后台的数据层和前台的VO进行分离。前段时间也针对于DAO设计模式... -
java dao设计模式
2012-04-21 14:04:40在JAVA开发中,随 着软件分层设计的流行及广泛的应用,对于DAO设 计模式大家已经不再陌生了,DAO层 已经在软件系统的开发中成为必不可少的一层,将后台的数据层和前台的VO进行分离。前段时间也针对于DAO设计模式... -
Java DAO模式 调用测试
2018-04-27 10:04:16本博客根据《李兴华--java8编程开发入门》视频整理而来。在现实开发之中,当业务层完成后,整个项目的内核就完成了。可是业务层最终是要交给用户去调用的,调用之前需要保证业务层的代码都是可用的。所以在调用之前... -
JAVA DAO设计模式
2014-03-07 19:52:311 如何使用DAO 1.1 持久层 1.1.1 什么是持久层 就是专门处理数据的代码如JDBC,它是一个工具 1.1.2 有什么好处 1.业务层与持久层解耦 2.提高代码重用 3.封装持久层,更容易使用 1.1.3 持久层组成 ... -
Java DAO模式 数据层接口
2018-04-23 19:04:46DAO模式 层次结构图现在已经完成了数据库的连接与关闭(数据库连接类实现)、开发VO类(实体类),接下来我们需要进行数据层的开发。首先,要明确一点:不同层之间如果要进行访问,必须提供有接口,以定义操作标准。... -
Java Dao工厂设计模式
2013-06-01 09:42:35这里简要说明Java中的分层设计思想。如下图所示: 将功能的实现分在两层进行,访问层和业务层。 (1)设计IDao接口 package web.java.xml....(2)设计接口实现类DaoJdbc package web.java.xml.model; public cl -
Java DAO模式 数据库连接类
2018-04-17 00:01:23第二步:新建一个Java项目并配置好数据库的驱动程序 java连接mysql数据库的 详细步骤: https://blog.csdn.net/huwentao0305/article/details/53378755 新建数据库连接类 由于所有数据库的连接操作都是固定的步骤,...
收藏数
23,075
精华内容
9,230
-
适用于微信小程序调用的hhtp工具jar包
-
华为1+X认证——网络系统建设与运维(初级)
-
SpringBoot 集成 Mqtt
-
房屋租赁合同模板.docx
-
Galera 高可用 MySQL 集群(PXC v5.7+Hapro)
-
2021-02-27
-
sleuth介绍
-
strategy模式
-
216种Web安全颜色谱
-
计算机游戏界面设计中的人机交互性研究
-
弹窗提示 运行之后 右键单击可退出
-
Navicat Premium 11.zip
-
第十一届B组C
-
Python启蒙到架构师的核心技术精讲课程
-
Scrum敏捷项目管理要点总结.pdf
-
删除win10自带杀毒软件.iso
-
朱老师c++课程第3部分-3.5STL的其他容器讲解
-
nodeMcu API说明.docx
-
JMETER 性能测试基础课程
-
MySQL 主从复制 Replication 详解(Linux 和 W