├── Mybatis └── Mybatis--day02.md ├── 数据结构 ├── 基础知识 │ ├── README.md │ ├── (5)树 │ │ ├── 树的遍历.md │ │ ├── 二叉查找树.md │ │ ├── 树的叶子节点数.md │ │ ├── 求树的深度.md │ │ ├── 平衡二叉树(AVL树).md │ │ └── 树的基本操作DEMO.md │ ├── (6)排序 │ │ ├── (6)堆排序.md │ │ ├── (5)快速排序.md │ │ ├── (7)归并排序.md │ │ ├── (8)基数排序.md │ │ ├── (3)直接插入排序.md │ │ ├── (1)冒泡排序(优化版本).md │ │ ├── (2)选择排序(优化版本).md │ │ ├── (2)选择排序(低级版本).md │ │ ├── (4)希尔排序(直插与冒泡).md │ │ ├── (8)基数排序基础--桶排序.md │ │ ├── 直接插入排序.md │ │ └── 数据结构与算法--八大基本排序算法总述(复杂度、稳定性).md │ ├── (2)链式存储结构 │ │ ├── 循环链表.md │ │ ├── 双向链表(C).md │ │ ├── 链表结构(C).md │ │ ├── 链表结构DEMO(C).md │ │ ├── 链表结构(Java).md │ │ └── 链表结构DEMO(Java).md │ ├── (7)查找 │ │ ├── (2)二分法查找.md │ │ ├── (3)树结构查找.md │ │ ├── (2)二分法改进之插值查找.md │ │ ├── (1)顺序查找(序号查与关键字查).md │ │ ├── (3)树结构查找DEMO(Java).md │ │ └── (4)线性索引查找.md │ ├── (3)栈结构 │ │ ├── 栈结构(Java).md │ │ ├── 栈链式结构(C).md │ │ ├── 栈顺序结构(C).md │ │ ├── 栈链式结构DEMO(C).md │ │ ├── 栈链式结构(Java).md │ │ ├── 栈顺序结构DEMO(C).md │ │ ├── 栈结构DEMO(Java).md │ │ └── 栈链式结构DEMO(Java).md │ ├── (1)顺序存储结构 │ │ ├── 顺序表结构(C).md │ │ ├── 顺序表结构DEMO(C).md │ │ ├── 顺序表结构(Java).md │ │ └── 顺序表结构DEMO(Java).md │ ├── (4)队列结构 │ │ ├── 队列链式结构DEMO(C).md │ │ ├── 循环队列结构DEMO(Java).md │ │ ├── 队列链式结构DEMO(Java).md │ │ └── 队列顺序结构DEMO(Java).md │ ├── (8)贪心算法 │ │ └── 最优哈夫曼树构建及其应用.md │ ├── (10)图 │ │ └── 图概念.md │ └── (9)哈希表 │ │ └── 哈希表(散列表).md └── 线性表.md ├── Oracle └── ORACLE错误编码大全.md ├── POI ├── HxlsOptRowsInterfaceImpl.java ├── HxlsOptRowsInterface.java ├── HxlsRead.java ├── ExcelExportSXXSSF.java └── HxlsAbstract.java ├── 项目笔记 ├── eclipse导入myeclipse方法.md ├── 使用OpenSessionInViewFilter方案解决Hibernate懒加载异常的问题.md ├── Dwr+Spring配置.md ├── Tomcat数据源配置方式.md ├── JavaWeb Dao层设计.md ├── 关于页面获取数据.md ├── hibernate中的表与表的关系模板.md ├── JavaWeb项目层次设计.md └── Struts标签的显示问题.md ├── README.md ├── 设计模式 └── 适配器模式.md ├── Spring └── Spring--day04.md ├── JavaScript ├── jQuery--day01.md └── jQuery--day02.md ├── Struts2 ├── Struts2day02.md └── Struts2day04.md ├── Hibernate └── Hibernate--day04.md └── 多线程 └── 多线程.md /Mybatis/Mybatis--day02.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /数据结构/基础知识/README.md: -------------------------------------------------------------------------------- 1 | # 说明 2 | 3 | ​ 非本人总结,fork与某gitHub -------------------------------------------------------------------------------- /Oracle/ORACLE错误编码大全.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/Oracle/ORACLE错误编码大全.md -------------------------------------------------------------------------------- /数据结构/基础知识/(5)树/树的遍历.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(5)树/树的遍历.md -------------------------------------------------------------------------------- /数据结构/基础知识/(5)树/二叉查找树.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(5)树/二叉查找树.md -------------------------------------------------------------------------------- /数据结构/基础知识/(5)树/树的叶子节点数.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(5)树/树的叶子节点数.md -------------------------------------------------------------------------------- /数据结构/基础知识/(5)树/求树的深度.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(5)树/求树的深度.md -------------------------------------------------------------------------------- /数据结构/基础知识/(6)排序/(6)堆排序.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(6)排序/(6)堆排序.md -------------------------------------------------------------------------------- /数据结构/基础知识/(2)链式存储结构/循环链表.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(2)链式存储结构/循环链表.md -------------------------------------------------------------------------------- /数据结构/基础知识/(6)排序/(5)快速排序.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(6)排序/(5)快速排序.md -------------------------------------------------------------------------------- /数据结构/基础知识/(6)排序/(7)归并排序.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(6)排序/(7)归并排序.md -------------------------------------------------------------------------------- /数据结构/基础知识/(6)排序/(8)基数排序.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(6)排序/(8)基数排序.md -------------------------------------------------------------------------------- /数据结构/基础知识/(7)查找/(2)二分法查找.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(7)查找/(2)二分法查找.md -------------------------------------------------------------------------------- /数据结构/基础知识/(7)查找/(3)树结构查找.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(7)查找/(3)树结构查找.md -------------------------------------------------------------------------------- /数据结构/基础知识/(2)链式存储结构/双向链表(C).md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(2)链式存储结构/双向链表(C).md -------------------------------------------------------------------------------- /数据结构/基础知识/(2)链式存储结构/链表结构(C).md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(2)链式存储结构/链表结构(C).md -------------------------------------------------------------------------------- /数据结构/基础知识/(3)栈结构/栈结构(Java).md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(3)栈结构/栈结构(Java).md -------------------------------------------------------------------------------- /数据结构/基础知识/(3)栈结构/栈链式结构(C).md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(3)栈结构/栈链式结构(C).md -------------------------------------------------------------------------------- /数据结构/基础知识/(3)栈结构/栈顺序结构(C).md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(3)栈结构/栈顺序结构(C).md -------------------------------------------------------------------------------- /数据结构/基础知识/(5)树/平衡二叉树(AVL树).md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(5)树/平衡二叉树(AVL树).md -------------------------------------------------------------------------------- /数据结构/基础知识/(5)树/树的基本操作DEMO.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(5)树/树的基本操作DEMO.md -------------------------------------------------------------------------------- /数据结构/基础知识/(6)排序/(3)直接插入排序.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(6)排序/(3)直接插入排序.md -------------------------------------------------------------------------------- /数据结构/基础知识/(1)顺序存储结构/顺序表结构(C).md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(1)顺序存储结构/顺序表结构(C).md -------------------------------------------------------------------------------- /数据结构/基础知识/(3)栈结构/栈链式结构DEMO(C).md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(3)栈结构/栈链式结构DEMO(C).md -------------------------------------------------------------------------------- /数据结构/基础知识/(3)栈结构/栈链式结构(Java).md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(3)栈结构/栈链式结构(Java).md -------------------------------------------------------------------------------- /数据结构/基础知识/(3)栈结构/栈顺序结构DEMO(C).md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(3)栈结构/栈顺序结构DEMO(C).md -------------------------------------------------------------------------------- /数据结构/基础知识/(6)排序/(1)冒泡排序(优化版本).md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(6)排序/(1)冒泡排序(优化版本).md -------------------------------------------------------------------------------- /数据结构/基础知识/(6)排序/(2)选择排序(优化版本).md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(6)排序/(2)选择排序(优化版本).md -------------------------------------------------------------------------------- /数据结构/基础知识/(6)排序/(2)选择排序(低级版本).md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(6)排序/(2)选择排序(低级版本).md -------------------------------------------------------------------------------- /数据结构/基础知识/(7)查找/(2)二分法改进之插值查找.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(7)查找/(2)二分法改进之插值查找.md -------------------------------------------------------------------------------- /数据结构/基础知识/(1)顺序存储结构/顺序表结构DEMO(C).md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(1)顺序存储结构/顺序表结构DEMO(C).md -------------------------------------------------------------------------------- /数据结构/基础知识/(1)顺序存储结构/顺序表结构(Java).md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(1)顺序存储结构/顺序表结构(Java).md -------------------------------------------------------------------------------- /数据结构/基础知识/(2)链式存储结构/链表结构DEMO(C).md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(2)链式存储结构/链表结构DEMO(C).md -------------------------------------------------------------------------------- /数据结构/基础知识/(2)链式存储结构/链表结构(Java).md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(2)链式存储结构/链表结构(Java).md -------------------------------------------------------------------------------- /数据结构/基础知识/(3)栈结构/栈结构DEMO(Java).md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(3)栈结构/栈结构DEMO(Java).md -------------------------------------------------------------------------------- /数据结构/基础知识/(3)栈结构/栈链式结构DEMO(Java).md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(3)栈结构/栈链式结构DEMO(Java).md -------------------------------------------------------------------------------- /数据结构/基础知识/(4)队列结构/队列链式结构DEMO(C).md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(4)队列结构/队列链式结构DEMO(C).md -------------------------------------------------------------------------------- /数据结构/基础知识/(6)排序/(4)希尔排序(直插与冒泡).md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(6)排序/(4)希尔排序(直插与冒泡).md -------------------------------------------------------------------------------- /数据结构/基础知识/(6)排序/(8)基数排序基础--桶排序.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(6)排序/(8)基数排序基础--桶排序.md -------------------------------------------------------------------------------- /数据结构/基础知识/(2)链式存储结构/链表结构DEMO(Java).md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(2)链式存储结构/链表结构DEMO(Java).md -------------------------------------------------------------------------------- /数据结构/基础知识/(4)队列结构/循环队列结构DEMO(Java).md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(4)队列结构/循环队列结构DEMO(Java).md -------------------------------------------------------------------------------- /数据结构/基础知识/(4)队列结构/队列链式结构DEMO(Java).md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(4)队列结构/队列链式结构DEMO(Java).md -------------------------------------------------------------------------------- /数据结构/基础知识/(4)队列结构/队列顺序结构DEMO(Java).md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(4)队列结构/队列顺序结构DEMO(Java).md -------------------------------------------------------------------------------- /数据结构/基础知识/(7)查找/(1)顺序查找(序号查与关键字查).md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(7)查找/(1)顺序查找(序号查与关键字查).md -------------------------------------------------------------------------------- /数据结构/基础知识/(7)查找/(3)树结构查找DEMO(Java).md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(7)查找/(3)树结构查找DEMO(Java).md -------------------------------------------------------------------------------- /数据结构/基础知识/(1)顺序存储结构/顺序表结构DEMO(Java).md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepRedApple/Note/HEAD/数据结构/基础知识/(1)顺序存储结构/顺序表结构DEMO(Java).md -------------------------------------------------------------------------------- /数据结构/基础知识/(6)排序/直接插入排序.md: -------------------------------------------------------------------------------- 1 | ```java 2 | private void sortCore(int[] a) { 3 | for (int i = 1; i < a.length; i++) { 4 | int j = i; 5 | int temp = a[i]; 6 | while(j > 0 && temp < a[j - 1]) { 7 | a[j] = a[j - 1]; 8 | j--; 9 | } 10 | a[j] = temp; 11 | } 12 | } 13 | ``` 14 | 15 | -------------------------------------------------------------------------------- /POI/HxlsOptRowsInterfaceImpl.java: -------------------------------------------------------------------------------- 1 | import java.util.List; 2 | 3 | /** 4 | * 测试导入数据接口 5 | * @author Thinkpad 6 | * 7 | */ 8 | public class HxlsOptRowsInterfaceImpl implements HxlsOptRowsInterface { 9 | 10 | @Override 11 | public String optRows(int sheetIndex, int curRow, List rowlist) 12 | throws Exception { 13 | //插入数据库 14 | System.out.println("sheetIndex="+sheetIndex+"curRow="+curRow+rowlist); 15 | return null; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /POI/HxlsOptRowsInterface.java: -------------------------------------------------------------------------------- 1 | import java.util.List; 2 | 3 | public interface HxlsOptRowsInterface { 4 | 5 | public static final String SUCCESS="success"; 6 | /** 7 | * 处理excel文件每行数据方法 8 | * @param sheetIndex 为sheet的序号 9 | * @param curRow 为行号 10 | * @param rowlist 行数据 11 | * @return success:成功,否则为失败原因 12 | * @throws Exception 13 | */ 14 | public String optRows(int sheetIndex, int curRow, List rowlist) throws Exception; 15 | 16 | } 17 | -------------------------------------------------------------------------------- /项目笔记/eclipse导入myeclipse方法.md: -------------------------------------------------------------------------------- 1 | # eclipse能够导入到Myeclipse的方法步骤 2 | 3 | ## 第一步:File 4 | 5 | ## 第二步:new 6 | 7 | ## 第三步:Dynamic Web Project 8 | 9 | ## 第四步:如图所示 10 | 11 | ![第四步](http://upload-images.jianshu.io/upload_images/1540531-12433ed0d1f1250e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 12 | 13 | ## 第五步:修改Default output folder 14 | 15 | ![第五步](http://upload-images.jianshu.io/upload_images/1540531-1338afa54b47fe0a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 16 | 17 | ## 第六步:修改文件目录 18 | 19 | ![第六步](http://upload-images.jianshu.io/upload_images/1540531-dcfc7ab45181d14f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 20 | 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Note 2 | 3 | > 个人学习资料,大部分都是培训笔记,共勉 4 | 5 | - [Activiti](https://github.com/DeepRedApple/Note/tree/master/Activiti) 6 | - [Hibernate](https://github.com/DeepRedApple/Note/tree/master/Hibernate) 7 | - [Java](https://github.com/DeepRedApple/Note/tree/master/Java) 8 | - [Javascript](https://github.com/DeepRedApple/Note/tree/master/Javascript) 9 | - [jfreechart](https://github.com/DeepRedApple/Note/tree/master/jfreechart) 10 | - [Maven](https://github.com/DeepRedApple/Note/tree/master/Maven) 11 | - [Mybatis](https://github.com/DeepRedApple/Note/tree/master/Mybatis) 12 | - [Nginx](https://github.com/DeepRedApple/Note/tree/master/Nginx) 13 | - [Oracle](https://github.com/DeepRedApple/Note/tree/master/Oracle) 14 | - [POI](https://github.com/DeepRedApple/Note/tree/master/POI) 15 | - [Shiro](https://github.com/DeepRedApple/Note/tree/master/Shiro) 16 | - [Spring](https://github.com/DeepRedApple/Note/tree/master/Spring) 17 | - [Struts2](https://github.com/DeepRedApple/Note/tree/master/Struts2) 18 | - [WebService](https://github.com/DeepRedApple/Note/tree/master/WebService) 19 | - [检索]() 20 | - [项目笔记](https://github.com/DeepRedApple/Note/tree/master/%E9%A1%B9%E7%9B%AE%E7%AC%94%E8%AE%B0) 21 | - ​ 22 | - ​ 23 | - ​ 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /数据结构/基础知识/(7)查找/(4)线性索引查找.md: -------------------------------------------------------------------------------- 1 | # 索引 2 | 3 | ## 概念 4 | 5 | 索引就是把一个关键字与它对应的记录相关联的过程,一个索引由若干个索引项构成,每个索引项至少应包含关键字和其对应的记录在存储器中的位置等信息。 6 | 7 | ## 分类 8 | 9 | ### 索引按结构分 10 | 11 | 线性索引、树形索引和多级索引 12 | 其中线性索引分为稠密索引、分块索引和倒排索引。 13 | 14 | ## (1)稠密索引 15 | 指在线性索引中,将数据集中的每个记录对应一个索引项。索引项一定是按照关键码有序的排列。(注意:索引项与数据集的记录个数相同 16 | 索引项有序,意味着,我们查找的时候,可以用折半、插值、斐波那契等有序的查找算法。 17 | 18 | ## (2)分块索引: 19 | 是把数据集的记录分成了若干块,并且这些块需要满足: 20 | 21 | ### 1.块内无序 22 | 23 | 即每一块内不要求有序,当然你可以使其有序,不过代价很大(我们是为了优化稠密索引而思考出来的分块索引,怎么可能还去耗费那么大的性能去做此事)。 24 | 25 | ### 2.块间有序 26 | 27 | 即设定一定规则给每一个块,比如第二块的记录都比第一块的大。 28 | 29 | #### 三个数据项: 30 | ##### 1.最大关键码 31 | 32 | 它存储每一块中的而最大关键字,这样的好处是可以使得在它之后的下一块中的最小关键字也能比这一块最大的关键字要大。 33 | 34 | ##### 2.存储个数 35 | 36 | 存储了块中的记录个数,以便于循环时使用。 37 | 38 | ##### 3.首数据 39 | 40 | 用于指向块首数据元素的指针,便于开始对这一块中记录进行遍历。 41 | 42 | #### 分块索引查找步骤: 43 | ##### 第一步: 44 | 45 | 在分块索引表中查找要查关键字所在的块。分块索引表是块间有序的,所以可使用折半、插值等算法。 46 | 47 | ##### 第二步: 48 | 49 | 根据块首指针找到相应的块,并在块中顺序查找关键码。因为块中可为无序,所以只能顺序查找。 50 | 51 | #### 总述 52 | 53 | 分块索引比顺序查找效率高很多,但是与折半查找相比还不够。所以在确定所在块的过程中,由于块间有序,可使用折半、插值等优化。 54 | 55 | ## (3)倒排索引: 56 | ![这里写图片描述](http://img.blog.csdn.net/20170327120455123?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSmFja19fRnJvc3Q=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 57 | ### 概念 58 | 有索引项通用结构:1.次关键字,如上图“英文单词”;2.记录号表,如上图“文章编号 59 | 记录号表存储具有相同次关键字的所有记录的记录号(可以是指向记录的真正或是该记录的主关键字 60 | 源于实际中需要根据属性(或字段、次关键码)的值来查找记录。 61 | 62 | ### 优点 63 | 64 | 查找记录快;缺点:记录号不定长。 65 | 66 | #### 应用 67 | 68 | lucene技术基础就是这个倒排索引。 69 | -------------------------------------------------------------------------------- /数据结构/基础知识/(8)贪心算法/最优哈夫曼树构建及其应用.md: -------------------------------------------------------------------------------- 1 | # 贪心算法 2 | 3 | 哈夫曼编码问题,是广泛地用于数据文件压缩的十分有效的编码方法。其压缩率通常在20%~90%之间。哈夫曼编码算法用字符在文件中出现的频率表来建立一个用0,1串表示各字符的最优表示方式。 4 | 5 | 解决当年数据传输的最优化问题。 6 | 7 | ## 构建过程: 8 | 假设有权值叶子结点有:A5,B15,D30,E10,C4 9 | (1)按权值排序叶子结点:A5,,E10,B15,D30,C4 10 | (2)取头两个最小权值的结点作为一个新节点N1的两个子结点,注意相对较小的是左孩子,此时例子,A为N1的左孩子,E为N1的右孩子。N1新结点权值为5+10=15. 11 | 12 | ![这里写图片描述](http://img.blog.csdn.net/20170324201634491?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSmFja19fRnJvc3Q=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 13 | 14 | (3)将N1替换A与E,插入有序序列中,保持从小到大排列。即N1 15,B15,D30,C4 15 | (4)重复步骤2,将N1与B作为一个新结点N2的两个子结点。N2权值=15+15=3 16 | (5)将N2替换N1与B,插入有序序列中,保持从小到大排 17 | (6)重复步骤2.将N2与D作为一个新节点N3的两个子结点 18 | 19 | ![这里写图片描述](http://img.blog.csdn.net/20170324202102966?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSmFja19fRnJvc3Q=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 20 | 21 | (7)将N3替换N2与D,插入有序序列中,保持从小到大排 22 | (8)重复步骤2.将N3与C作为一个新节点N3的两个子结点。完成哈夫曼树的构建。 23 | 24 | ![这里写图片描述](http://img.blog.csdn.net/20170324202142536?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSmFja19fRnJvc3Q=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 25 | ![这里写图片描述](http://img.blog.csdn.net/20170324202223708?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSmFja19fRnJvc3Q=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 26 | ## 应用: 27 | 传输的是一连串的字母,我们先用权值分配好他来构建最优哈夫曼树。如下图左。 28 | 29 | ![这里写图片描述](http://img.blog.csdn.net/20170324203110307?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSmFja19fRnJvc3Q=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 30 | 31 | ? 然后!规定哈夫曼树的左分支代表0,右分支代表1,则从根结点到叶子结点所经过的路径分支组成的0和1序列便为该结点对应字符的编码。这就是哈夫曼编码!!如上图右。 32 | -------------------------------------------------------------------------------- /设计模式/适配器模式.md: -------------------------------------------------------------------------------- 1 | # 适配器模式 2 | 3 | > 慕课网学习笔记[地址](http://www.imooc.com/learn/146) 4 | 5 | ## 定义 6 | 7 | 适配器模式将一个类的接口,转换成客户期望的另外一个接口。使得原本由于接口不兼容而不能一起工作的那些类可以在一起工作 8 | 9 | ## 构成 10 | 11 | ![](http://upload-images.jianshu.io/upload_images/1540531-aa9b40c083c6e30c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 12 | 13 | ## 实现 14 | 15 | ### 组合实现 16 | 17 | #### ThreePlugIf 18 | 19 | ```java 20 | /* 21 | * 三相插座接口 22 | */ 23 | public interface ThreePlugIf { 24 | 25 | //使用三相电流供电 26 | public void powerWithThree(); 27 | } 28 | 29 | ``` 30 | 31 | #### TwoPlugAdapter 32 | 33 | ```java 34 | /* 35 | * 二相转三相的插座适配器 36 | */ 37 | 38 | public class TwoPlugAdapter implements ThreePlugIf { 39 | 40 | private GBTwoPlug plug; 41 | 42 | public TwoPlugAdapter(GBTwoPlug plug){ 43 | this.plug = plug; 44 | } 45 | @Override 46 | public void powerWithThree() { 47 | System.out.println("通过转化"); 48 | plug.powerWithTwo(); 49 | 50 | } 51 | 52 | } 53 | ``` 54 | 55 | #### GBTwoPlug 56 | 57 | ```java 58 | public class GBTwoPlug { 59 | 60 | //使用二相电流供电 61 | public void powerWithTwo(){ 62 | System.out.println("使用二相电流供电"); 63 | } 64 | } 65 | ``` 66 | 67 | #### NoteBook 68 | 69 | ```java 70 | package com.immoc.pattern.adapter; 71 | 72 | public class NoteBook { 73 | 74 | private ThreePlugIf plug; 75 | 76 | public NoteBook(ThreePlugIf plug){ 77 | this.plug = plug; 78 | } 79 | 80 | //使用插座充电 81 | public void charge(){ 82 | plug.powerWithThree(); 83 | } 84 | 85 | public static void main(String[] args) { 86 | GBTwoPlug two = new GBTwoPlug(); 87 | ThreePlugIf three = new TwoPlugAdapter(two); 88 | NoteBook nb = new NoteBook(three); 89 | nb.charge(); 90 | } 91 | 92 | } 93 | ``` 94 | 95 | ### 继承实现 96 | 97 | #### TwoPlugAdapterExtends 98 | 99 | ```java 100 | public class TwoPlugAdapterExtends extends GBTwoPlug implements ThreePlugIf { 101 | 102 | @Override 103 | public void powerWithThree() { 104 | this.powerWithTwo(); 105 | } 106 | 107 | } 108 | ``` 109 | 110 | #### NoteBook 111 | 112 | ```java 113 | public class NoteBook { 114 | 115 | private ThreePlugIf plug; 116 | 117 | public NoteBook(ThreePlugIf plug){ 118 | this.plug = plug; 119 | } 120 | 121 | //使用插座充电 122 | public void charge(){ 123 | plug.powerWithThree(); 124 | } 125 | 126 | public static void main(String[] args) { 127 | GBTwoPlug two = new GBTwoPlug(); 128 | ThreePlugIf three = new TwoPlugAdapterExtends(); 129 | NoteBook nb = new NoteBook(three); 130 | nb.charge(); 131 | 132 | } 133 | 134 | } 135 | ``` 136 | 137 | ## 博客 138 | 139 | [适配器模式](http://blog.csdn.net/qq_29375837/article/details/70214462) 140 | 141 | -------------------------------------------------------------------------------- /项目笔记/使用OpenSessionInViewFilter方案解决Hibernate懒加载异常的问题.md: -------------------------------------------------------------------------------- 1 | # 使用OpenSessionInViewFilter方案解决Hibernate懒加载异常的问题 2 | 3 | > 在项目练习的时候,遇到了这个懒加载异常,当时解决的方法是在配置文件中设置lazy="false"。该方法有很到缺点,效率极低,我们将所有相关联的数据都查询了,频繁的查询降低了效率!!不建议采用 4 | 5 | ## Web程序中的懒加载异常说明及解决方案 6 | 7 | ![图一](http://upload-images.jianshu.io/upload_images/1540531-fd3b34cdd9187c3b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 8 | 9 | ### 异常说明 10 | 11 | 当一个请求来了之后,先执行Action,在执行结果。在action里面有Service业务层,调用Service,Service做业务处理。 12 | 13 | 开始执行Service方法的时候,开始开启事务和Session,Service方法结束或回滚提交事务,会自动关闭Session。 14 | 15 | 在Service里面查询列表加载对象的时候,但是其相关连的对象并没有加载,但是Session关闭了,关联对象最终没有加载,在页面中用到了懒加载属性,但是是在之前加载的,且Session已经关闭了,所以有了懒加载异常,说没有Session。 16 | 17 | ### 解决方案 18 | 19 | ![图二](http://upload-images.jianshu.io/upload_images/1540531-fee5f69b942018e0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 20 | 21 | 从上面的异常说明中可以得知,主要原因是在页面中没有Session,那么我们可以使Session不关闭,不关闭Session又会出现问题,那么我们就在整个请求的过程中添加一个过滤器或者拦截器,过滤器或拦截器是先进后出。我们在过滤器或拦截器中关闭Session,也就是在当页面显示一些数据后,再在过滤器或拦截器里面关闭Session就可以了。但是需要设置当事务提交之后,不需要关闭Session。在spring中已经有一个过滤器可以帮助我们在过滤器中关闭Session了。OpenSessionInViewFilter 22 | 23 | ### 配置方案 24 | 25 | #### 第一步:web.xml配置 26 | 27 | ```xml 28 | 29 | 31 | OA 32 | 33 | 34 | 35 | contextConfigLocation 36 | classpath:applicationContext*.xml 37 | 38 | 39 | 40 | org.springframework.web.context.ContextLoaderListener 41 | 42 | 43 | 44 | 45 | OpenSessionInViewFilter 46 | org.springframework.orm.hibernate4.support.OpenSessionInViewFilter 47 | 48 | 49 | 50 | OpenSessionInViewFilter 51 | *.action 52 | 53 | 54 | 55 | 56 | struts2 57 | org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter 58 | 59 | 60 | 61 | struts2 62 | /* 63 | 64 | 65 | 66 | ``` 67 | 68 | **注意:**拦截的是所有的action,而且在Action里面调用的是Service,与struts的配置Action的扩展名一样 69 | 70 | #### 第二步:struts配置 71 | 72 | ```xml 73 | 74 | 75 | ``` 76 | 77 | > 不过,当整个系统中出现两个请求的,并且不是一个请求的时候,还是会出现懒加载异常。比如,一个是SSH框架里面的Struts2里面的请求,里面已经已经通过OpenSessionInViewFilter解决的懒加载异常,但是当系统需要的Servlet的监听器里面需要初始化某些数据的时候,而且这些数据与其他数据有关系的时候,还是会出现懒加载异常,所以还要在实体配置文件中配置lazy="false"属性。 -------------------------------------------------------------------------------- /项目笔记/Dwr+Spring配置.md: -------------------------------------------------------------------------------- 1 | # Spring+dwr整合 2 | 3 | # 1、Dwr介绍: 4 | 5 | DWR(Direct Web Remoting)是一个用于改善web页面与Java类交互的远程服务器端Ajax开源框架,可以帮助开发人员开发包含AJAX技术的网站.它可以允许在浏览器里的代码使用运行在WEB服务器上的JAVA函数,就像它就在浏览器里一样。 6 | 7 | # 2、Jar包 8 | 9 | 如果是maven工程加入以下依赖: 10 | 11 | <!-- dwr --> 12 | 13 | ```xml 14 | 15 | 16 | org.directwebremoting 17 | dwr 18 | 3.0.M1 19 | 20 | 21 | ``` 22 | 23 | 24 | 如果不是maven工程则需要加入; dwr-3.0.M1.jar 25 | 26 | # 3、Dwr servlet 27 | 28 | 在web.xml中加入: 29 | 30 | ```xml 31 | 32 | dwr-invoker 33 | uk.ltd.getahead.dwr.DWRServlet 34 | 35 | 36 | debug 37 | true 38 | 39 | 40 | 41 | crossDomainSessionSecurity 42 | false 43 | 44 | 45 | allowScriptTagRemoting 46 | true 47 | 48 | 49 | 50 | dwr-invoker 51 | /dwr/* 52 | 53 | ``` 54 | 55 | # 4、dwr.xml 56 | 57 | 在WEB-INF下配置dwr.xml文件: 58 | 59 | ```xml-dtd 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | ``` 70 | 71 | - Creator: 72 | 73 | creator属性的值可以是new,struts,spring......因为此处是整合spring来做的,所以设置成"spring" 74 | 75 | 如果creator为new则param为: 76 | 77 | <param name="class" value="类路径名"/> 78 | 79 | - javascript="dwrService" 80 | 81 | 规定网页访问js地址: 82 | 83 | <script type='text/javascript' src='工程路径/dwr/interface/ dwrService.js'></script> 84 | 85 | 前这的/dwr/就是指定走dwr 的servlet 86 | 87 | - 指向spring的bean 88 | 89 | <param name="beanName" value="dwrService" /> 90 | 91 | 例如: 92 | 93 | dwrService即在spring中定义的bean 94 | 95 | ```java 96 | public String testdwr() throws Exception{ 97 | return "helloworld"; 98 | } 99 | ``` 100 | 101 | 102 | # 5、使用dwr 103 | 104 | 网页中加入dwr的js引用。 105 | 106 | ```html 107 | 108 | 109 | 110 | ``` 111 | 112 | 上边两行红色为固定写法,使用dwr必须引用engine.js和util.js 113 | 114 | 第三行为编写的dwr方法,其中"工程路径/dwr/interface/"是固定的,后边的dwrService.js是dwr.xml中定义的javascript="dwrService"。 115 | 116 | 调用dwr方法: 117 | 118 | ```javascript 119 | dwrService.testdwr({ 120 | callback:function(data) { 121 | alert(data); 122 | }}); 123 | ``` 124 | 125 | 126 | dwrService为dwr.xml中定义的javascript="dwrService",testdwr为spring bean中定义的方法。Callback为回调函数。 127 | 128 | 一个传参数的例子: 129 | 130 | Bean的方法: 131 | 132 | ```java 133 | public String testdwrparam(String name) throws Exception{ 134 | return "helloworld";+name; 135 | } 136 | ``` 137 | 138 | 页面调用: 139 | 140 | ```javascript 141 | dwrService. testdwrparam (‘张三’,{ 142 | callback:function(data) { 143 | alert(data); 144 | }}); 145 | ``` 146 | 147 | 148 | 实验结果发现,dwr 不支持重载函数/方法,有兴趣的试验下。 149 | 150 | -------------------------------------------------------------------------------- /POI/HxlsRead.java: -------------------------------------------------------------------------------- 1 | import java.io.FileNotFoundException; 2 | import java.io.IOException; 3 | import java.sql.SQLException; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | 8 | public class HxlsRead extends HxlsAbstract{ 9 | 10 | 11 | //数据处理解析数据的接口 12 | private HxlsOptRowsInterface hxlsOptRowsInterface; 13 | //处理数据总数 14 | private int optRows_sum = 0; 15 | //处理数据成功数量 16 | private int optRows_success = 0; 17 | //处理数据失败数量 18 | private int optRows_failure = 0; 19 | //excel表格每列标题 20 | private List rowtitle ; 21 | //失败数据 22 | private List> failrows; 23 | //失败原因 24 | private List failmsgs ; 25 | 26 | //要处理数据所在的sheet索引,sheet索引从0开始 27 | private int sheetIndex; 28 | /** 29 | * 导入文件的名称 30 | * @param filename 导入文件的物理路径 31 | * @param sheetIndex 要读取数据所在sheet序号 32 | * @param hxlsOptRowsInterface 处理读取每一行数据的接口 33 | * @throws IOException 34 | * @throws FileNotFoundException 35 | * @throws SQLException 36 | */ 37 | public HxlsRead(String filename,int sheetIndex,HxlsOptRowsInterface hxlsOptRowsInterface) throws IOException, 38 | FileNotFoundException, SQLException { 39 | super(filename); 40 | this.sheetIndex = sheetIndex; 41 | this.hxlsOptRowsInterface = hxlsOptRowsInterface; 42 | this.rowtitle = new ArrayList(); 43 | this.failrows = new ArrayList>(); 44 | this.failmsgs = new ArrayList(); 45 | } 46 | 47 | /** 48 | * 对读取到一行数据进行解析 49 | */ 50 | @Override 51 | public void optRows(int sheetIndex,int curRow, List rowlist) throws Exception { 52 | /*for (int i = 0 ;i< rowlist.size();i++){ 53 | System.out.print("'"+rowlist.get(i)+"',"); 54 | } 55 | System.out.println();*/ 56 | //将rowlist的长度补齐和标题一致 57 | int k=rowtitle.size()-rowlist.size(); 58 | for(int i=0;i(rowlist)); 73 | failmsgs.add(result); 74 | }else{ 75 | optRows_success++; 76 | } 77 | } 78 | 79 | } 80 | 81 | 82 | } 83 | 84 | public long getOptRows_sum() { 85 | return optRows_sum; 86 | } 87 | 88 | public void setOptRows_sum(int optRows_sum) { 89 | this.optRows_sum = optRows_sum; 90 | } 91 | 92 | public long getOptRows_success() { 93 | return optRows_success; 94 | } 95 | 96 | public void setOptRows_success(int optRows_success) { 97 | this.optRows_success = optRows_success; 98 | } 99 | 100 | public long getOptRows_failure() { 101 | return optRows_failure; 102 | } 103 | 104 | public void setOptRows_failure(int optRows_failure) { 105 | this.optRows_failure = optRows_failure; 106 | } 107 | 108 | 109 | public List getRowtitle() { 110 | return rowtitle; 111 | } 112 | 113 | public List> getFailrows() { 114 | return failrows; 115 | } 116 | 117 | public List getFailmsgs() { 118 | return failmsgs; 119 | } 120 | 121 | public void setFailmsgs(List failmsgs) { 122 | this.failmsgs = failmsgs; 123 | } 124 | 125 | public static void main(String[] args){ 126 | HxlsRead xls2csv; 127 | try { 128 | //第一个参数就是导入的文件 129 | //第二个参数就是导入文件中哪个sheet 130 | //第三个参数导入接口的实现类对象 131 | xls2csv = new HxlsRead("d:/test11.xls",0,new HxlsOptRowsInterfaceImpl()); 132 | xls2csv.process(); 133 | } catch (FileNotFoundException e) { 134 | e.printStackTrace(); 135 | } catch (IOException e) { 136 | e.printStackTrace(); 137 | } catch (SQLException e) { 138 | e.printStackTrace(); 139 | } 140 | 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /数据结构/基础知识/(10)图/图概念.md: -------------------------------------------------------------------------------- 1 | ### (1)数据元素 2 | 3 | 线性表中数据元素叫元素,树中数据元素叫结点,图中的数据元素叫顶点。 4 | 5 | ### (2)图分无向图和有向图。 6 | 7 | 无向图由顶点和边构成,有向图由顶点和弧构成(弧有弧尾和弧头之分)。 8 | 9 | #### 边总数 10 | 11 | 无向完全图--任意两个顶点之间都存在边。有N*(N-1)/2条边 12 | 有向完全图--任意两个顶点之间存在方向互为相反的两条弧。有N*(N-1)条边 13 | 14 | ### (3)图的分类 15 | 16 | 图按边或弧的多少分稀疏图和稠密图。如果任意两个顶点之间都存在边叫完全图,有向的的叫有向完全图。 17 | 18 | ### (4)度和顶点 19 | 20 | 无向图顶点 的边数叫度,有向图顶点分为入度和出度。 21 | 22 | 度:每个结点连了多少条边 23 | 24 | ### (5)网: 25 | 26 | 图上的边或弧上带权称为网。 27 | 28 | 权:图的边或弧相关的数(两顶点距离)。 29 | 30 | ### (6)图的路径 31 | 32 | 图中顶点间存在路径,两顶点存在路径说明是连通的。如果路径最终回到起始点称为环,当中不重复的叫简单路径。若“任意”两点是连通的,则图就是连通图,有向则称强连通图。图中有子图,若子图极大连通就是连通分量,有向的则称强连通分量。 33 | 34 | #### 路径长度 35 | 36 | 就是从一个节点走到另一个节点所经过的边或弧的条数。 37 | 38 | #### 带权路径长度之和 39 | 40 | 树的带权路径长度规定为所有叶子结点的带权路径长度之和,记为WPL。 41 | 42 | 图1不是连通图,图2是。 43 | 44 | ![这里写图片描述](http://img.blog.csdn.net/20170424152234114?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSmFja19fRnJvc3Q=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 45 | ### (7)连通分量 46 | 47 | (1)要是子图;(2)子图是连通的;(3)连通子图含有极大顶点数;(4)具有极大顶点数的连通子图包含依附于这些顶点的所有边。 48 | 49 | ### (8)树、有向树、森林 50 | 51 | 无向图中连通且n个顶点n-1条边叫生成树。有向图中一顶点入度为0其余顶点入度为1的叫有向树。一个有向图由若干棵有向树构成生成森林。 52 | 53 | #### 有向树 54 | 55 | 一个有向图恰有一个顶点的入度为0,其余顶点的入度均为。 56 | 57 | 图2和图3是图1有向图的生成森林。 58 | 59 | ![这里写图片描述](http://img.blog.csdn.net/20170424152641120?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSmFja19fRnJvc3Q=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 60 | ### (9)邻接矩阵(存储方式) 61 | 62 | 用两个数组来表示图。一个一维数组存储顶点信息,一个二维数组(邻接矩阵)存储图中的边或弧的信息。 63 | 64 | 很适用于边数相对顶点较多的图 65 | 66 | #### 无向图邻接矩阵: 67 | 对角线为0说明不存在顶点到自身的边。 68 | 69 | ![这里写图片描述](http://img.blog.csdn.net/20170424155048714?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSmFja19fRnJvc3Q=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 70 | #### 有向图邻接矩阵: 71 | ![这里写图片描述](http://img.blog.csdn.net/20170424155225076?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSmFja19fRnJvc3Q=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 72 | #### 带权的有向图邻接矩阵: 73 | ![这里写图片描述](http://img.blog.csdn.net/20170424155342172?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSmFja19fRnJvc3Q=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 74 | 75 | 那个无限的符号是一个计算机允许的、大于所有边上权值的值。 76 | 77 | ### (10)邻接表 78 | 79 | 一种数组与链表相结合的存储方 80 | 很适用于边数相对顶点较少的图 81 | 有邻接点才用链表连起来 82 | 顶点表的各个结点由data和firstedge两个域表示。data是数据域,存储顶点信息,firstedge是指针域,指向边表的第一个结点 83 | 边表结点由adjvex和next两个域组成。adjvex是邻接点域,存储某个顶点的邻接点在顶点表中的下标;next存储指向边表中下一个结点的指针。 84 | 85 | #### 无向图邻接表: 86 | ![这里写图片描述](http://img.blog.csdn.net/20170424160054097?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSmFja19fRnJvc3Q=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 87 | #### 有向图邻接表: 88 | 以顶点为弧尾来存储边表,方便得出每个顶点的出度。(当然有时会换过来,如果是为了入度的话--逆邻接表) 89 | 90 | ![这里写图片描述](http://img.blog.csdn.net/20170424162244494?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSmFja19fRnJvc3Q=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 91 | #### 有向图逆邻接表: 92 | 这样很容易得出某个顶点的入度或出度,判断两顶点是否存在弧。 93 | 94 | ![这里写图片描述](http://img.blog.csdn.net/20170424162603468?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSmFja19fRnJvc3Q=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)![这里写图片描述](http://img.blog.csdn.net/20170424162615983?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSmFja19fRnJvc3Q=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 95 | #### 带权值的有向图邻接表: 96 | ![这里写图片描述](http://img.blog.csdn.net/20170424163340868?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSmFja19fRnJvc3Q=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 97 | ### (11)十字链表: 98 | 把邻接表与逆邻接表结合起 99 | firstin表示入边表头指针,指向该顶点的入边表中第一个结点,firstout表示出边表头指针 100 | tailvex指弧起点在顶点表的下标,headvex指弧重点在顶点表中的下标,headlink指入边表指针域,指向终点相同的下一条边,tailvex是指边表指针域,指向起点相同的下一条边。如果是网还可以增加一个weight域来存储权值。 101 | 102 | 此方式好处:讲邻接表和逆邻接表整合起来,既容易找到vi尾的弧,也容易找到vi头的弧,因此容易求出出度和入度。 103 | 104 | ![这里写图片描述](http://img.blog.csdn.net/20170424170438302?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSmFja19fRnJvc3Q=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 105 | ### (12)邻接多重表: 106 | 更关注边的操作时使用此结构 107 | ivex和jvex是与某条边依附的两个顶点在顶点表中下标。ilink指向依附顶点ivex的下一条边,jlink指向依附顶点jvex的下一条边。 108 | 109 | ![这里写图片描述](http://img.blog.csdn.net/20170424171759214?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSmFja19fRnJvc3Q=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 110 | 111 | 开始连线: 112 | 113 | ![这里写图片描述](http://img.blog.csdn.net/20170424171828460?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSmFja19fRnJvc3Q=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 114 | -------------------------------------------------------------------------------- /数据结构/基础知识/(6)排序/数据结构与算法--八大基本排序算法总述(复杂度、稳定性).md: -------------------------------------------------------------------------------- 1 | # 本文罗列八大排序的复杂度、稳定性,并相互对比。 2 | # 一、冒泡排序 3 | ![这里写图片描述](http://img.blog.csdn.net/20170323105153231?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSmFja19fRnJvc3Q=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 4 | ## 时间复杂度 5 | ### 正序 6 | 7 | 若文件的初始状态是正序的,一趟扫描即可完成排序。所需的关键字比较次数C和记录移动次数M均达到最小值:Cmin = N - 1, Mmin = 0。所以,冒泡排序最好时间复杂度为O(N)。 8 | 9 | ### 反序 10 | 11 | 若初始文件是反序的,需要进行 N -1 趟排序。每趟排序要进行 N - i 次关键字的比较(1 ≤ i ≤ N - 1),且每次比较都必须移动记录三次来达到交换记录位置。在这种情况下,比较和移动次数均达到最大值: 12 | 13 | Cmax = N(N-1)/2 = O(N2) 14 | 15 | Mmax = 3N(N-1)/2 = O(N2) 16 | 17 | 冒泡排序的最坏时间复杂度为O(N2)。 18 | 19 | 因此,冒泡排序的平均时间复杂度为O(N2)。 20 | 21 | ## 算法稳定性: 22 | 冒泡排序就是把小的元素往前调或者把大的元素往后调。比较是相邻的两个元素比较,交换也发生在这两个元素之间。所以相同元素的前后顺序并没有改变,所以冒泡排序是一种稳定排序算法。 23 | 24 | # 二、简单选择排序 25 | ![这里写图片描述](http://img.blog.csdn.net/20170323105518562?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSmFja19fRnJvc3Q=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 26 | ## 时间复杂度 27 | 简单选择排序的比较次数与序列的初始排序无关。 假设待排序的序列有 N 个元素,则比较次数总是N (N - 1) / 2。而移动次数与序列的初始排序有关。当序列正序时,移动次数最少,为 0. 28 | 29 | 当序列反序时,移动次数最多,为3N (N - 1) / 2。 30 | 31 | 所以,综合以上,简单排序的时间复杂度为 O(N2)。 32 | 33 | ## 空间复杂度 34 | 简单选择排序需要占用 1 个临时空间,在交换数值时使用。 35 | 36 | ## 算法稳定性 37 | ## 举个栗子 38 | 序列5 8 5 2 9, 我们知道第一遍选择第1个元素5会和2交换搜索,那么原序列中2个5的相对前后顺序就被破坏了,所以选择排序不是一个稳定的排序算法 39 | 40 | # 三、直接插入排序 41 | ![这里写图片描述](http://img.blog.csdn.net/20170323105947736?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSmFja19fRnJvc3Q=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 42 | ## 时间复杂度 43 | 当数据正序时,执行效率最好,每次插入都不用移动前面的元素,时间复杂度为O(N)。 当数据反序时,执行效率最差,每次插入都要前面的元素后移,时间复杂度为O(N2)。所以,数据越接近正序,直接插入排序的算法性能越好。 44 | 45 | ## 空间复杂度 46 | 由直接插入排序算法可知,我们在排序过程中,需要一个临时变量存储要插入的值,所以空间复杂度为 1 。 47 | 48 | ## 算法稳定性 49 | 直接插入排序的过程中,不需要改变相等数值元素的位置,所以它是稳定的算法。 50 | 51 | # 四、希尔排序 52 | 53 | ![这里写图片描述](http://img.blog.csdn.net/20170323112953578?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSmFja19fRnJvc3Q=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 54 | 55 | ## 时间复杂度 56 | 步长的选择是希尔排序的重要部分。只要最终步长为1任何步长序列都可以工作。 57 | 58 | 算法最开始以一定的步长进行排序。然后会继续以一定步长进行排序,最终算法以步长为1进行排序。当步长为1时,算法变为插入排序,这就保证了数据一定会被排序。 59 | 60 | Donald Shell 最初建议步长选择为N/2并且对步长取半直到步长达到1。虽然这样取可以比O(N2)类的算法(插入排序)更好,但这样仍然有减少平均时间和最差时间的余地。可能希尔排序最重要的地方在于当用较小步长排序后,以前用的较大步长仍然是有序的。比如,如果一个数列以步长5进行了排序然后再以步长3进行排序,那么该数列不仅是以步长3有序,而且是以步长5有序。如果不是这样,那么算法在迭代过程中会打乱以前的顺序,那就不会以如此短的时间完成排序了。 61 | 62 | ![这里写图片描述](http://img.blog.csdn.net/20170323113642034?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSmFja19fRnJvc3Q=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 63 | 64 | 已知的最好步长序列是由Sedgewick提出的(1, 5, 19, 41, 109,...),该序列的项来自这两个算式。 65 | 66 | 研究也表明“比较在希尔排序中是最主要的操作,而不是交换。”用这样步长序列的希尔排序比插入排序和堆排序都要快,甚至在小数组中比快速排序还快,但是在涉及大量数据时希尔排序还是比快速排序慢。 67 | 68 | ## 算法稳定性 69 | 希尔排序中相等数据可能会交换位置,所以希尔排序是不稳定的算法。 70 | 71 | # 五、快速排序 72 | ![这里写图片描述](http://img.blog.csdn.net/20170323121152224?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSmFja19fRnJvc3Q=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 73 | ## 时间复杂度 74 | 当数据有序时,以第一个关键字为基准分为两个子序列,前一个子序列为空,此时执行效率最差。而当数据随机分布时,以第一个关键字为基准分为两个子序列,两个子序列的元素个数接近相等,此时执行效率最好。所以,数据越随机分布时,快速排序性能越好;数据越接近有序,快速排序性能越差。 75 | 76 | ## 空间复杂度 77 | 快速排序在每次分割的过程中,需要 1 个空间存储基准值。而快速排序的大概需要 Nlog2N次 的分割处理,所以占用空间也是 Nlog2N 个。 78 | 79 | ## 算法稳定性 80 | 在快速排序中,相等元素可能会因为分区而交换顺序,所以它是不稳定的算法 81 | 82 | # 六、堆排序 83 | ![这里写图片描述](http://img.blog.csdn.net/20170323121905289?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSmFja19fRnJvc3Q=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 84 | ## 时间复杂度 85 | 堆的存储表示是顺序的。因为堆所对应的二叉树为完全二叉树,而完全二叉树通常采用顺序存储方式。 86 | 87 | 当想得到一个序列中第k个最小的元素之前的部分排序序列,最好采用堆排序。 88 | 89 | 因为堆排序的时间复杂度是O(n+klog2n),若k≤n/log2n,则可得到的时间复杂度为O(n)。 90 | 91 | ## 算法稳定性 92 | 一种不稳定的排序方法 93 | 94 | 因为在堆的调整过程中,关键字进行比较和交换所走的是该结点到叶子结点的一条路径, 95 | 96 | 因此对于相同的关键字就可能出现排在后面的关键字被交换到前面来的情况。 97 | 98 | # 七、归并排序 99 | ![这里写图片描述](http://img.blog.csdn.net/20170323122132431?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSmFja19fRnJvc3Q=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 100 | ## 时间复杂度 101 | 归并排序的形式就是一棵二叉树,它需要遍历的次数就是二叉树的深度,而根据完全二叉树的可以得出它的时间复杂度是O(n*log2n)。 102 | 103 | ## 空间复杂度 104 | 由前面的算法说明可知,算法处理过程中,需要一个大小为n的临时存储空间用以保存合并序列。 105 | 106 | ## 算法稳定性 107 | 在归并排序中,相等的元素的顺序不会改变,所以它是稳定的算法。 108 | 109 | # 八 、基数排序 110 | ![这里写图片描述](http://img.blog.csdn.net/20170323122828028?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSmFja19fRnJvc3Q=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 111 | ## 时间复杂度 112 | 通过上文可知,假设在基数排序中,r为基数,d为位数。则基数排序的时间复杂度为O(d(n+r))。 113 | 114 | 可以看出,基数排序的效率和初始序列是否有序没有关联。 115 | 116 | ## 空间复杂度 117 | 在基数排序过程中,对于任何位数上的基数进行“装桶”操作时,都需要n+r个临时空间。 118 | 119 | ## 算法稳定性 120 | 在基数排序过程中,每次都是将当前位数上相同数值的元素统一“装桶”,并不需要交换位置。所以基数排序是稳定的算法。 121 | 122 | # 比较: 123 | ## (1)直接插入排序和希尔排序的比较: 124 | 直接插入排序是稳定的;而希尔排序是不稳定的。 125 | 126 | 直接插入排序更适合于原始记录基本有序的集合。 127 | 128 | 希尔排序的比较次数和移动次数都要比直接插入排序少,当N越大时,效果越明显。 129 | 130 | 在希尔排序中,增量序列gap的取法必须满足:最后一个步长必须是 1 。 131 | 132 | 直接插入排序也适用于链式存储结构;希尔排序不适用于链式结构。 133 | 134 | ## (2)归并排序和堆排序、快速排序的比较 135 | 若从空间复杂度来考虑:首选堆排序,其次是快速排序,最后是归并排序。 136 | 137 | 若从稳定性来考虑,应选取归并排序,因为堆排序和快速排序都是不稳定的。 138 | 139 | 若从平均情况下的排序速度考虑,应该选择快速排序。 140 | 141 | 142 | -------------------------------------------------------------------------------- /项目笔记/Tomcat数据源配置方式.md: -------------------------------------------------------------------------------- 1 | tomcat数据库连接池服务器数据库jdbcoracle首先定义tomcat6的安装根目录为 ${CATALINA_HOME} 2 | 3 | > 在tomcat6版本中,context元素已经从server.xml文件中独立出来了,放在一个context.xml文件中。因为server.xml是不可动态重加载的资源,服务器一旦启动了以后,要修改这个文件,就得重启服务器才能重新加载。而context.xml文件则不然,tomcat服务器会定时去扫描这个文件。一旦发现文件被修改(时间戳改变了),就会自动重新加载这个文件,而不需要重启服务器。我们当然推荐把应用需要的JNDI资源配置在context.xml文件中,而不是server.xml文件中。 4 | 5 | 由于context元素的可用范围是可以控制的,我们可以根据需要为Context元素定义不同级别的可用范围。 6 | 7 | # 一、全局范围 8 | 9 | 全局可用的范围意味着tomcat服务器下面的所有应用都可以使用这个context元素定义的资源 10 | 11 | 全局可用范围的context元素在文件 ${CATALINA_HOME}/conf/context.xml 文件中描述。这个文件在tomcat刚刚被安装的时候,是没有定义任何资源的。我们可以看到,这个文件的内容: 12 | 13 | ```xml 14 | 15 | WEB-INF/web.xml 16 | 17 | ``` 18 | 19 | 其中的 \\WEB-INF/web.xml表示服务器会监视应用的WEB-INF/web.xml 文件来知道那个应用会引用在此处定义的资源。 20 | 21 | # 二、 指定的虚拟主机可用 22 | 23 | 指定的虚拟主机内可用就是说,在tomcat服务器配置的虚拟主机中,只有指定的那个虚拟主机上跑的应用才能使用。什么是虚拟主机和如何配置虚拟主机在这里就不描述了,有兴趣的同学自己去查tomcat的官方资料。要配置一个虚拟主机可用的context资源,可以在$/{CATALINA_HOME}/conf/目录下的文件 ${enginename}/${hostname}/context.xml.default 中表述。 24 | 25 | 比如,一般一个tomcat服务器安装好了以后,都有一个默认的叫做 Catalina 的引擎,在这个引擎下有一个叫做 localhost 的虚拟主机。我们的应用一般都放在这个虚拟主机下。关于这个虚拟主机的配置,不再本文表述,有兴趣的同学可以自己去查tomcat的官方文档。那么,如果我们想要配置一个在 Catalina/localhost 虚拟主机下都可以使用的资源,我们需要在目录 \${CATALINA_HOME}/conf 下建立路径 Catalina/localhost,在这个路径下创建文件 context.xml.default。全路径是 ${CATALINA_HOME}/conf/Catalina/localhost/context.xml.default 26 | 27 | # 三、指定的应用可用 28 | 29 | 顾名思义,一个指定的应用可用的context元素,意味着这是一个只有指定的引擎,指定的虚拟主机,指定的应用才可以使用的context元素。 30 | 31 | 如果我们用appname来代表这个指定的这个指定的应用的名字,那么元素的定义应该被放置在 \${CATALINA_HOME}/conf/\${enginename}/\${hostname}/${appname}.xml文件中。 32 | 33 | 例如,假设在localhost下我们有一个web应用叫做webtest,那么我们应该创建文件 ${CATALINA_HOME}/conf/Catalina/localhost/webtest.xml。 34 | 35 | # Tomcat6.0数据源配置 36 | 37 | ## 方法一: 38 | 39 | ### 1.配置tomcat下的conf下的context.xml文件,在之间添加连接池配置: 40 | 41 | ```xml 42 | 52 | ``` 53 | 54 | ### 2.配置你的应用下的web.xml中的之间加入: 55 | 56 | ```xml 57 | 58 | DB Connection 59 | jdbc/mydb 60 | javax.sql.DataSource 61 | Container 62 | 63 | ``` 64 | 65 | 在以往的tomcat当中还需要在web.xml指定相应的resource,在tomcat 5.5以后的版本不写也可以,但建议还是配置。 66 | 67 | ### 3.把连接数据库的第三方驱动放到\${CATALINA_HOME}/lib下面就ok了 68 | 69 | ### 4.测试程序test.jsp如下: 70 | 71 | ```jsp 72 | <%@ page import="javax.naming.*"%> 73 | <%@ page import="java.sql.*"%> 74 | <%@ page import="javax.sql.*"%> 75 | <% 76 | Context initContext = new InitialContext(); 77 | Context envContext = (Context)initContext.lookup("java:/comp/env"); 78 | DataSource ds = (DataSource)envContext.lookup("jdbc/myoracle"); 79 | Connection conn = ds.getConnection(); 80 | conn.close(); 81 | %> 82 | ``` 83 | 84 | ## 方法二: 85 | 86 | 我们只需要在WebRoot目录下,新建一个META-INF的目录(假如不存在,注意目录名称大写), 87 | 在该目录下创建一个context.xml文件,并且在context.xml文件当添加以下的配置信息: 88 | 89 | ```xml 90 | 91 | 102 | 103 | ``` 104 | 105 | 其中: 106 | name 表示指定的jndi名称 107 | auth 表示认证方式,一般为Container 108 | type 表示数据源床型,使用标准的javax.sql.DataSource 109 | maxActive 表示连接池当中最大的数据库连接 110 | maxIdle 表示最大的空闲连接数 111 | maxWait 当池的数据库连接已经被占用的时候,最大等待时间 112 | logAbandoned 表示被丢弃的数据库连接是否做记录,以便跟踪 113 | username 表示数据库用户名 114 | password 表示数据库用户的密码 115 | driverClassName 表示JDBC DRIVER 116 | url 表示数据库URL地址 117 | 118 | 此方法二一样适用Tomcat5.5 119 | 120 | # Tomcat5.5x数据源配置 121 | 122 | ## 方式一、全局数据库连接池 123 | 124 | ### 1、通过管理界面配置连接池,或者直接在${CATALINA_HOME}/conf/server.xml的GlobalNamingResources中增加 125 | 126 | ```xml 127 | 136 | ``` 137 | 138 | ### 2、在${CATALINA_HOME}/webapps/myapp/META-INF/context.xml的Context中增加: 139 | 140 | ```xml 141 | 142 | ``` 143 | 144 | 这样就可以了。 145 | 146 | ## 方式二、全局数据库连接池 147 | 148 | 1、同上 149 | 2、在${CATALINA_HOME}/conf/context.xml的Context中增加: 150 | 151 | ```xml 152 | 153 | ``` 154 | 155 | ## 方式三、局部数据库连接池 156 | 157 | 只需在\${CATALINA_HOME}/webapps/myapps/META-INF/context.xml的Context中增加: 158 | 159 | ```xml 160 | 165 | ``` 166 | 167 | -------------------------------------------------------------------------------- /项目笔记/JavaWeb Dao层设计.md: -------------------------------------------------------------------------------- 1 | # Java Web Dao层设计 2 | 3 | ## UML设计图 4 | 5 | ![Dao层设计](http://upload-images.jianshu.io/upload_images/1540531-0a72df3b938f78a2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 6 | 7 | ## 实体类 8 | 9 | ```java 10 | package cn.zzuli.oa.domain; 11 | 12 | public class Role { 13 | 14 | } 15 | ``` 16 | 17 | ```java 18 | package cn.zzuli.oa.domain; 19 | 20 | public class User { 21 | 22 | private Long id; 23 | private String username; 24 | 25 | public User() { 26 | super(); 27 | } 28 | 29 | public Long getId() { 30 | return id; 31 | } 32 | 33 | public void setId(Long id) { 34 | this.id = id; 35 | } 36 | 37 | public String getUsername() { 38 | return username; 39 | } 40 | 41 | public void setUsername(String username) { 42 | this.username = username; 43 | } 44 | 45 | } 46 | ``` 47 | 48 | ## BaseDao接口 49 | 50 | ```java 51 | package cn.zzuli.oa.base; 52 | 53 | import java.util.List; 54 | 55 | public interface BaseDao { 56 | 57 | /** 58 | * 保存实体 59 | * @param entity 60 | */ 61 | void save(T entity); 62 | 63 | /** 64 | * 删除实体 65 | * @param id 66 | */ 67 | void delete(Long id); 68 | 69 | /** 70 | * 更新实体 71 | * @param entity 72 | */ 73 | void update(T entity); 74 | 75 | /** 76 | * 77 | * @param id 78 | * @return 79 | */ 80 | T getById(Long id); 81 | 82 | /** 83 | * 查询实体 84 | * @param ids id的集合 85 | * @return 86 | */ 87 | List listByIds(Long[] ids); 88 | 89 | /** 90 | * 查询所有 91 | * @return 92 | */ 93 | List listAll(); 94 | 95 | } 96 | ``` 97 | 98 | ## BaseDaoImpl代码,实现BaseDao接口 99 | 100 | ```java 101 | package cn.zzuli.oa.base.impl; 102 | 103 | import java.lang.reflect.ParameterizedType; 104 | import java.util.Collections; 105 | import java.util.List; 106 | 107 | import javax.annotation.Resource; 108 | 109 | import org.hibernate.Session; 110 | import org.hibernate.SessionFactory; 111 | 112 | import cn.zzuli.oa.base.BaseDao; 113 | 114 | @SuppressWarnings("unchecked") 115 | public abstract class BaseDaoImpl implements BaseDao { 116 | 117 | @Resource 118 | private SessionFactory sessionFactory; 119 | 120 | protected Class clazz; 121 | 122 | public BaseDaoImpl() { 123 | //通过反射得到T的真实类型 124 | ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();//获取这个父类的泛型类型 125 | this.clazz = (Class) pt.getActualTypeArguments()[0]; //获取第一个泛型T的类型 126 | 127 | System.out.println("clazz = " + clazz.getName()); 128 | } 129 | 130 | 131 | @Override 132 | public void save(T entity) { 133 | getSession().save(entity); 134 | } 135 | 136 | @Override 137 | public void delete(Long id) { 138 | Object obj = getSession().get(clazz, id); 139 | getSession().delete(obj); 140 | } 141 | 142 | @Override 143 | public void update(T entity) { 144 | getSession().update(entity); 145 | } 146 | 147 | @Override 148 | public T getById(Long id) { 149 | return (T) getSession().get(clazz, id); 150 | } 151 | 152 | @Override 153 | public List listByIds(Long[] ids) { 154 | if (ids == null || ids.length == 0) { 155 | return Collections.EMPTY_LIST; 156 | } 157 | return getSession().createQuery("FROM " + clazz.getSimpleName() + " WHERE id IN(:ids)") 158 | .setParameterList("ids", ids).list(); 159 | } 160 | 161 | @Override 162 | public List listAll() { 163 | return getSession().createQuery("FROM " + clazz.getSimpleName()).list(); 164 | } 165 | 166 | /** 167 | * 获取当前可用的Session 168 | * 169 | * @return 当前可用的Session 170 | */ 171 | protected Session getSession() { 172 | return sessionFactory.getCurrentSession(); 173 | } 174 | 175 | } 176 | ``` 177 | 178 | ## RoleDao接口,继承BaseDao 179 | 180 | ```java 181 | package cn.zzuli.oa.dao; 182 | 183 | import cn.zzuli.oa.base.BaseDao; 184 | import cn.zzuli.oa.domain.Role; 185 | 186 | public interface RoleDao extends BaseDao { 187 | 188 | } 189 | ``` 190 | 191 | ## UserDao接口,继承BaseDao 192 | 193 | > UserDao实现类UserDaoImpl可以实现的自己的功能代码 194 | 195 | ```java 196 | package cn.zzuli.oa.dao; 197 | 198 | import cn.zzuli.oa.base.BaseDao; 199 | import cn.zzuli.oa.domain.User; 200 | 201 | public interface UserDao extends BaseDao{ 202 | 203 | } 204 | ``` 205 | 206 | ## RoleDaoImpl代码,继承BaseDaoImpl,实现RoleDao 207 | 208 | ```java 209 | package cn.zzuli.oa.dao.impl; 210 | 211 | import org.springframework.stereotype.Repository; 212 | 213 | import cn.zzuli.oa.base.impl.BaseDaoImpl; 214 | import cn.zzuli.oa.dao.RoleDao; 215 | import cn.zzuli.oa.domain.Role; 216 | 217 | @Repository 218 | public class RoleDaoImpl extends BaseDaoImpl implements RoleDao { 219 | 220 | } 221 | ``` 222 | 223 | ## UserDaoImpl代码,继承BaseDaoImpl,实现UserDao 224 | 225 | ```java 226 | package cn.zzuli.oa.dao.impl; 227 | 228 | import org.springframework.stereotype.Repository; 229 | 230 | import cn.zzuli.oa.base.impl.BaseDaoImpl; 231 | import cn.zzuli.oa.dao.UserDao; 232 | import cn.zzuli.oa.domain.User; 233 | 234 | @Repository 235 | public class UserDaoImpl extends BaseDaoImpl implements UserDao{ 236 | 237 | } 238 | ``` 239 | 240 | ## 测试类 241 | 242 | ```java 243 | package cn.zzuli.oa.base; 244 | 245 | import org.junit.Test; 246 | 247 | import cn.zzuli.oa.dao.RoleDao; 248 | import cn.zzuli.oa.dao.UserDao; 249 | import cn.zzuli.oa.dao.impl.RoleDaoImpl; 250 | import cn.zzuli.oa.dao.impl.UserDaoImpl; 251 | import cn.zzuli.oa.domain.Role; 252 | import cn.zzuli.oa.domain.User; 253 | 254 | public class BaseDaoTest { 255 | 256 | @Test 257 | public void testGetById() { 258 | UserDao userDao = new UserDaoImpl(); 259 | RoleDao roleDao = new RoleDaoImpl(); 260 | 261 | } 262 | 263 | } 264 | ``` 265 | 266 | ## 实现效果 267 | 268 | ![实现效果](http://upload-images.jianshu.io/upload_images/1540531-56ac78980d7b3c81.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 269 | 270 | 此处输出的正是BaseDao实现类BaseDaoImple中构造方法获取的泛型的类型, -------------------------------------------------------------------------------- /数据结构/基础知识/(9)哈希表/哈希表(散列表).md: -------------------------------------------------------------------------------- 1 | # 散列技术 2 | 3 | 在记录的存储位置和它的关键字之间建立一个确定的对应关系f,使得每个关键字key对应一个存储位置f(key)。既是存储方法也是查找方法。 4 | 散列技术将记录存储在一块连续的存储空间中,这块连续存储空间称为散列表。 5 | 散列技术也不具备很多常规数据结构的能力。比如:1. 一个关键字对应多个记录的情况;2.也不适合于范围查找。 6 | 7 | ## 设计原则: 8 | 1.计算简单。保证存储和查找耗费少量时间。 9 | 2.散列地址分布均匀。进来让散列地址均匀分布在存储空间中,保证存储空间有效利用,并减少处理冲突耗费的时间。 10 | 11 | ## 构造的方法: 12 | ### 1.直接定址法: 13 | 如F(key)=a*key+b;这样一个线性的函数式的。 14 | 优点:简单均匀,也不会产生冲突,但要求是:事先知道关键字的分布情况。 15 | 适合查找表较小且连续的情况。 16 | 17 | ### 2.数字分析法: 18 | 使用关键字的一部分来计算散列存储位置的方法。 19 | 适合处理关键字位数比较大的情况。如果事先知道关键字的分布且关键字的若干位分布较均匀,即可考虑这方法。 20 | 21 | ### 3.平分取中法: 22 | 如:1234,平方为1522756,取中为227. 23 | 适合于不知道关键字的分布,而位数又不是很大的情况。 24 | 25 | ### 4.折叠法: 26 | 将关键字从左到右分割成位数相等的几部分,将几部分叠加求和。 27 | 适合事先不需要知道关键字的分布,适合关键字位数较多的情况。 28 | 29 | ### 5.除留余数法: 30 | 如f(key)=key mod p(p<=m),mod是取模(取余)。 31 | 若散列表表长为m,通常p小于或等于表长(最好接近m)的最小质数或不包含小于20质因子的合数。 32 | 33 | ## 构造设计散列函数的因素: 34 | ### 1.计算散列地址所需的时间 35 | ### 2.关键字的长度 36 | ### 3.散列表的大小 37 | ### 4.关键字的分布情况 38 | ### 5.记录查找的频率。 39 | # 处理冲突的方法:(冲突是不可避免的!) 40 | ## (1)开放定址法: 41 | 即:一旦发生冲突,就去寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到,并将记录存入。 42 | 43 | ### 分类 44 | #### 线性探测法 45 | 46 | 就是冲突了就直接寻找判断它后面的一个位置是否空,空则插入,非空则继续找后一个。存在的问题:出现本来都不是同义词却需要争夺一个地址的情况(堆积)。 47 | 48 | #### 二次探测法 49 | 50 | 例子: 51 | 52 | 目的是为了不让关键字都聚集在某一块区域。 53 | 54 | ![这里写图片描述](http://img.blog.csdn.net/20170401122151042?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSmFja19fRnJvc3Q=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 55 | #### 随机探测法: 56 | 在冲突时,对于位移量di采用随机函数计算。 57 | 58 | ## (2)再散列函数法: 59 | 每当发生散列地址冲突时,就换一个散列函数计算。使得关键字不产生聚集,但也增加了计算时间。 60 | 61 | ## (3)链地址法: 62 | ![这里写图片描述](http://img.blog.csdn.net/20170401124944321?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSmFja19fRnJvc3Q=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 63 | 64 | 对于很可能造成冲突的散列函数来说,提供了绝不会出现 找不到地址的保障。但也带来查找时候的遍历单链表的性能损耗。 65 | 66 | ## (4)公共溢出区法: 67 | ![这里写图片描述](http://img.blog.csdn.net/20170401125223822?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSmFja19fRnJvc3Q=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 68 | 69 | 凡是冲突的都找一个公共溢出区去存放。查找的时候,对给定值通过散列函数计算出散列地址后,先与基本表的响应位置进行对比,如果相等则查找成功;如果不相等,则到溢出表去进行顺序查找。 70 | 71 | 对于基本表,有冲突的数据很少的情况下,公共溢出区的结构对查找性能是很高的。 72 | 73 | # 哈希表经验总述: 74 | ## (1)哈希寻址 75 | 76 | 根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。 77 | 对比:数组的特点是:寻址容易,插入和删除困难;而链表的特点是:寻址困难,插入和删除容易。哈希则是一种寻址容易,插入删除也容易的数据结构。 78 | 79 | ## (2)哈希的应用: 80 | 81 | ### 1、作用领域 82 | 83 | Hash主要用于信息安全领域中加密算法,它把一些不同长度的信息转化成杂乱的128位的编码,这些编码值叫做Hash值. 也可以说,Hash就是找到一种数据内容和数据存放地址之间的映射关系 84 | 85 | ### 2、查找 86 | 87 | 哈希表,又称为散列,是一种更加快捷的查找技术。我们之前的查找,都是这样一种思路:集合中拿出来一个元素,看看是否与我们要找的相等,如果不等,缩小范围,继续查找。而哈希表是完全另外一种思路:当我知道key值以后,我就可以直接计算出这个元素在集合中的位置,根本不需要一次又一次的查找! 88 | 89 | 举一个例子,假如我的数组A中,第i个元素里面装的key就是i,那么数字3肯定是在第3个位置,数字10肯定是在第10个位置。哈希表就是利用利用这种基本的思想,建立一个从key到位置的函数,然后进行直接计算查找。 90 | 91 | ### 3、应用 92 | 93 | Hash表在海量数据处理中有着广泛应用。查询速度非常的快,几乎是O(1)的时间复杂度. 94 | 95 | ## (3)实现步骤: 96 | 当存储记录时,通过散列函数计算出记录的散列地址 97 | 98 | 当查找记录时,我们通过同样的是散列函数计算记录的散列地址,并按此散列地址访问该记录 99 | 100 | ## (4)优缺点: 101 | ### 优点 102 | 103 | 不论哈希表中有多少数据,查找、插入、删除(有时包括删除)只需要接近常量的时间即0(1)的时间级。实际上,这只需要几条机器指令。 104 | 105 | ### 缺点 106 | 107 | 它是基于数组的,数组创建后难于扩展,某些哈希表被基本填满时,性能下降得非常严重,所以程序员必须要清楚表中将要存储多少数据(或者准备好定期地把数据转移到更大的哈希表中,这是个费时的过程)。 108 | 109 | ## (5)查找性能分析: 110 | #### 1.散列函数是否均匀 111 | #### 2.处理冲突的方法 112 | #### 3.散列表的装填因子 113 | 装填因子a=填入表中的记录个数/散列表长度。a表示散列表的装满的程度。填入记录越多,a越大,产生冲突的可能性越大。 114 | 115 | # 实现:(使用除留余数法和线性探测法) 116 | ## 哈希表结构: 117 | ``` 118 | private int manyItems; //哈希表大小 119 | private Object[] keys; //键 120 | private Object[] values; //值 121 | private boolean[] hasBeenUsed;//判断这个键是否存了数据value 122 | } 123 | ``` 124 | ## 初始化: 125 | ``` 126 | public Table(int capacity){ 127 | if(capacity <= 0){ 128 | throw new IllegalArgumentException("Capacity is negative."); 129 | } 130 | keys = new Object[capacity]; 131 | values =new Object[capacity]; 132 | hasBeenUsed = new boolean[capacity]; 133 | } 134 | ``` 135 | ## 判空 136 | ``` 137 | /** 138 | * 判断表是否为空 139 | * @return 140 | */ 141 | public boolean isEmpty(){ 142 | return manyItems == 0; 143 | } 144 | ``` 145 | ## 清空表: 146 | ``` 147 | //保证线程安全 148 | public synchronized void clear() { 149 | if(manyItems !=0){ 150 | for(int i = 0;i < values.length;i++){ 151 | keys[i]=null; //把键、值、以及判占用标志都清空。 152 | values[i]=null; 153 | hasBeenUsed[i]=false; 154 | } 155 | manyItems = 0; //大小变0 156 | } 157 | } 158 | ``` 159 | ## 判断是否存在指定的关键字 160 | ``` 161 | public boolean containsKey(Object key) { 162 | 163 | return findIndex(key)!=-1; 164 | } 165 | ``` 166 | ## 获取关键字 167 | ``` 168 | public Object get(Object key) { 169 | int index = findIndex(key); 170 | if(index!=-1){ 171 | return values[index]; 172 | } 173 | return null; 174 | } 175 | ``` 176 | ## 计算散列码: 177 | ``` 178 | /** 179 | * 获取散列码,大小不超过表的大小 180 | */ 181 | public int hash(Object key){ 182 | //返回的是存放在该values数组的位置 183 | //其实就是返回key%length 184 | return Math.abs(key.hashCode())%values.length; 185 | } 186 | ``` 187 | ## 把索引指向下一位 188 | ``` 189 | public int nextIndex(int index){ 190 | if(index+1 == values.length){ 191 | return 0; 192 | }else{ 193 | return index + 1; 194 | } 195 | } 196 | ``` 197 | ## 判断指定的位置是否已经被使用 198 | ``` 199 | /** 200 | * 判断指定的位置是否已经被使用 201 | */ 202 | public boolean hasBeenUsed(int index){ 203 | return hasBeenUsed[index]; 204 | } 205 | ``` 206 | ## 根据key查找关键字 207 | 208 | ? 如果在表中找到了指定的关键字,返回指定关键字的索引。否则返回 -1.(没找到的时候) 209 | 210 | ``` 211 | public int findIndex(Object key){ 212 | int count = 0; 213 | int i = hash(key); 214 | while((count < values.length) && hasBeenUsed[i]){ 215 | //分配的位置已经被使用,而且存在指定的关键字 216 | if(keys[i].equals(key)){ 217 | return i; 218 | } 219 | //编辑遍历的次数,当全部元素都遍历完之后,退出遍历 220 | count++; 221 | i = nextIndex(i); 222 | } 223 | return -1; 224 | } 225 | ``` 226 | ## 返回该表中当前有多少对键值对。 227 | ``` 228 | public int size() { 229 | return manyItems; 230 | } 231 | ``` 232 | ## 插入关键字进散列表: 233 | ``` 234 | public synchronized Object put(Object key, Object value) { 235 | int i = findIndex(hash(key)); // 236 | Object temp = null; 237 | if(i != -1){ 238 | //表中已经存在该关键字 239 | temp = values[i]; 240 | values[i] = value; //替换内容 241 | //返回被替换的内容 242 | return temp; 243 | }else if(manyItems < values.length){ 244 | //表中不存在该关键字且表未满 245 | //返回的是存放在该keys数组的位置 246 | i = hash(key); 247 | //检查散列码是否有冲突 248 | if(keys[i]!= null){ 249 | //散列码有冲突,索引往后移一位 250 | i = nextIndex(i); 251 | } 252 | keys[i] = key; //强制赋值 253 | values[i]= value; 254 | hasBeenUsed[i] = true; 255 | manyItems ++; 256 | return null; 257 | }else{ 258 | //表已满 259 | throw new IllegalStateException("Table is full"); 260 | } 261 | ``` 262 | ## 删除数据 263 | ``` 264 | public synchronized Object remove(Object key) { 265 | int index = findIndex(key); //老套路,hash计算出位置先 266 | Object result = null; 267 | if(index!=-1){ 268 | result = values[index]; //不等空就拿暂存变量输出它 269 | keys[index]= null; //然后把三个值清空 270 | values[index]= null; 271 | hasBeenUsed[index]=false; 272 | manyItems --; 273 | } 274 | return result; 275 | } 276 | ``` 277 | -------------------------------------------------------------------------------- /项目笔记/关于页面获取数据.md: -------------------------------------------------------------------------------- 1 | # EL(Excepress Language表达式语言) 2 | 3 | ## 1、所有的EL都是以$"{"开始,以"}"结尾的 4 | 5 | 例:${sessionScope.user.sex}(sessionScope是EL的内置对象,后面会讲到).该例子的意思是:从session中取得用户的性别.相当于下面的代码 6 | 7 | ```jsp 8 | <% 9 | User user=(User)session.getParameter("user"); 10 | String sex=user.getSex(); 11 | %> 12 | ``` 13 | 14 | ## 2、EL提供"."和"[ ]"两种运算符来存取数据,[]可以访问集合或者数组的元素,Bean的属性 15 | 16 | 下列两者所代表的意思是一样的,但是需要保证要取得对象的哪个的属性有相应的setXxx()和getXxx()方法才行(即符合JavaBean规范) 17 | 18 | 例:\${sessionScope.user.sex} <=======> ${session.user["sex"]}. 19 | 20 | "."和"[]"也可以混合使用,如下:${sessionScope.shoppingCart[0].price} 返回结果为shoppingCart中第一项物品的价格 21 | 在EL中,字符串即可以用"abc",也可以使用'abc'; 22 | 23 | ## 3、EL运算符 24 | 25 | EL的算术运算符和JAVA中的运算符大致相同,优先级也相同,区别在于"+"运算符不会连接字符串,只用于加法运算; 26 | EL关系运算符有以下6个 27 | 关系运算符号 说明 举例 结果 28 | ==或eq(equal) 等于 \${5==5}或${5eq5} true 29 | !=或ne(not equal) 不等于 \${5!=5}或${5eq5} false 30 | <或lt(less than) 小于 \${3!=5}或${3lt5} true或gt(great than) 大于 略 31 | <=或le 小于等于 略 32 | =或ge 大于等于 略 33 | 34 | ## 4、empty运算符 35 | 36 | empty运算符主要用来判断值是否为null或空的,如果为空或null就返回true. 例如 \${empty param.name}(param内置对象,后面讲解) 37 | 38 | ## 5、使用EL从表达中取得数据 39 | 40 | 与输入有关的隐含对象有两个:param和paramValues,他们两个是EL中的内置对象.一般而言,我们在取得用户的请求参数时,可以利用下列方法:request.getParameter(String name)和request.getParameterValues(String name),而在EL中可以是用param和paramValues两者来取得数据.以上的两句等价于\${param.name}和\${paramValues.name},而${paramValues.hobbies[0]}可以通过指定下标来访问特定的参数的值; 41 | 42 | ## EL的内置对象 43 | 44 | 属性范围 在EL中的对象 45 | page pageScope 46 | request requestScope 47 | session sessionScope 48 | application applicationScope 49 | 在EL中使用内置对象的属性${requestScope.user}等价于<%=request.getParameter("user")%>. 如果不指定范围,那就会在不同的范围间进行搜索. 50 | 51 | | 对象 | 类型 | 说明 | 52 | | :--------------: | :--------------------------: | :--------------------------------------: | 53 | | PageContext | javax.servlet.ServletContext | 表示此JSP的PageContext | 54 | | PageScope | java.util.Map | 取得Page范围的属性名称所对应的值 | 55 | | RequestScope | java.util.Map | 取得Request范围的属性名称所对应的值 | 56 | | sessionScope | java.util.Map | 取得Session范围的属性名称所对应的值 | 57 | | applicationScope | java.util.Map | 取得Application范围的属称所对应的值 | 58 | | param | java.util.Map | 如同ServletRequest.getParameter(String\|\|name)返回String类型的值 | 59 | | paramValues | java.util.Map | 如同ServletRequest.getParameterValues(String name)。返回String []类型的值 | 60 | | header | java.util.Map | 如同ServletRequest.getHeader(String name)返回String类型的值 | 61 | | headerValues | java.util.Map | 如同ServletRequest.getHeaders(String name)。返回String []类型的值 | 62 | | cookie | java.util.Map | 如同HttpServletRequest.getCookies() | 63 | | initParam | java.util.Map | 如同ServletContext.getInitParameter(String name)。返回String类型的值 | 64 | 65 | ### pageContext对象 66 | 67 | 我们可以使用 ${pageContext}来取得其他有关用户要求或页面的详细信息。下面列出了几个比较常用的部分。 68 | 69 | | Expression | 说 明 | 70 | | :--------------------------------------: | :--------------------------------------: | 71 | | ${pageContext.request} | 取得请求对象 | 72 | | ${pageContext.session} | 取得session对象 | 73 | | ${pageContext.request.queryString} | 取得请求的参数字符串 | 74 | | ${pageContext.request.requestURL} | 取得请求的URL,但不包括请求之参数字符串 | 75 | | ${pageContext.request.contextPath} | 服务的web application的名称 | 76 | | ${pageContext.request.method} | 取得HTTP的方法(GET、POST) | 77 | | ${pageContext.request.protocol} | 取得使用的协议(HTTP/1.1、HTTP/1.0) | 78 | | ${pageContext.request.remoteUser} | 取得用户名称 | 79 | | ${pageContext.request.remoteAddr } | 取得用户的IP地址 | 80 | | ${pageContext.session.new} | 判断session是否为新的,所谓新的session,表示刚由 server产生而client尚未使用 | 81 | | ${pageContext.session.id} | 取得session的ID | 82 | | ${pageContext.servletContext.serverInfo} | 取得主机端的服务信息 | 83 | 84 | # JSTL(JSP标准标签库) 85 | 86 | > JSTL由核心标签,\ ,xml解析标签 \,国际化标签 \,数据库访问标签\,函数标签\ 87 | 88 | 核心标签 89 | 90 | ```jsp 91 | <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> 92 | ``` 93 | 94 | 属性设置 95 | 96 | ```xml 97 | 设置属性 98 | 移除设置的属性 99 | ``` 100 | 101 | 过程控制 102 | 103 | ```xml 104 | 条件标签 只有在test属性的值为true是才会执行标签体 105 | 例: 106 | 107 |

hello

108 |
109 | ``` 110 | 111 | \choose和when是组合在一起使用的,有点类似于switch case的语法 。 112 | \when也是条件判断标签,test属性的值为true是才会执行标签体。 113 | 114 | ```xml 115 | 116 | 117 |

you is a child

118 | 119 | 120 |

you is a young person

121 |
122 | 123 |

you is a old person

124 |
125 | 126 | ``` 127 | 128 | \迭代标签 129 | 130 | ```xml 131 | 132 |

${book.parice}

133 |
134 | 135 |

hello

136 |
137 | ``` 138 | 139 | # 声明: 140 | 141 | ## $ 符号是EL表达式用的 142 | 143 | ## % 是jsp代码用的 144 | 145 | 是OGNL表达式用的,存放的值在根目录下才用#,有时候OGNL表达式不允许嵌套OGNL表达式,但是又必须要使用他,那么你可以用 %表达式 来实现嵌套 146 | 147 | ## jsp页面引入标签库: 148 | 149 | ```jsp 150 | <%@taglib prefix="s" uri="/struts-tags"%> 151 | ``` 152 | 153 | 在web.xml中声明要使用的标签 154 | 155 | ```xml 156 | 157 | struts2 158 | org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter 159 | 160 | ``` 161 | 162 | ## jsp页面读取action中属性在页面输出 163 | 164 | ```jsp 165 | 167 | 168 | 169 | 170 |   171 | 172 | 173 | 174 | 176 | 177 | 186 | ``` 187 | 188 | ## 用java代码代替的,访问某一个范围内的属性 189 | 190 | // 验证#attr搜索顺序是从page开始的,搜索的顺序为:page,reques,session,application。 191 | 192 | \ 193 | 194 | 获取的是requet中的对象值 195 | 196 | 方法一:\ 197 | 198 | 方法二:\ 199 | 200 | 方法三:\ 201 | 202 | 方法四:\ 203 | 204 | 方法五:${requestScope.user.userName} 205 | 206 | 方法六:\ attr按page,request,sessionapplication 207 | 208 | 获取session中的值: 209 | 210 | ```xml 211 | 212 | ``` 213 | 214 | 获取application中值: 215 | 216 | ```xml 217 | 218 | ``` 219 | 220 | -------------------------------------------------------------------------------- /POI/ExcelExportSXXSSF.java: -------------------------------------------------------------------------------- 1 | import java.io.FileOutputStream; 2 | import java.lang.reflect.Method; 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.apache.poi.ss.usermodel.Cell; 7 | import org.apache.poi.ss.usermodel.Row; 8 | import org.apache.poi.ss.usermodel.Sheet; 9 | import org.apache.poi.xssf.streaming.SXSSFSheet; 10 | import org.apache.poi.xssf.streaming.SXSSFWorkbook; 11 | /** 12 | * excel导出的封装类 13 | */ 14 | public class ExcelExportSXXSSF { 15 | 16 | // 定义工作表 17 | private SXSSFWorkbook wb; 18 | 19 | /** 20 | * 定义工作表中的sheet 21 | */ 22 | private Sheet sh; 23 | 24 | 25 | /** 26 | * 定义保存在内存中的数量,-1表示手动控制 27 | */ 28 | private int flushRows; 29 | /** 导出文件行数 */ 30 | private int rownum; 31 | /** 导出文件列数 */ 32 | private int colnum; 33 | 34 | /** 导出文件的存放路径 */ 35 | private String filePath; 36 | /** 下载导出文件的路径 */ 37 | private String fileWebPath; 38 | /**文件名称前缀*/ 39 | private String filePrefix; 40 | /**导出文件全路径*/ 41 | private String fileAllPath; 42 | /** 导出文件列标题 */ 43 | private List fieldNames; 44 | /**导出文件每列代码,用于反射获取对象属性值*/ 45 | private List fieldCodes; 46 | 47 | private ExcelExportSXXSSF() { 48 | 49 | } 50 | 51 | /** 52 | * 开始导出方法 53 | * 54 | * @param filePath 55 | * 导出文件存放物理路径 56 | * @param fileWebPath 57 | * 导出文件web下载路径 58 | * @param filePrefix 59 | * 导出文件名的前缀 60 | * @param flushRows 61 | * 存放在内存的数据量 62 | * @param fieldNames 63 | * 导出文件列标题 64 | * @param fieldCodes 65 | * 导出数据对象的字段名称 66 | * @param flushRows 67 | * 写磁盘控制参数 68 | * @return 69 | */ 70 | public static ExcelExportSXXSSF start(String filePath, String fileWebPath,String filePrefix, 71 | List fieldNames,List fieldCodes, int flushRows) throws Exception { 72 | ExcelExportSXXSSF excelExportSXXSSF = new ExcelExportSXXSSF(); 73 | excelExportSXXSSF.setFilePath(filePath); 74 | excelExportSXXSSF.setFileWebPath(fileWebPath); 75 | excelExportSXXSSF.setFilePrefix(filePrefix); 76 | excelExportSXXSSF.setFieldNames(fieldNames); 77 | excelExportSXXSSF.setFieldCodes(fieldCodes); 78 | excelExportSXXSSF.setWb(new SXSSFWorkbook(flushRows));//创建workbook 79 | excelExportSXXSSF.setSh(excelExportSXXSSF.getWb().createSheet());//创建sheet 80 | excelExportSXXSSF.writeTitles(); 81 | return excelExportSXXSSF; 82 | } 83 | 84 | /** 85 | * 设置导入文件的标题 86 | * 开始生成导出excel的标题 87 | * @throws Exception 88 | */ 89 | private void writeTitles() throws Exception { 90 | rownum = 0;//第0行 91 | colnum = fieldNames.size();//根据列标题得出列数 92 | Row row = sh.createRow(rownum); 93 | for (int cellnum = 0; cellnum < colnum; cellnum++) { 94 | Cell cell = row.createCell(cellnum); 95 | cell.setCellValue(fieldNames.get(cellnum)); 96 | } 97 | } 98 | 99 | /** 100 | * 向导出文件写数据 101 | * 102 | * @param datalist 103 | * 存放Object对象,仅支持单个自定义对象,不支持对象中嵌套自定义对象 104 | * @return 105 | */ 106 | public void writeDatasByObject(List datalist) throws Exception { 107 | 108 | for (int j = 0; j < datalist.size(); j++) { 109 | rownum = rownum + 1; 110 | Row row = sh.createRow(rownum); 111 | for (int cellnum = 0; cellnum < fieldCodes.size(); cellnum++) { 112 | Object owner = datalist.get(j); 113 | Object value = invokeMethod(owner, fieldCodes.get(cellnum), 114 | new Object[] {}); 115 | Cell cell = row.createCell(cellnum); 116 | cell.setCellValue(value!=null?value.toString():""); 117 | } 118 | 119 | } 120 | 121 | } 122 | /** 123 | * 向导出文件写数据 124 | * 125 | * @param datalist 126 | * 存放字符串数组 127 | * @return 128 | */ 129 | public void writeDatasByString(List datalist) throws Exception { 130 | rownum = rownum + 1; 131 | Row row = sh.createRow(rownum); 132 | int datalist_size = datalist.size(); 133 | for (int cellnum = 0; cellnum < colnum; cellnum++) { 134 | Cell cell = row.createCell(cellnum); 135 | if(datalist_size>cellnum){ 136 | cell.setCellValue(datalist.get(cellnum)); 137 | }else{ 138 | cell.setCellValue(""); 139 | } 140 | 141 | } 142 | } 143 | 144 | /** 145 | * 手动刷新方法,如果flushRows为-1则需要使用此方法手动刷新内存 146 | * 147 | * @param flushNum 148 | * @throws Exception 149 | */ 150 | public void flush(int flushNum) throws Exception { 151 | ((SXSSFSheet) sh).flushRows(flushNum); 152 | } 153 | 154 | /** 155 | * 导出文件 156 | * 157 | * @throws Exception 158 | */ 159 | public String exportFile() throws Exception { 160 | String filename = filePrefix+"_"+MyUtil.getCurrentTimeStr() + ".xlsx"; 161 | FileOutputStream out = new FileOutputStream(filePath + filename); 162 | wb.write(out); 163 | out.flush(); 164 | out.close(); 165 | setFileAllPath(fileWebPath + filename); 166 | return fileWebPath + filename; 167 | } 168 | 169 | /** 170 | * 反射方法,通过get方法获取对象属性 171 | * 172 | * @param owner 173 | * @param fieldname 174 | * @param args 175 | * @return 176 | * @throws Exception 177 | */ 178 | private Object invokeMethod(Object owner, String fieldname, Object[] args) 179 | throws Exception { 180 | 181 | String methodName = "get" + fieldname.substring(0, 1).toUpperCase() 182 | + fieldname.substring(1); 183 | Class ownerClass = owner.getClass(); 184 | 185 | Class[] argsClass = new Class[args.length]; 186 | 187 | for (int i = 0, j = args.length; i < j; i++) { 188 | argsClass[i] = args[i].getClass(); 189 | } 190 | 191 | Method method = ownerClass.getMethod(methodName, argsClass); 192 | return method.invoke(owner, args); 193 | } 194 | 195 | public SXSSFWorkbook getWb() { 196 | return wb; 197 | } 198 | 199 | public void setWb(SXSSFWorkbook wb) { 200 | this.wb = wb; 201 | } 202 | 203 | public Sheet getSh() { 204 | return sh; 205 | } 206 | 207 | public void setSh(Sheet sh) { 208 | this.sh = sh; 209 | } 210 | 211 | 212 | public int getFlushRows() { 213 | return flushRows; 214 | } 215 | 216 | public void setFlushRows(int flushRows) { 217 | this.flushRows = flushRows; 218 | } 219 | 220 | public String getFilePath() { 221 | return filePath; 222 | } 223 | 224 | public void setFilePath(String filePath) { 225 | this.filePath = filePath; 226 | } 227 | 228 | public String getFileWebPath() { 229 | return fileWebPath; 230 | } 231 | 232 | public void setFileWebPath(String fileWebPath) { 233 | this.fileWebPath = fileWebPath; 234 | } 235 | 236 | public List getFieldNames() { 237 | return fieldNames; 238 | } 239 | 240 | public void setFieldNames(List fieldNames) { 241 | this.fieldNames = fieldNames; 242 | } 243 | 244 | public List getFieldCodes() { 245 | return fieldCodes; 246 | } 247 | 248 | public void setFieldCodes(List fieldCodes) { 249 | this.fieldCodes = fieldCodes; 250 | } 251 | 252 | public int getRownum() { 253 | return rownum; 254 | } 255 | 256 | public String getFilePrefix() { 257 | return filePrefix; 258 | } 259 | 260 | public void setFilePrefix(String filePrefix) { 261 | this.filePrefix = filePrefix; 262 | } 263 | 264 | public int getColnum() { 265 | return colnum; 266 | } 267 | 268 | public String getFileAllPath() { 269 | return fileAllPath; 270 | } 271 | 272 | public void setFileAllPath(String fileAllPath) { 273 | this.fileAllPath = fileAllPath; 274 | } 275 | 276 | public static void main(String[] args) throws Exception { 277 | /** 导出文件存放物理路径 278 | * @param fileWebPath 279 | * 导出文件web下载路径 280 | * @param filePrefix 281 | * 导出文件名的前缀 282 | * @param flushRows 283 | * 存放在内存的数据量 284 | * @param fieldNames 285 | * 导出文件列标题 286 | * @param fieldCodes 287 | * 导出数据对象的字段名称 288 | * @param flushRows*/ 289 | //导出文件存放的路径,并且是虚拟目录指向的路径 290 | String filePath = "d:/upload/linshi/"; 291 | //导出文件的前缀 292 | String filePrefix="ypxx"; 293 | //-1表示关闭自动刷新,手动控制写磁盘的时机,其它数据表示多少数据在内存保存,超过的则写入磁盘 294 | int flushRows=100; 295 | 296 | //指导导出数据的title 297 | List fieldNames=new ArrayList(); 298 | fieldNames.add("流水号"); 299 | fieldNames.add("通用名"); 300 | fieldNames.add("价格"); 301 | 302 | //告诉导出类数据list中对象的属性,让ExcelExportSXXSSF通过反射获取对象的值 303 | List fieldCodes=new ArrayList(); 304 | fieldCodes.add("bm");//药品流水号 305 | fieldCodes.add("mc");//通用名 306 | fieldCodes.add("price");//价格 307 | 308 | 309 | 310 | //注意:fieldCodes和fieldNames个数必须相同且属性和title顺序一一对应,这样title和内容才一一对应 311 | 312 | 313 | //开始导出,执行一些workbook及sheet等对象的初始创建 314 | ExcelExportSXXSSF excelExportSXXSSF = ExcelExportSXXSSF.start(filePath, "/upload/", filePrefix, fieldNames, fieldCodes, flushRows); 315 | 316 | //准备导出的数据,将数据存入list,且list中对象的字段名称必须是刚才传入ExcelExportSXXSSF的名称 317 | List list = new ArrayList(); 318 | 319 | Ypxx ypxx1 = new Ypxx("001", "青霉素", 5); 320 | Ypxx ypxx2 = new Ypxx("002", "感冒胶囊", 2.5f); 321 | list.add(ypxx1); 322 | list.add(ypxx2); 323 | 324 | //执行导出 325 | excelExportSXXSSF.writeDatasByObject(list); 326 | //输出文件,返回下载文件的http地址 327 | String webpath = excelExportSXXSSF.exportFile(); 328 | 329 | System.out.println(webpath); 330 | 331 | 332 | } 333 | 334 | } 335 | -------------------------------------------------------------------------------- /数据结构/线性表.md: -------------------------------------------------------------------------------- 1 | # 线性表的类型定义 2 | 3 | ## 定义: 4 | 5 | ​ 线性表是n个数据元素的有序序列 6 | 7 | ## 特点: 8 | 9 | 1. 存在唯一的一个被称为"第一个"的数据元素 10 | 2. 存在唯一的一个被称为"最后一个"的数据元素 11 | 3. 除第一个之外,集合中的每个数据元素均只有一个前驱 12 | 4. 除最后一个之外,集合中的每个数据元素均只有一个后继 13 | 14 | # 线性表的顺序表示和实现 15 | 16 | ## 定义: 17 | 18 | ​ 线性表的顺序表示指的是用一组地址连续的存储单元依次存储线性表的数据元素,逻辑关系上相邻的两个元素,物理地址上也相邻。 19 | 20 | ## 存储位置: 21 | 22 | ​ 一般来说,线性表的第$i$个数据元素$${a}_i$$的存储位置为 23 | $$ 24 | LOC({a}_i)=LOC({a}_1)+(i-1)*l 25 | $$ 26 | ​ 公式中$LOC({a}_1)$是线性表的第一个数据元素$a_i$的存储位置,通常被称作线性表的起始位置和基地址。 27 | 28 | ​ 线性表的这种机内表示称做线性表的顺序结构或顺序映像,通常,称这种存储结构的线性表为顺序表。它的特点是,为表中相邻的元素$$a_i$$和$${a}_i+_1$$赋以相邻的存储位置$$LOC({a}_i)$$和$$LOC(a{_i+_1})$$ 。 29 | 30 | ```c 31 | //------线性表的动态分配顺序存储结构------------ 32 | #define LIST_INIT_SIZE 100 //线性表存储空间的初始化分配量 33 | #define LISTINCREMENT 10 //线性表存储空间的分配增量 34 | typedef struct { 35 | ElemType *elem; //存储空间基址 36 | int length; //当前长度 37 | int listsize; //当前分配的存储容量(以sizeof(ElemType)为单位) 38 | }Sqlist; 39 | ``` 40 | 41 | ​ 在上述定义中,数据指针elem指示线性表的基地址,length指示线性表的当前长度。顺序表的初始化操作就是为顺序表分配一个预定义大小的数组空间,并将线性表的当前长度设为"0"。listsize指示顺序表当前分配的存储空间大小。一旦因插入元素而空间不足时,可进行再分配,即为顺序表增加一个大小为存储LISTINCREMENT的数据元素的空间。 42 | 43 | ```c 44 | Status InitList_Sq(SqList &L) { 45 | //构造一个空的线性表。 46 | L.elem = (ElemType *)malloc(LIST_INIT_SIZE *sizeof(ElemType)); 47 | if(!L.elem)exit(OVERFLOW);//存储分配失败 48 | L.length = 0; //空表长度为0 49 | L.listsize = LIST_INIT_SIZE; //初始存储容量 50 | return OK; 51 | } 52 | ``` 53 | 54 | ​ 线性表的插入操作是指的是在线性表的第$i-1$个数据元素和第$i$个数据元素之间插入一个新的数据元素,就是要长度为$n$的线性表 55 | $$ 56 | (a_1,...,a_{i-1},a_i,...,a_n) 57 | $$ 58 | 变成长度为$n+1$的线性表 59 | $$ 60 | (a_1,...,a_{i-1},b,a_i,...,a_n) 61 | $$ 62 | 数据元素$a_{i-1}$和$a_i$之间的逻辑关系发生了变化, 63 | 64 | ​ 一般情况下,在第$i$(1<=$i$<=$n$)个元素之前插入一个元素时,需将第$n$至第$i$共($n-i+1$)个元素向后移动一个位置。 65 | 66 | ```c 67 | Status ListInsert_Sq(SqList &L, int i, ElemType e) { 68 | //在顺序线性表L中第i个位置之前插入新的元素e 69 | //i的合法值为1<=i<=ListLength_Sq(L)+1 70 | if(i < 1 || i > L.length + 1) return ERROR;//i值不合法 71 | if(L.length >= L.listsize) { //当前存储空间已满,增加分配 72 | newbase = (ElemType *)realloc(L.elem, (L.listsize + LISTINCREMENT) * sizeof(ElemType)); 73 | if(!newbase)exit(OVERFLOW);//存储分配失败 74 | L.elem = newbase; 75 | L.listsieze += LISTINCREMENT; 76 | } 77 | q = &(L.elem[i-1]); 78 | for(p = &(L.elem[L.length - 1]); p >= q; --p) 79 | *(p+1) = *p;// 插入位置及之后的元素右移 80 | *q = e; //插入e 81 | ++L.length;//表长增1 82 | return OK; 83 | } 84 | ``` 85 | 86 | ​ 线性表的删除操作是使长度为$n$的线性表 87 | $$ 88 | (a_1,...,a_{i-1},a_i,a_{i+1},...,a_n) 89 | $$ 90 | 变成长度为$n-1$的线性表 91 | $$ 92 | (a_1,...,a_{i-1},a_{i+1},...,a_n) 93 | $$ 94 | 数据元素$a_{i-1}$,$a_i$,$a_{i+1}$之间的逻辑关系发生了变化,为了在存储结构上反映这个变化,同样需要移动元素。 95 | 96 | ​ 一般情况下,删除第$i$($1<= i <= n$)个元素时需将从第$i+1$至第$n$(共$n-i$)个元素依次向前移动一个位置。 97 | 98 | ```c 99 | Status ListDelete_Sq(SqList &L, int i, ElemType &e){ 100 | //在顺序线性表L中删除第i个元素,并用e返回其值 101 | //i的合法值为1<=i<=ListLength_Sq(L) 102 | if((i < 1)||(i > L.length)) return ERROR; //i不合法 103 | p = &(L.elem[i -1]);//p为被删除元素的位置 104 | e = *p; //被删除元素的值赋给e 105 | q = L.elem + L.length - 1; //表尾元素的位置 106 | for(++ p; p <= q; ++p) 107 | *(p - 1) = *p; //被删除元素之后的元素后移 108 | --L.length; //表长减1 109 | return OK; 110 | } 111 | ``` 112 | 113 | ​ 从以上两个算法中可见,当在顺序存储结构的线性表中某个位置上插入或删除一个数据元素时,其时间主要消耗在移动元素上,而移动元素的个数取决于插入或删除元素的位置。 114 | 115 | ​ 假设$p_i$是在$i$个元素之前插入一个元素的概率,则在长度为$n$的线性表中插入一个元素时所需要移动元素次数的期望值(平均次数)为 116 | $$ 117 | E_{is}=\sum_{i=1}^{n+1}{p_i}(n-i+1) 118 | $$ 119 | ​ 假设$q_i$是删除第$i$个元素的概率,则在长度为$n$的线性表中删除一个元素时所需移动元素次数的期望值(平均次数)为 120 | $$ 121 | E_{dl}=\sum_{i=1}^n{q_i}(n-i) 122 | $$ 123 | ​ 不失一般性,我们可以假设在线性表的任何位置上插入或者删除元素都是等概率的,即 124 | $$ 125 | p_i=\frac 1 {n+1},q_i=\frac 1 n 126 | $$ 127 | ​ 则两个公式可以简化为 128 | $$ 129 | E_{is}=\frac 1 {n+1} \sum_{i=1}^{n+1}(n-i+1)=\frac n 2 130 | $$ 131 | 132 | $$ 133 | E_{dl}=\frac 1 n \sum_{i=1}^n (n-i)=\frac {n-1} 2 134 | $$ 135 | 136 | ​ 由此可见,在顺序存储结构的线性表中插入或者删除一个数据元素,平均约移动表中的一半元素。若表长为$n$,则算法ListInsert_Sq和ListDelete_Sq的时间复杂度为$O(n)$。 137 | 138 | # 线性表的链式表示和实现 139 | 140 | ​ 线性表的顺序存储结构的特点是逻辑关系上相邻的两个元素在物理地址上也相邻,因此可以随机存取表中任一元素,它的存储位置可用一个简单、直观的公式来表示。然而,从另一方面来讲,这个特点也铸成了这种存储结构的弱点:在插入或者删除的时候,需要移动大量的数据元素。线性表的另一种存储结构:链式存储结构。由于它不要求在逻辑上相邻的元素的物理位置上也相邻,因此它没有顺序结构所具有的弱点,但是同时也失去了顺序表可随机存取的优点。 141 | 142 | ## 线性链表 143 | 144 | ​ 线性表的链式存储结构的特点是用一组任意的存储单元存储线性表的数据元素(这组存储单元可以是连续的,也可以是不连续的)。因此,为了表示每个数据元素$a_i$与其直接后继数据元素$a_{i+1}$之间的逻辑关系,对数据元素$a_i$来说,除了本身存储的数据信息外,还需要存储一个指示其直接后继的的信息(即直接后继的存储地址)。这两部分信息组成数据元素$a_i$的存储映像,称为结点(node)。它包括两个域:其中存储数据元素信息的域被称为数据域;存储直接后继存储地址的域称为指针域。指针域中存储的信息称作指针或者链。$n$个结点$(a_i(1<=i<=n))$链接成链表,即为线性表 145 | $$ 146 | (a_1,a_2,...a_n) 147 | $$ 148 | 的链式存储结构。又由于此链表的每个结点中只包含一个指针域,故又称线性链表或单链表。 149 | 150 | ​ 线性表的线性链表存储结构中,整个链表的存取必须从头指针开始进行,头指针指示链表中的第一个结点(即第一个数据元素的存储映像)的存储位置。同时,由于最后一个数据元素没有直接后继,则线性链表中最后一个结点的指针为空(null)。 151 | 152 | ​ 用线性链表表示线性表时,数据元素之间的逻辑关系是由结点中的指针指示的。话句话说,指针为数据元素之间的逻辑关系的映像,则逻辑上相邻的两个数据元素其存储的物理位置不要求相邻,由此,这种存储结构为非顺序映像或链式映像。 153 | 154 | ```c 155 | //----------线性表的单链表存储结构------------ 156 | typedef struct LNode{ 157 | ElemType data; 158 | struct LNode * next; 159 | }LNode, * LinkList; 160 | ``` 161 | 162 | ​ 假设L是LinkList型的变量,则L为单链表的头指针,它指向表中第一个结点。若L为空(L=NULL),则所表示的线性表为空表,其长度$n$为0。有时,我们在单链表的第一个结点之前附设一个结点,称之为头结点。头结点的数据域可以不存储任何数据信息,也可以存储如线性表的长度之类的附加信息,头结点的指针域存储指向第一个结点的指针(即第一个元素结点的存储位置)。 163 | 164 | ​ 在线性表的顺序存储结构中,由于逻辑上相邻的两个元素在物理位置上紧邻,则每个元素的存储位置都可以从线性表的起始位置计算得到。而在单链表中,任何两个元素的存储位置之间没有固定的联系。然而,每个元素的存储位置都包含在其直接前驱结点的信息之中。假设$p$是指向线性表中第$i$个数据元素(结点$a_i$)的指针,则p->next是指向第$i+1$个数据元素(结点$a_{i+1}$)的指针。如果$p->data=a_i$,则$p->next->data=a_{i+1}$。所以,在单链表中,取得第$i$数据元素必须从头指针出发寻找,因此,单链表是非随机存储的存储结构。 165 | 166 | ```c 167 | Status GetElem_L(LinkList L, int i, ElemType &e) { 168 | //L为带头结点的单链表的头指针 169 | //当第i个元素存在时,其值赋值给e并返回OK,否则返回ERROR 170 | p = L->next; j = 1;//初始化,p指向第一个结点,j为计数器 171 | while(p && j < i) { //顺指针向后查找,直到p指向第i个元素或p为空 172 | p = p -> next; 173 | ++j; 174 | } 175 | if(!p || j > i) { 176 | return ERROR;//第i个元素不存在 177 | } 178 | e = p -> data; 179 | return OK; 180 | } 181 | ``` 182 | 183 | ​ 该算法中的基本操作是比较$j$和$i$并后移指针$p$,while循环体重的语句频度与被查元素在表中的位置有关,若$1<=i<=n$,则频度为$i-1$,否则频度为$n$,因此该算法的时间复杂度为$O(n)$ 184 | 185 | ​ 在单链表中的插入一个数据元素$x$,首先要生成一个数据域为$x$的结点,然后插入在单链表中。根据插入操作的逻辑定义,还需要修改结点$a$中的指针域,令其指向结点$x$,而结点$x$中的指针域应指向结点$b$,从而实现3个元素$a,b和x$之间逻辑关系的变化。即为以下语句: 186 | $$ 187 | s->next=p->next;p->=s; 188 | $$ 189 | ​ 在单链表中的删除一个数据元素$b$时,为在单链表中实现元素$a,b和c$之间逻辑关系的变化,仅需要修改结点$a$中的指针域即可。即为以下语句: 190 | $$ 191 | p->next=p->next->next; 192 | $$ 193 | 194 | ```c 195 | Status ListInsert_L(LinkList &L, int i, ElemType e) { 196 | //在带头结点的单链线性表L中第i个位置之前插入元素e 197 | p = L; j = 0; 198 | while(p && j < i - 1) { //寻找第i-1个结点 199 | p = p -> next; 200 | ++ j; 201 | } 202 | if(!p || j > i - 1) return ERROR; 203 | s = (LinkList) malloc (sizeof(LNode)); 204 | s -> data = e; 205 | s -> next = p -> next; 206 | p -> next = s; 207 | return OK; 208 | } 209 | ``` 210 | 211 | ```c 212 | Status ListDelete_L(LinkList &L, int i, ElemType &e) { 213 | //在带头结点的单链线性表L中,删除第i个元素,并由e返回其值 214 | p = L; j = 0; 215 | while(p ->next && j < i-1) {//寻找第i个结点,并令p指向其前驱 216 | p = p -> next; 217 | ++ j; 218 | } 219 | if(!(p -> next)|| j > i-1) return ERROR; 220 | q = p -> next; 221 | p -> next = q -> next; 222 | e = q -> data; 223 | free(q); 224 | return OK; 225 | } 226 | ``` 227 | 228 | ​ 由以上两个算法中,我们可以得知,其时间复杂度为$O(n)$,在第$i$个结点之前插入一个新的结点或者删除第$i$个结点,都必须首先找到第$i-1$个结点,也就是需要修改指针的结点。 229 | 230 | ​ 单链表和顺序存储结构不同,它是一种动态结构。整个可用存储空间可为多个链表共同享用,每个链表占用的空间不需要预先分配划定,而是可以由系统应需求即时生成。因此,建立线性表的链式存储结构的过程就是一个动态生成链表的过程。其时间复杂度为$O(n)$,算法如下: 231 | 232 | ```c 233 | void CreateList_L(LinkList &L, int n) { 234 | //逆位序输入n个元素的值,建立带表头结点的单链表L 235 | L = (LinkList) malloc (sizeof(LNode)); 236 | L -> next = null; //先建立一个带头结点的单链表 237 | for(i = n; i > 0; --i) { 238 | p = (LinkList) malloc(sizeof(LNode));//生成新的结点 239 | scanf(&p -> data); //输入元素值 240 | p -> next = L -> next; 241 | L -> next = p; 242 | } 243 | } 244 | ``` 245 | 246 | ## 循环链表 247 | 248 | ​ 循环链表是另一种形式的链式存储结构。它的特点是表中最后一个结点的指针域指向头结点,整个链表形成一个环。循环链表的操作和线性链表基本一致,差别仅在于算法中的循环条件不是$p$或者$p->next$是否为空,而是它们是否等于头指针。 249 | 250 | ## 双向链表 251 | 252 | ​ 在双向链表的结点中有两个指针域,其一指向直接后继,另一指向直接前驱,其存储结构如下: 253 | 254 | ```c 255 | //----------------------线性表的双向链表的存储结构------------- 256 | typedef struct DuLNode { 257 | ElemType data; 258 | struct DuLNode * prior; 259 | struct DuLNode * next; 260 | } DuLNode, * DuLinkList; 261 | ``` 262 | 263 | ​ 在双向链表中插入、删除时,需要同时修改两个方向上的指针。其时间复杂都为$O(n)$ 264 | 265 | ```c 266 | Status ListInsert_DuL(DuLinkList &L, int i, ElemType e) { 267 | //在带头结点的双链循环线性表L中第i个位置之前插入元素e 268 | //i的不合法值为1<=i<=表长+1 269 | if(!(p = GetElemP_DuL(L, i))) //在L中确定插入位置 270 | return ERROR; //p=NULL 即插入不合法 271 | if(!(s = (DuLinkList)malloc(sizeof(DuLNode)))) return ERROR; 272 | s -> data = e; 273 | s -> prior = p -> prior; 274 | p -> prior->next = s; 275 | s -> next = p; 276 | p -> prior = s; 277 | return OK; 278 | } 279 | ``` 280 | 281 | ```c 282 | Status ListDelete_DuL(DuLinkList &L, int i, ElemType &e) { 283 | //删除带头结点的双链循环线性表L的第i个元素,i的合法值为1<=i<=表长 284 | if(!(p = GetElemP_DuL(L, i))) //在L中确定第i个元素的位置指针p 285 | return ERROR; 286 | e = p -> data; 287 | p -> prior -> next = p -> next; 288 | p -> next -> prior = p -> prior; 289 | free(p); 290 | return OK; 291 | } 292 | ``` 293 | 294 | # 参考博客及文档 295 | 296 | [1]:[数据结构与算法之线性表](http://www.cnblogs.com/wsnb/p/5191518.html) 297 | 298 | [2]:[线性表—维基百科](https://zh.wikipedia.org/zh-cn/%E7%BA%BF%E6%80%A7%E8%A1%A8) 299 | 300 | [3]:[线性表—百度百科](https://baike.baidu.com/item/%E7%BA%BF%E6%80%A7%E8%A1%A8/3228081?fr=aladdin) -------------------------------------------------------------------------------- /POI/HxlsAbstract.java: -------------------------------------------------------------------------------- 1 | import java.io.FileInputStream; 2 | import java.io.FileNotFoundException; 3 | import java.io.IOException; 4 | import java.io.PrintStream; 5 | import java.sql.SQLException; 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | import org.apache.poi.hssf.eventusermodel.EventWorkbookBuilder.SheetRecordCollectingListener; 10 | import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener; 11 | import org.apache.poi.hssf.eventusermodel.HSSFEventFactory; 12 | import org.apache.poi.hssf.eventusermodel.HSSFListener; 13 | import org.apache.poi.hssf.eventusermodel.HSSFRequest; 14 | import org.apache.poi.hssf.eventusermodel.MissingRecordAwareHSSFListener; 15 | import org.apache.poi.hssf.eventusermodel.dummyrecord.LastCellOfRowDummyRecord; 16 | import org.apache.poi.hssf.eventusermodel.dummyrecord.MissingCellDummyRecord; 17 | import org.apache.poi.hssf.model.HSSFFormulaParser; 18 | import org.apache.poi.hssf.record.BOFRecord; 19 | import org.apache.poi.hssf.record.BlankRecord; 20 | import org.apache.poi.hssf.record.BoolErrRecord; 21 | import org.apache.poi.hssf.record.BoundSheetRecord; 22 | import org.apache.poi.hssf.record.FormulaRecord; 23 | import org.apache.poi.hssf.record.LabelRecord; 24 | import org.apache.poi.hssf.record.LabelSSTRecord; 25 | import org.apache.poi.hssf.record.NoteRecord; 26 | import org.apache.poi.hssf.record.NumberRecord; 27 | import org.apache.poi.hssf.record.RKRecord; 28 | import org.apache.poi.hssf.record.Record; 29 | import org.apache.poi.hssf.record.SSTRecord; 30 | import org.apache.poi.hssf.record.StringRecord; 31 | import org.apache.poi.hssf.usermodel.HSSFWorkbook; 32 | import org.apache.poi.poifs.filesystem.POIFSFileSystem; 33 | 34 | public abstract class HxlsAbstract implements HSSFListener { 35 | private int minColumns; 36 | private POIFSFileSystem fs; 37 | private PrintStream output; 38 | 39 | private int lastRowNumber; 40 | private int lastColumnNumber; 41 | 42 | /** Should we output the formula, or the value it has? */ 43 | private boolean outputFormulaValues = true; 44 | 45 | /** For parsing Formulas */ 46 | private SheetRecordCollectingListener workbookBuildingListener; 47 | private HSSFWorkbook stubWorkbook; 48 | 49 | // Records we pick up as we process 50 | private SSTRecord sstRecord; 51 | private FormatTrackingHSSFListener formatListener; 52 | 53 | /** So we known which sheet we're on */ 54 | private int sheetIndex = -1; 55 | private BoundSheetRecord[] orderedBSRs; 56 | @SuppressWarnings("unchecked") 57 | private ArrayList boundSheetRecords = new ArrayList(); 58 | 59 | // For handling formulas with string results 60 | private int nextRow; 61 | private int nextColumn; 62 | private boolean outputNextStringRecord; 63 | 64 | private int curRow; 65 | private List rowlist; 66 | @SuppressWarnings( "unused") 67 | private String sheetName; 68 | 69 | public HxlsAbstract(POIFSFileSystem fs) 70 | throws SQLException { 71 | this.fs = fs; 72 | this.output = System.out; 73 | this.minColumns = -1; 74 | this.curRow = 0; 75 | this.rowlist = new ArrayList(); 76 | } 77 | 78 | public HxlsAbstract(String filename) throws IOException, 79 | FileNotFoundException, SQLException { 80 | this(new POIFSFileSystem(new FileInputStream(filename))); 81 | } 82 | 83 | //excel记录行操作方法,以行索引和行元素列表为参数,对一行元素进行操作,元素为String类型 84 | // public abstract void optRows(int curRow, List rowlist) throws SQLException ; 85 | 86 | //excel记录行操作方法,以sheet索引,行索引和行元素列表为参数,对sheet的一行元素进行操作,元素为String类型,rowlist存储了行数据 87 | public abstract void optRows(int sheetIndex,int curRow, List rowlist) throws Exception; 88 | 89 | /** 90 | * 遍历 excel 文件 91 | */ 92 | public void process() throws IOException { 93 | MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener( 94 | this); 95 | formatListener = new FormatTrackingHSSFListener(listener); 96 | 97 | HSSFEventFactory factory = new HSSFEventFactory(); 98 | HSSFRequest request = new HSSFRequest(); 99 | 100 | if (outputFormulaValues) { 101 | request.addListenerForAllRecords(formatListener); 102 | } else { 103 | workbookBuildingListener = new SheetRecordCollectingListener( 104 | formatListener); 105 | request.addListenerForAllRecords(workbookBuildingListener); 106 | } 107 | 108 | factory.processWorkbookEvents(request, fs); 109 | } 110 | 111 | /** 112 | * HSSFListener 监听方法,处理 Record 113 | */ 114 | @SuppressWarnings("unchecked") 115 | public void processRecord(Record record) { 116 | int thisRow = -1; 117 | int thisColumn = -1; 118 | String thisStr = null; 119 | String value = null; 120 | 121 | switch (record.getSid()) { 122 | case BoundSheetRecord.sid: 123 | boundSheetRecords.add(record); 124 | break; 125 | case BOFRecord.sid: 126 | BOFRecord br = (BOFRecord) record; 127 | if (br.getType() == BOFRecord.TYPE_WORKSHEET) { 128 | // Create sub workbook if required 129 | if (workbookBuildingListener != null && stubWorkbook == null) { 130 | stubWorkbook = workbookBuildingListener 131 | .getStubHSSFWorkbook(); 132 | } 133 | 134 | // Works by ordering the BSRs by the location of 135 | // their BOFRecords, and then knowing that we 136 | // process BOFRecords in byte offset order 137 | sheetIndex++; 138 | if (orderedBSRs == null) { 139 | orderedBSRs = BoundSheetRecord 140 | .orderByBofPosition(boundSheetRecords); 141 | } 142 | sheetName = orderedBSRs[sheetIndex].getSheetname(); 143 | } 144 | break; 145 | 146 | case SSTRecord.sid: 147 | sstRecord = (SSTRecord) record; 148 | break; 149 | 150 | case BlankRecord.sid: 151 | BlankRecord brec = (BlankRecord) record; 152 | 153 | thisRow = brec.getRow(); 154 | thisColumn = brec.getColumn(); 155 | thisStr = ""; 156 | break; 157 | case BoolErrRecord.sid: 158 | BoolErrRecord berec = (BoolErrRecord) record; 159 | 160 | thisRow = berec.getRow(); 161 | thisColumn = berec.getColumn(); 162 | thisStr = ""; 163 | break; 164 | 165 | case FormulaRecord.sid: 166 | FormulaRecord frec = (FormulaRecord) record; 167 | 168 | thisRow = frec.getRow(); 169 | thisColumn = frec.getColumn(); 170 | 171 | if (outputFormulaValues) { 172 | if (Double.isNaN(frec.getValue())) { 173 | // Formula result is a string 174 | // This is stored in the next record 175 | outputNextStringRecord = true; 176 | nextRow = frec.getRow(); 177 | nextColumn = frec.getColumn(); 178 | } else { 179 | thisStr = formatListener.formatNumberDateCell(frec); 180 | } 181 | } else { 182 | thisStr = '"' + HSSFFormulaParser.toFormulaString(stubWorkbook, 183 | frec.getParsedExpression()) + '"'; 184 | } 185 | break; 186 | case StringRecord.sid: 187 | if (outputNextStringRecord) { 188 | // String for formula 189 | StringRecord srec = (StringRecord) record; 190 | thisStr = srec.getString(); 191 | thisRow = nextRow; 192 | thisColumn = nextColumn; 193 | outputNextStringRecord = false; 194 | } 195 | break; 196 | 197 | case LabelRecord.sid: 198 | LabelRecord lrec = (LabelRecord) record; 199 | 200 | curRow = thisRow = lrec.getRow(); 201 | thisColumn = lrec.getColumn(); 202 | value = lrec.getValue().trim(); 203 | value = value.equals("")?" ":value; 204 | this.rowlist.add(thisColumn, value); 205 | break; 206 | case LabelSSTRecord.sid: 207 | LabelSSTRecord lsrec = (LabelSSTRecord) record; 208 | 209 | curRow = thisRow = lsrec.getRow(); 210 | thisColumn = lsrec.getColumn(); 211 | if (sstRecord == null) { 212 | rowlist.add(thisColumn, " "); 213 | } else { 214 | value = sstRecord 215 | .getString(lsrec.getSSTIndex()).toString().trim(); 216 | value = value.equals("")?" ":value; 217 | rowlist.add(thisColumn,value); 218 | } 219 | break; 220 | case NoteRecord.sid: 221 | NoteRecord nrec = (NoteRecord) record; 222 | 223 | thisRow = nrec.getRow(); 224 | thisColumn = nrec.getColumn(); 225 | // TODO: Find object to match nrec.getShapeId() 226 | thisStr = '"' + "(TODO)" + '"'; 227 | break; 228 | case NumberRecord.sid: 229 | NumberRecord numrec = (NumberRecord) record; 230 | 231 | curRow = thisRow = numrec.getRow(); 232 | thisColumn = numrec.getColumn(); 233 | value = formatListener.formatNumberDateCell(numrec).trim(); 234 | value = value.equals("")?" ":value; 235 | // Format 236 | rowlist.add(thisColumn, value); 237 | break; 238 | case RKRecord.sid: 239 | RKRecord rkrec = (RKRecord) record; 240 | 241 | thisRow = rkrec.getRow(); 242 | thisColumn = rkrec.getColumn(); 243 | thisStr = '"' + "(TODO)" + '"'; 244 | break; 245 | default: 246 | break; 247 | } 248 | 249 | // 遇到新行的操作 250 | if (thisRow != -1 && thisRow != lastRowNumber) { 251 | lastColumnNumber = -1; 252 | } 253 | 254 | // 空值的操作 255 | if (record instanceof MissingCellDummyRecord) { 256 | MissingCellDummyRecord mc = (MissingCellDummyRecord) record; 257 | curRow = thisRow = mc.getRow(); 258 | thisColumn = mc.getColumn(); 259 | rowlist.add(thisColumn," "); 260 | } 261 | 262 | // 如果遇到能打印的东西,在这里打印 263 | if (thisStr != null) { 264 | if (thisColumn > 0) { 265 | output.print(','); 266 | } 267 | output.print(thisStr); 268 | } 269 | 270 | // 更新行和列的值 271 | if (thisRow > -1) 272 | lastRowNumber = thisRow; 273 | if (thisColumn > -1) 274 | lastColumnNumber = thisColumn; 275 | 276 | // 行结束时的操作 277 | if (record instanceof LastCellOfRowDummyRecord) { 278 | if (minColumns > 0) { 279 | // 列值重新置空 280 | if (lastColumnNumber == -1) { 281 | lastColumnNumber = 0; 282 | } 283 | } 284 | // 行结束时, 调用 optRows() 方法 285 | lastColumnNumber = -1; 286 | try { 287 | optRows(sheetIndex,curRow, rowlist); 288 | } catch (Exception e) { 289 | e.printStackTrace(); 290 | } 291 | rowlist.clear(); 292 | } 293 | } 294 | } 295 | -------------------------------------------------------------------------------- /项目笔记/hibernate中的表与表的关系模板.md: -------------------------------------------------------------------------------- 1 | # Hibernate中表与表的关系模板代码 2 | 3 | ## 一对多的关系 4 | 5 | ```xml 6 | 7 | 8 | 9 | 10 | 11 | ``` 12 | 13 | ![一对多](http://upload-images.jianshu.io/upload_images/1540531-8c243b1e4f3d31e2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 14 | 15 | ## 多对一关系 16 | 17 | ```xml 18 | 19 | 20 | 21 | 22 | ``` 23 | 24 | ![多对一](http://upload-images.jianshu.io/upload_images/1540531-581cdc614f1cef10.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 25 | 26 | ## 多对多关系 27 | 28 | ```xml 29 | 30 | 31 | 32 | 33 | 34 | ``` 35 | 36 | ```xml 37 | 38 | 39 | 40 | 41 | 42 | ``` 43 | 44 | 需要第三表来维护 45 | 46 | ## 模板实例 47 | 48 | ### 实体类 49 | 50 | #### Department.java 51 | 52 | ```java 53 | package cn.zzuli.oa.domain; 54 | 55 | import java.util.HashSet; 56 | import java.util.Set; 57 | 58 | /** 59 | * 部门 60 | * @author LZH 61 | * @date 2017年2月23日 62 | */ 63 | public class Department { 64 | private Long id; 65 | private Set users = new HashSet(); 66 | private Department parent; 67 | private Set children = new HashSet(); 68 | 69 | private String name; 70 | private String description; 71 | 72 | public Long getId() { 73 | return id; 74 | } 75 | 76 | public void setId(Long id) { 77 | this.id = id; 78 | } 79 | 80 | public Set getUsers() { 81 | return users; 82 | } 83 | 84 | public void setUsers(Set users) { 85 | this.users = users; 86 | } 87 | 88 | public Department getParent() { 89 | return parent; 90 | } 91 | 92 | public void setParent(Department parent) { 93 | this.parent = parent; 94 | } 95 | 96 | public Set getChildren() { 97 | return children; 98 | } 99 | 100 | public void setChildren(Set children) { 101 | this.children = children; 102 | } 103 | 104 | public String getName() { 105 | return name; 106 | } 107 | 108 | public void setName(String name) { 109 | this.name = name; 110 | } 111 | 112 | public String getDescription() { 113 | return description; 114 | } 115 | 116 | public void setDescription(String description) { 117 | this.description = description; 118 | } 119 | 120 | } 121 | ``` 122 | 123 | #### Role.java 124 | 125 | ```java 126 | package cn.zzuli.oa.domain; 127 | 128 | import java.util.HashSet; 129 | import java.util.Set; 130 | 131 | /** 132 | * 岗位 133 | * @author LZH 134 | * @date 2017年2月23日 135 | */ 136 | public class Role { 137 | private Long id; 138 | private String name; 139 | private String description; 140 | private Set users = new HashSet(); 141 | 142 | public Long getId() { 143 | return id; 144 | } 145 | 146 | public void setId(Long id) { 147 | this.id = id; 148 | } 149 | 150 | public String getName() { 151 | return name; 152 | } 153 | 154 | public void setName(String name) { 155 | this.name = name; 156 | } 157 | 158 | public String getDescription() { 159 | return description; 160 | } 161 | 162 | public void setDescription(String description) { 163 | this.description = description; 164 | } 165 | 166 | public Set getUsers() { 167 | return users; 168 | } 169 | 170 | public void setUsers(Set users) { 171 | this.users = users; 172 | } 173 | 174 | } 175 | ``` 176 | 177 | #### User.java 178 | 179 | ```java 180 | package cn.zzuli.oa.domain; 181 | 182 | import java.util.HashSet; 183 | import java.util.Set; 184 | 185 | /** 186 | * 用户 187 | * @author LZH 188 | * @date 2017年2月23日 189 | */ 190 | public class User { 191 | private Long id; 192 | private Department department; 193 | private Set roles = new HashSet(); 194 | 195 | private String loginName; // 登录名 196 | private String password; // 密码 197 | private String name; // 真实姓名 198 | private String gender; // 性别 199 | private String phoneNumber; // 电话号码 200 | private String email; // 电子邮件 201 | private String description; // 说明 202 | 203 | public Long getId() { 204 | return id; 205 | } 206 | 207 | public void setId(Long id) { 208 | this.id = id; 209 | } 210 | 211 | public Department getDepartment() { 212 | return department; 213 | } 214 | 215 | public void setDepartment(Department department) { 216 | this.department = department; 217 | } 218 | 219 | public Set getRoles() { 220 | return roles; 221 | } 222 | 223 | public void setRoles(Set roles) { 224 | this.roles = roles; 225 | } 226 | 227 | public String getLoginName() { 228 | return loginName; 229 | } 230 | 231 | public void setLoginName(String loginName) { 232 | this.loginName = loginName; 233 | } 234 | 235 | public String getPassword() { 236 | return password; 237 | } 238 | 239 | public void setPassword(String password) { 240 | this.password = password; 241 | } 242 | 243 | public String getName() { 244 | return name; 245 | } 246 | 247 | public void setName(String name) { 248 | this.name = name; 249 | } 250 | 251 | public String getGender() { 252 | return gender; 253 | } 254 | 255 | public void setGender(String gender) { 256 | this.gender = gender; 257 | } 258 | 259 | public String getPhoneNumber() { 260 | return phoneNumber; 261 | } 262 | 263 | public void setPhoneNumber(String phoneNumber) { 264 | this.phoneNumber = phoneNumber; 265 | } 266 | 267 | public String getEmail() { 268 | return email; 269 | } 270 | 271 | public void setEmail(String email) { 272 | this.email = email; 273 | } 274 | 275 | public String getDescription() { 276 | return description; 277 | } 278 | 279 | public void setDescription(String description) { 280 | this.description = description; 281 | } 282 | 283 | } 284 | ``` 285 | 286 | ### 对应配置文件 287 | 288 | #### Department.hbm.xml 289 | 290 | ```xml 291 | 292 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | ``` 326 | 327 | #### Role.hbm.xml 328 | 329 | ```xml 330 | 331 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | ``` 354 | 355 | #### User.hbm.xml 356 | 357 | ```xml 358 | 359 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | ``` 390 | 391 | ### 数据表模型 392 | 393 | ![数据表模型](http://upload-images.jianshu.io/upload_images/1540531-dee9717ac8161626.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 394 | 395 | 396 | 397 | ## 总结: 398 | 399 | ![图片总结](http://upload-images.jianshu.io/upload_images/1540531-4b3708277b62a85a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 400 | 401 | ### 1、写注释 402 | 403 | ​ 格式为:?属性,表达的是本对象与?的?关系。 404 | 405 | ​ 例:“department属性,本对象与Department的多对一” 406 | 407 | ### 2、模版 408 | 409 | #### 多对一 410 | 411 | ```xml 412 | 413 | ``` 414 | 415 | #### 一对多 416 | 417 | ```xml 418 | 419 | 420 | 421 | 422 | ``` 423 | 424 | #### 多对多 425 | 426 | ```xml 427 | 428 | 429 | 430 | 431 | ``` 432 | 433 | ### 3、填空 434 | 435 | •name属性:属性名(注释中的第1问号) 436 | 437 | •class属性:关联的实体类型(注释中的第2个问号) 438 | 439 | •column属性: 440 | 441 | •\:一般可以写成属性名加Id后缀,如属性为department,则column值写成departmentId。 442 | 443 | •一对多中的\:从关联的对方(对方是多对一)映射中把column值拷贝过来。 444 | 445 | •多对多中的\:一般可以写成本对象的名加Id后缀,如本对象名为User,则写为userId。 446 | 447 | •多对多中的\:一般可以写为关联对象的名称加Id后缀。 -------------------------------------------------------------------------------- /项目笔记/JavaWeb项目层次设计.md: -------------------------------------------------------------------------------- 1 | # JavaWeb 各个层次简化设计 2 | 3 | ## UML类图 4 | 5 | ![UML类图](http://upload-images.jianshu.io/upload_images/1540531-aefd961f155d6b9a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 6 | 7 | ## Dao层 8 | 9 | ### BaseDao接口 10 | 11 | ```java 12 | package cn.zzuli.oa.base; 13 | 14 | import java.util.List; 15 | 16 | /** 17 | * Dao层的基类 18 | * @author LZH 19 | * @date 2017年2月25日 20 | * @param 泛型 获取实体类 21 | */ 22 | public interface BaseDao { 23 | 24 | /** 25 | * 保存实体 26 | * @param entity 27 | */ 28 | void save(T entity); 29 | 30 | /** 31 | * 删除实体 32 | * @param id 33 | */ 34 | void delete(Long id); 35 | 36 | /** 37 | * 更新实体 38 | * @param entity 39 | */ 40 | void update(T entity); 41 | 42 | /** 43 | * 44 | * @param id 45 | * @return 46 | */ 47 | T getById(Long id); 48 | 49 | /** 50 | * 查询实体 51 | * @param ids id的集合 52 | * @return 53 | */ 54 | List listByIds(Long[] ids); 55 | 56 | /** 57 | * 查询所有 58 | * @return 59 | */ 60 | List listAll(); 61 | 62 | } 63 | ``` 64 | 65 | ### BaseDao实现类BaseDaoImpl 66 | 67 | ```java 68 | package cn.zzuli.oa.base.impl; 69 | 70 | import java.lang.reflect.ParameterizedType; 71 | import java.util.Collections; 72 | import java.util.List; 73 | 74 | import javax.annotation.Resource; 75 | 76 | import org.hibernate.Session; 77 | import org.hibernate.SessionFactory; 78 | import org.springframework.transaction.annotation.Transactional; 79 | 80 | import cn.zzuli.oa.base.BaseDao; 81 | 82 | /** 83 | * dao层的实现类 84 | * 85 | * @author LZH 86 | * @date 2017年2月25日 87 | * @param 88 | * 泛型 用于获取实体类 89 | */ 90 | @Transactional // @Transactional可以被继承,即对子类也有效 91 | @SuppressWarnings("unchecked") 92 | public abstract class BaseDaoImpl implements BaseDao { 93 | 94 | @Resource 95 | private SessionFactory sessionFactory; 96 | 97 | protected Class clazz; 98 | 99 | public BaseDaoImpl() { 100 | // 通过反射得到T的真实类型 101 | ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass(); 102 | this.clazz = (Class) pt.getActualTypeArguments()[0]; // 获取T的类型 103 | } 104 | 105 | @Override 106 | public void save(T entity) { 107 | getSession().save(entity); 108 | } 109 | 110 | @Override 111 | public void delete(Long id) { 112 | Object obj = getSession().get(clazz, id); 113 | getSession().delete(obj); 114 | } 115 | 116 | @Override 117 | public void update(T entity) { 118 | getSession().update(entity); 119 | } 120 | 121 | @Override 122 | public T getById(Long id) { 123 | return (T) getSession().get(clazz, id); 124 | } 125 | 126 | @Override 127 | public List listByIds(Long[] ids) { 128 | if (ids == null || ids.length == 0) { 129 | return Collections.EMPTY_LIST; 130 | } 131 | return getSession().createQuery("FROM " + clazz.getSimpleName() + " WHERE id IN(:ids)") 132 | .setParameterList("ids", ids).list(); 133 | } 134 | 135 | @Override 136 | public List listAll() { 137 | return getSession().createQuery("FROM " + clazz.getSimpleName()).list(); 138 | } 139 | 140 | /** 141 | * 获取当前可用的Session 142 | * 143 | * @return 当前可用的Session 144 | */ 145 | protected Session getSession() { 146 | return sessionFactory.getCurrentSession(); 147 | } 148 | 149 | } 150 | ``` 151 | 152 | ## Service业务层设计 153 | 154 | 各个模块接口,在每个接口中,可以写每个模块所特有的方法,以供调用实现。这里面由于继承了BaseDaoImpl可是直接调用Session来执行操作数据,这样就可以写一些每个模块里面所独有的方法。 155 | 156 | ### RoleService 157 | 158 | ```java 159 | package cn.zzuli.oa.service; 160 | 161 | import cn.zzuli.oa.base.BaseDao; 162 | import cn.zzuli.oa.domain.Role; 163 | 164 | /** 165 | * 岗位业务层接口 166 | * 可以写自己模块所特有的方法 167 | * @author LZH 168 | * @date 2017年2月25日 169 | */ 170 | public interface RoleService extends BaseDao{ 171 | 172 | } 173 | ``` 174 | 175 | ### UserService 176 | 177 | ```java 178 | package cn.zzuli.oa.service; 179 | 180 | import cn.zzuli.oa.base.BaseDao; 181 | import cn.zzuli.oa.domain.User; 182 | 183 | public interface UserService extends BaseDao{ 184 | 185 | } 186 | ``` 187 | 188 | ### RoleService实现类RoleServiceImpl 189 | 190 | ```java 191 | package cn.zzuli.oa.service.impl; 192 | 193 | import org.springframework.stereotype.Service; 194 | 195 | import cn.zzuli.oa.base.impl.BaseDaoImpl; 196 | import cn.zzuli.oa.domain.Role; 197 | import cn.zzuli.oa.service.RoleService; 198 | 199 | /** 200 | * 岗位业务层实现类 201 | * 202 | * @author LZH 203 | * @date 2017年2月25日 204 | */ 205 | @Service 206 | public class RoleServiceImpl extends BaseDaoImpl implements RoleService { 207 | 208 | } 209 | ``` 210 | 211 | ### UserService实现类UserServiceImpl 212 | 213 | ```java 214 | package cn.zzuli.oa.service.impl; 215 | 216 | import org.springframework.stereotype.Service; 217 | 218 | import cn.zzuli.oa.base.impl.BaseDaoImpl; 219 | import cn.zzuli.oa.domain.User; 220 | import cn.zzuli.oa.service.UserService; 221 | 222 | /** 223 | * 用户业务层 224 | * 225 | * @author LZH 226 | * @date 2017年2月26日 227 | */ 228 | @Service 229 | public class UserServiceImpl extends BaseDaoImpl implements UserService { 230 | 231 | } 232 | ``` 233 | 234 | ## Action层设计 235 | 236 | ### BaseAction基类 237 | 238 | ```java 239 | package cn.zzuli.oa.base; 240 | 241 | import java.lang.reflect.ParameterizedType; 242 | 243 | import javax.annotation.Resource; 244 | 245 | import com.opensymphony.xwork2.ActionSupport; 246 | import com.opensymphony.xwork2.ModelDriven; 247 | 248 | import cn.zzuli.oa.service.DepartmentService; 249 | import cn.zzuli.oa.service.RoleService; 250 | import cn.zzuli.oa.service.UserService; 251 | 252 | public class BaseAction extends ActionSupport implements ModelDriven { 253 | 254 | private static final long serialVersionUID = 1L; 255 | 256 | //填写各个Service的实现类,方便在控制层中调用各个不同之间的使用 257 | @Resource 258 | protected RoleService roleService; 259 | @Resource 260 | protected DepartmentService departmentService; 261 | @Resource 262 | protected UserService userSercice; 263 | //..... 264 | 265 | protected T model; 266 | 267 | @SuppressWarnings({ "unchecked", "rawtypes" }) 268 | public BaseAction() { 269 | try { 270 | // 得到model的类型信息 271 | ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass(); 272 | Class clazz = (Class) pt.getActualTypeArguments()[0]; 273 | 274 | // 生成model的实例 通过反射实例 275 | model = (T) clazz.newInstance(); 276 | } catch (Exception e) { 277 | e.printStackTrace(); 278 | } 279 | } 280 | 281 | @Override 282 | public T getModel() { 283 | return model; 284 | } 285 | 286 | } 287 | ``` 288 | 289 | ### RoleAction 290 | 291 | ```java 292 | package cn.zzuli.oa.view.action; 293 | 294 | import java.util.List; 295 | 296 | import org.springframework.context.annotation.Scope; 297 | import org.springframework.stereotype.Controller; 298 | 299 | import com.opensymphony.xwork2.ActionContext; 300 | 301 | import cn.zzuli.oa.base.BaseAction; 302 | import cn.zzuli.oa.domain.Role; 303 | 304 | /** 305 | * 岗位控制层 306 | * @Controller 307 | @Scope("prototype") 这两个注解不能写到父类中,否则就失效了 308 | * @author LZH 309 | * @date 2017年2月25日 310 | */ 311 | @Controller 312 | @Scope("prototype") 313 | public class RoleAction extends BaseAction { 314 | 315 | private static final long serialVersionUID = 1L; 316 | 317 | /** 318 | * 列表 319 | * 320 | * @return 321 | * @throws Exception 322 | */ 323 | public String list() throws Exception { 324 | List roleList = roleService.listAll(); 325 | ActionContext.getContext().put("roleList", roleList); 326 | return "list"; 327 | } 328 | 329 | /** 330 | * 添加 331 | * 332 | * @return 333 | * @throws Exception 334 | */ 335 | public String add() throws Exception { 336 | roleService.save(model); 337 | return "toList"; 338 | } 339 | 340 | /** 341 | * 删除 342 | * 343 | * @return 344 | * @throws Exception 345 | */ 346 | public String delete() throws Exception { 347 | roleService.delete(model.getId()); 348 | return "toList"; 349 | } 350 | 351 | /** 352 | * 修改 353 | * 354 | * @return 355 | * @throws Exception 356 | */ 357 | public String edit() throws Exception { 358 | Role role = roleService.getById(model.getId()); 359 | role.setName(model.getName()); 360 | role.setDescription(model.getDescription()); 361 | roleService.update(role); 362 | return "toList"; 363 | } 364 | 365 | /** 366 | * 添加页面 367 | * 368 | * @return 369 | * @throws Exception 370 | */ 371 | public String addUI() throws Exception { 372 | return "addUI"; 373 | } 374 | 375 | /** 376 | * 修改页面 377 | * 378 | * @return 379 | * @throws Exception 380 | */ 381 | public String editUI() throws Exception { 382 | Role role = roleService.getById(model.getId()); 383 | model.setName(role.getName()); 384 | model.setDescription(role.getDescription()); 385 | 386 | // ActionContext.getContext().getValueStack().push(role);//放到对象栈的栈顶 387 | return "editUI"; 388 | } 389 | 390 | } 391 | ``` 392 | 393 | ### UserAction 394 | 395 | ```java 396 | package cn.zzuli.oa.view.action; 397 | 398 | import org.springframework.context.annotation.Scope; 399 | import org.springframework.stereotype.Controller; 400 | 401 | import cn.zzuli.oa.base.BaseAction; 402 | import cn.zzuli.oa.domain.User; 403 | 404 | /** 405 | * 用户控制层 406 | * 407 | * @author LZH 408 | * @date 2017年2月26日 409 | */ 410 | @Controller 411 | @Scope("prototype") 412 | public class UserAction extends BaseAction { 413 | 414 | private static final long serialVersionUID = 1L; 415 | 416 | /** 417 | * 列表 418 | * 419 | * @return 420 | * @throws Exception 421 | */ 422 | public String list() throws Exception { 423 | return "list"; 424 | } 425 | 426 | /** 427 | * 添加 428 | * 429 | * @return 430 | * @throws Exception 431 | */ 432 | public String add() throws Exception { 433 | return "toList"; 434 | } 435 | 436 | /** 437 | * 添加页面 438 | * 439 | * @return 440 | * @throws Exception 441 | */ 442 | public String addUI() throws Exception { 443 | return "addUI"; 444 | } 445 | 446 | /** 447 | * 删除 448 | * 449 | * @return 450 | * @throws Exception 451 | */ 452 | public String delete() throws Exception { 453 | return "toList"; 454 | } 455 | 456 | /** 457 | * 修改 458 | * 459 | * @return 460 | * @throws Exception 461 | */ 462 | public String edit() throws Exception { 463 | return "toList"; 464 | } 465 | 466 | /** 467 | * 修改页面 468 | * 469 | * @return 470 | * @throws Exception 471 | */ 472 | public String editUI() throws Exception { 473 | return "editUI"; 474 | } 475 | 476 | /** 477 | * 初始化密码为1234 478 | * 479 | * @return 480 | * @throws Exception 481 | */ 482 | public String initPassword() throws Exception { 483 | return "toList"; 484 | } 485 | 486 | } 487 | ``` 488 | 489 | -------------------------------------------------------------------------------- /Spring/Spring--day04.md: -------------------------------------------------------------------------------- 1 | # 一、spring day03回顾 2 | 3 | ## 1.1事务管理 4 | 5 | - 基于xml配置 6 | 7 | ```xml 8 | 1.配置事务管理器 9 | jdbc:DataSourceTransactionManager 10 | hibernate:HibernateTransactionManager 11 | 2.事务通知(详情、属性) 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 3. AOP编程,ABCD--> ABC 20 | 21 | 22 | ``` 23 | 24 | 25 | - 基于注解 26 | 27 | ```xml 28 | xml 配置 29 | 1.事务管理器 30 | 31 | 2.将配置事务管理器交予spring 32 | 33 | 34 | 35 | 目标类 36 | @Transactional 类 | 方法 37 | ``` 38 | 39 | ## 1.2整合Junit 40 | 41 | @RunWith(SpringJunit4RnnerClass.class) 42 | 43 | @ContextConfiguration(locations="classpath:...xml") 44 | 45 | @Autowired 注入 46 | 47 | @Test 测试 48 | 49 | ## 1.3整合web 50 | 51 | web.xml 配置 52 | 53 | 1.确定xml位置 54 | 55 | <context-param> 56 | 57 | name:contextConfigLocation 58 | 59 | value:classpath:...xml 60 | 61 | 2.加载xml文件,配置监听器 62 | 63 | ContextLoaderListener 64 | 65 | ## 1.4整合 66 | 67 | 1. hibernate po (domain、bean) 68 | 2. dao层 69 | 70 | 需要HibernateTemplate 相当于session操作PO类--> 必须提供setter方法,让spring注入,xml配置模板 71 | 72 | save() update delete saveOrUpdate find 73 | 74 | 继承HibernateDaoSupport,需要注入SessionFactory,底层自动创建模板 75 | 76 | dao方法中this.getHibernateTemplate() 77 | 78 | 3.service 层,spring配置 79 | 80 | properties <context:property-placeholder location> 81 | 82 | 配置数据源:ComboPooledDataSource 83 | 84 | 配置SessionFactory:LocalSessionFactoryBean 85 | 86 | 事务管理 87 | 88 | 4.web层,aciton 89 | 90 | struts.xml <action name="" class="全限定类名"> 前面看到一位struts,底层使用spring 91 | 92 | 默认与spring整合之后,按照【名称】自动注入 93 | 94 | # 二、SVN 95 | 96 | ## 2.1版本控制 97 | 98 | ### 2.1.1什么版本控制 99 | 100 | - 版本控制(Revision Control):是维护工程蓝图的标准做法,能追踪工程蓝图从诞生一直到定案的过程。是一种记录若干文件内容变化,以便将来查阅特定版本修订情况的系统。也是一种软体工程技巧,籍以在开发的过程中,确保由不同人所编辑的同一档案都得到更新。 101 | 102 | ### 2.1.2版本控制软件 103 | 104 | - CVS(Concurrent Versions System)代表协作版本系统或者并发版本系统,是一种版本控制系统,方便软件的开发和使用者协同工作。 105 | - VSS (Visual Source Safe )只能在windows下,作为Microsoft Visual Studio 的一名成员,它主要任务就是负责项目文件的管理 106 | - Git是用于Linux内核开发的版本控制工具。它采用了分布式版本库的方式,不必服务器端软件支持,使源代码的发布和交流极其方便。Git的速度很快,这对于诸如Linux kernel这样的大项目来说自然很重要。Git最为出色的是它的合并跟踪(merge tracing)能力。 www.github.org 107 | 108 | 109 | - SVN(Subversion ),是一个开放源代码的版本控制系统,采用了分支管理系统,它的设计目标就是取代CVS。 110 | 111 | ## 2.2SVN特点 112 | 113 | - 统一的版本号。CVS是对每个文件顺序编排版本号,在某一时间各文件的版本号各不相同。而Subversion下,任何一次提交都会对所有文件增加到同一个新版本号,即使是提交并不涉及的文件。所以,各文件在某任意时间的版本号是相同的。版本号相同的文件构成软件的一个版本。 114 | - 原子提交。一次提交不管是单个还是多个文件,都是作为一个整体提交的。在这当中发生的意外例如传输中断,不会引起数据库的不完整和数据损坏。 115 | - 重命名、复制、删除文件等动作都保存在版本历史记录当中。 116 | - 对于二进制文件,使用了节省空间的保存方法。(简单的理解,就是只保存和上一版本不同之处) 117 | - 目录也有版本历史。整个目录树可以被移动或者复制,操作很简单,而且能够保留全部版本记录。 118 | - 分支的开销非常小。 119 | - 优化过的数据库访问,使得一些操作不必访问数据库就可以做到。这样减少了很多不必要的和数据库主机之间的网络流量。 120 | - 支持元数据(Metadata)管理。每个目录或文件都可以定义属性(Property),它是一些隐藏的键值对,用户可以自定义属性内容,而且属性和文件内容一样在版本控制范围内。 121 | - 支持FSFS和Berkeley DB两种资料库格式。 122 | - 不足:只能设置目录的访问权限,无法设置单个文件的访问权限。 123 | 124 | ## 2.3体系结构 125 | 126 | ![](http://upload-images.jianshu.io/upload_images/1540531-89067284b445cc5a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 127 | 128 | ## 2.4安装 129 | 130 | ![](http://upload-images.jianshu.io/upload_images/1540531-1bd1217bb5200abb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 131 | 132 | - 测试安装 133 | 134 | ![](http://upload-images.jianshu.io/upload_images/1540531-30a19260333cec8f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 135 | 136 | - 检查path系统环境变量 137 | 138 | ![](http://upload-images.jianshu.io/upload_images/1540531-a406b3d127fd6953.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 139 | 140 | ## 2.5创建仓库 141 | 142 | - 格式:cmd> svnadmin create 路径 143 | 144 | ![](http://upload-images.jianshu.io/upload_images/1540531-78a81e7411f59830.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 145 | 146 | 147 | - 仓库目录结构 148 | 149 | ![](http://upload-images.jianshu.io/upload_images/1540531-8bce08c7e020ee9f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 150 | 151 | - 注意: 创建仓库时,目录必须是空的,及新建文件夹 152 | 153 | ## 2.6启动 154 | 155 | - 格式:cmd> svnserve -d -r 仓库的路径 156 | 157 | ```cmake 158 | -d后台执行 159 | -r版本库的根目录 160 | ``` 161 | 162 | 启动时,指定"仓库路径"不同,分类:多仓库和单仓库 163 | 164 | - 多仓库【掌握】 165 | 166 | ![](http://upload-images.jianshu.io/upload_images/1540531-0a9be1e323e9de00.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 167 | 168 | 169 | 启动:svnserve -d -r 仓库父目录 ,表示启动时多仓库 170 | 171 | 例如:svnserve -d -r G:\repository\svn 172 | 173 | 访问:svn://localhost:3690/bbs 174 | 175 | - 单仓库 176 | 177 | ![](http://upload-images.jianshu.io/upload_images/1540531-88e017f7a0af2543.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 178 | 179 | 180 | 启动:svnserve -d -r 仓库的根 ,表示启动时单仓库 181 | 182 | 例如:svnserve -d -r G:\repository\svn\bbs 183 | 184 | 访问:svn://localhost:3690 185 | 186 | - 将操作注册成操作系统的"服务",开机启动。 187 | 188 | 1."运行",services.msc 打开"服务" 189 | 190 | 2. 删除"服务" 191 | 192 | ![](http://upload-images.jianshu.io/upload_images/1540531-a37772e5da2bee54.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 193 | 194 | 3. 注册"服务" 195 | 196 | ![](http://upload-images.jianshu.io/upload_images/1540531-b3c15f10a5e28e77.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 197 | 198 | ``` 199 | sc create svn binpath= "D:\java\Subversion\bin\svnserve.exe --service -r G:\repository\svn" displayname= "SVN-Service" start= auto depend= Tcpip 200 | ``` 201 | 202 | 4. 启动或停止"服务" 203 | 204 | ![](http://upload-images.jianshu.io/upload_images/1540531-6206d387278e17b8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 205 | 206 | ## 2.7操作【掌握思想】 207 | 208 | ![](http://upload-images.jianshu.io/upload_images/1540531-937e32839e94cdb4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 209 | 210 | ### 2.7.1checkout 211 | 212 | - 格式:svn checkout 服务器地址 下载地址 213 | 214 | ![](http://upload-images.jianshu.io/upload_images/1540531-c3c9b99f742b3404.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 215 | 216 | ### 2.7.2commit 217 | 218 | - 格式:svn commit 资源 219 | 220 | 问题1:没有纳入版本控制 221 | 222 | ![](http://upload-images.jianshu.io/upload_images/1540531-0cc8477f78d15316.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 223 | 224 | 使用add子命令添加到本地版本库 225 | 226 | ![](http://upload-images.jianshu.io/upload_images/1540531-208e269705bd7fe2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 227 | 228 | 229 | 问题2:没有编写日志 230 | 231 | ![](http://upload-images.jianshu.io/upload_images/1540531-c3bfca17d7bf24f1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 232 | 233 | 234 | 采用-m 参数设置日志信息 235 | 236 | ![](http://upload-images.jianshu.io/upload_images/1540531-0d344bcb078025a5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 237 | 238 | 239 | 问题3:没有权限 240 | 241 | ![](http://upload-images.jianshu.io/upload_images/1540531-44c8bfc03eea4a90.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 242 | 243 | 244 | 修改权限,设置匿名访问 245 | 246 | G:\repository\svn\bbs\conf\svnserve.conf 247 | 248 | ![](http://upload-images.jianshu.io/upload_images/1540531-9d06def8c1982abc.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 249 | 250 | 251 | ### 2.7.3update 252 | 253 | - 格式:svn update 254 | 255 | ![](http://upload-images.jianshu.io/upload_images/1540531-3dc55b059074e16c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 256 | 257 | ## 2.8图形化:TortoiseSVN 安装 258 | 259 | ![](http://upload-images.jianshu.io/upload_images/1540531-2f7a5a3b79aed58b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 260 | 261 | - 安装成功之后,所有的操作都是"右键" 262 | 263 | ## 2.9svn权限 264 | 265 | - 权限需要3个配置文件 266 | 267 | ![](http://upload-images.jianshu.io/upload_images/1540531-bb5f18fcaab5b028.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 268 | 269 | - svnserve.conf 270 | 271 | 开启认证 272 | 273 | ![](http://upload-images.jianshu.io/upload_images/1540531-a68c8a53042e29e6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 274 | 275 | 276 | 确定账号配置文件位置 277 | 278 | ![](http://upload-images.jianshu.io/upload_images/1540531-27129484597a1b5f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 279 | 280 | 确定认证配置文件位置 281 | 282 | ![](http://upload-images.jianshu.io/upload_images/1540531-ea8847620024c6c2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 283 | 284 | 285 | - passwd 账号配置(一行一个账号,账号用户名和密码组成,使用等号分隔) 286 | 287 | ![](http://upload-images.jianshu.io/upload_images/1540531-166987cbf7f65865.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 288 | 289 | - authz 认证配置文件 290 | 291 | 配置组,格式:组名= 用户1 ,用户2,.... 292 | 293 | ![](http://upload-images.jianshu.io/upload_images/1540531-7579787e26f1a198.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 294 | 295 | 296 | 认证细节配置 297 | 298 | 多仓库 299 | 300 | ​ [bbs:/] -->确定仓库名称 。[bbs:/doc] 给bbs仓库的doc目录配置权限 301 | 302 | ​ @itheima= rw --> 给itheima组设置权限。 303 | 304 | ​ read('r') ,read-write('rw') ,or no access(''). 305 | 306 | ​ user3= r --> 给user3 指定权限 307 | 308 | ​ *= --> 其他用户没有权限 309 | 310 | ![](http://upload-images.jianshu.io/upload_images/1540531-57b068f24c90fca5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 311 | 312 | 单仓库 313 | 314 | [/] -->当仓库的根 [/doc] 单仓库doc目录 315 | 316 | ![](http://upload-images.jianshu.io/upload_images/1540531-c5dfb7cc727c1150.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 317 | 318 | ## 2.10TortoiseSVN 常见图标 319 | 320 | ![](http://upload-images.jianshu.io/upload_images/1540531-729c2e614ca4a99c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 321 | 322 | ## 2.11myeclipse svn 插件 323 | 324 | ### 2.11.1安装插件 325 | 326 | ![](http://upload-images.jianshu.io/upload_images/1540531-61bff8a075149523.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 327 | 328 | 如果3个都不能使用,直接换eclipse 329 | 330 | - 安装方式1:直接复制 331 | 332 | ![](http://upload-images.jianshu.io/upload_images/1540531-bfb382881ad82ed0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 333 | 334 | eclipse插件规范 335 | 336 | eclipse 目录 337 | 338 | | -- features目录 339 | 340 | | -- plugins 目录 341 | 342 | - 方式2:使用link文件 343 | 344 | 将插件解压到任意目录(不含中文、空格),在myeclipse/dropins目录添加一个link文件 345 | 346 | 文件名:自定义 347 | 348 | 文件扩展名:link 349 | 350 | 文件内容: 351 | 352 | path = 插件完整目录,需要指定到eclipse,及可以看到(features 、plugins) 353 | 354 | 例如: 355 | 356 | path=D:\\java\\MyEclipse\\MyEclipse 10\\svn\\eclipse 357 | 358 | path=D:/java/MyEclipse/MyEclipse 10/svn/eclipse 359 | 360 | - 方式3:在线安装 361 | 362 | - 安装成功标志 363 | 364 | ![](http://upload-images.jianshu.io/upload_images/1540531-f834aa745e03a902.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 365 | 366 | ### 2.11.2操作 367 | 368 | ## 2.12svn目录规范 369 | 370 | ![](http://upload-images.jianshu.io/upload_images/1540531-17ee1fb6f2db8d19.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 371 | 372 | ![](http://upload-images.jianshu.io/upload_images/1540531-de8f06a36b40a6a8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 373 | 374 | trunk ,主线,用于存放程序整个进度 375 | 376 | branches ,分支,例如:bug修复、特殊功能等 377 | 378 | tags,标签(版本),此目录下的内容不能修改 -------------------------------------------------------------------------------- /项目笔记/Struts标签的显示问题.md: -------------------------------------------------------------------------------- 1 | # Struts2中修改自定义标签的源代码使标签不显示 2 | 3 | > 某些页面中关于权限的显示及链接的问题。可以通过修改Struts2里的自定义标签的源代码来使标签不显示 4 | > 5 | > 我以\为例 6 | 7 | ## 1、找到Struts2里面的标签配置文件struts-tag.tld 8 | 9 | ![Struts2标签的源代码配置文件struts-tag.tld](http://upload-images.jianshu.io/upload_images/1540531-55c5124e8b934a44.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 10 | 11 | ## 2、找到\a\节点 12 | 13 | ![结点标签](http://upload-images.jianshu.io/upload_images/1540531-2ca5f02846a9a7a0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 14 | 15 | > 说明:tag节点代表一个struts2的标签,里面有名称、属性、说明、源文件等内容 16 | 17 | ## 3、打开org.apache.struts2.views.jsp.ui.AnchorTag 18 | 19 | ```java 20 | /* 21 | * $Id$ 22 | * 23 | * Licensed to the Apache Software Foundation (ASF) under one 24 | * or more contributor license agreements. See the NOTICE file 25 | * distributed with this work for additional information 26 | * regarding copyright ownership. The ASF licenses this file 27 | * to you under the Apache License, Version 2.0 (the 28 | * "License"); you may not use this file except in compliance 29 | * with the License. You may obtain a copy of the License at 30 | * 31 | * http://www.apache.org/licenses/LICENSE-2.0 32 | * 33 | * Unless required by applicable law or agreed to in writing, 34 | * software distributed under the License is distributed on an 35 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 36 | * KIND, either express or implied. See the License for the 37 | * specific language governing permissions and limitations 38 | * under the License. 39 | */ 40 | 41 | package org.apache.struts2.views.jsp.ui; 42 | 43 | import javax.servlet.http.HttpServletRequest; 44 | import javax.servlet.http.HttpServletResponse; 45 | 46 | import org.apache.struts2.components.Anchor; 47 | import org.apache.struts2.components.Component; 48 | 49 | import com.opensymphony.xwork2.util.ValueStack; 50 | 51 | /** 52 | * @see Anchor 53 | */ 54 | public class AnchorTag extends AbstractClosingTag { 55 | 56 | private static final long serialVersionUID = -1034616578492431113L; 57 | 58 | protected String href; 59 | protected String includeParams; 60 | protected String scheme; 61 | protected String action; 62 | protected String namespace; 63 | protected String method; 64 | protected String encode; 65 | protected String includeContext; 66 | protected String escapeAmp; 67 | protected String portletMode; 68 | protected String windowState; 69 | protected String portletUrlType; 70 | protected String anchor; 71 | protected String forceAddSchemeHostAndPort; 72 | 73 | public Component getBean(ValueStack stack, HttpServletRequest req, HttpServletResponse res) { 74 | return new Anchor(stack, req, res); 75 | } 76 | 77 | protected void populateParams() { 78 | super.populateParams(); 79 | 80 | Anchor tag = (Anchor) component; 81 | tag.setHref(href); 82 | tag.setIncludeParams(includeParams); 83 | tag.setScheme(scheme); 84 | tag.setValue(value); 85 | tag.setMethod(method); 86 | tag.setNamespace(namespace); 87 | tag.setAction(action); 88 | tag.setPortletMode(portletMode); 89 | tag.setPortletUrlType(portletUrlType); 90 | tag.setWindowState(windowState); 91 | tag.setAnchor(anchor); 92 | 93 | if (encode != null) { 94 | tag.setEncode(Boolean.valueOf(encode).booleanValue()); 95 | } 96 | if (includeContext != null) { 97 | tag.setIncludeContext(Boolean.valueOf(includeContext).booleanValue()); 98 | } 99 | if (escapeAmp != null) { 100 | tag.setEscapeAmp(Boolean.valueOf(escapeAmp).booleanValue()); 101 | } 102 | if (forceAddSchemeHostAndPort != null) { 103 | tag.setForceAddSchemeHostAndPort(Boolean.valueOf(forceAddSchemeHostAndPort).booleanValue()); 104 | } 105 | } 106 | 107 | public void setHref(String href) { 108 | this.href = href; 109 | } 110 | 111 | public void setEncode(String encode) { 112 | this.encode = encode; 113 | } 114 | 115 | public void setIncludeContext(String includeContext) { 116 | this.includeContext = includeContext; 117 | } 118 | 119 | public void setEscapeAmp(String escapeAmp) { 120 | this.escapeAmp = escapeAmp; 121 | } 122 | 123 | public void setIncludeParams(String name) { 124 | includeParams = name; 125 | } 126 | 127 | public void setAction(String action) { 128 | this.action = action; 129 | } 130 | 131 | public void setNamespace(String namespace) { 132 | this.namespace = namespace; 133 | } 134 | 135 | public void setMethod(String method) { 136 | this.method = method; 137 | } 138 | 139 | public void setScheme(String scheme) { 140 | this.scheme = scheme; 141 | } 142 | 143 | public void setValue(String value) { 144 | this.value = value; 145 | } 146 | 147 | public void setPortletMode(String portletMode) { 148 | this.portletMode = portletMode; 149 | } 150 | 151 | public void setPortletUrlType(String portletUrlType) { 152 | this.portletUrlType = portletUrlType; 153 | } 154 | 155 | public void setWindowState(String windowState) { 156 | this.windowState = windowState; 157 | } 158 | 159 | public void setAnchor(String anchor) { 160 | this.anchor = anchor; 161 | } 162 | 163 | public void setForceAddSchemeHostAndPort(String forceAddSchemeHostAndPort) { 164 | this.forceAddSchemeHostAndPort = forceAddSchemeHostAndPort; 165 | } 166 | } 167 | ``` 168 | 169 | ## 4、在自己的项目中建一个与这个源代码包名、类名一模一样的类 170 | 171 | > 说明:里面的代码跟struts2里面的源代码一样复制过来 172 | 173 | ![类](http://upload-images.jianshu.io/upload_images/1540531-254a34e8076412c6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 174 | 175 | ## 5、编辑 176 | 177 | ```java 178 | /* 179 | * $Id$ 180 | * 181 | * Licensed to the Apache Software Foundation (ASF) under one 182 | * or more contributor license agreements. See the NOTICE file 183 | * distributed with this work for additional information 184 | * regarding copyright ownership. The ASF licenses this file 185 | * to you under the Apache License, Version 2.0 (the 186 | * "License"); you may not use this file except in compliance 187 | * with the License. You may obtain a copy of the License at 188 | * 189 | * http://www.apache.org/licenses/LICENSE-2.0 190 | * 191 | * Unless required by applicable law or agreed to in writing, 192 | * software distributed under the License is distributed on an 193 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 194 | * KIND, either express or implied. See the License for the 195 | * specific language governing permissions and limitations 196 | * under the License. 197 | */ 198 | 199 | package org.apache.struts2.views.jsp.ui; 200 | 201 | import javax.servlet.http.HttpServletRequest; 202 | import javax.servlet.http.HttpServletResponse; 203 | import javax.servlet.jsp.JspException; 204 | 205 | import org.apache.struts2.components.Anchor; 206 | import org.apache.struts2.components.Component; 207 | 208 | import com.opensymphony.xwork2.util.ValueStack; 209 | 210 | import cn.zzuli.oa.domain.User; 211 | 212 | /** 213 | * @see Anchor 214 | */ 215 | public class AnchorTag extends AbstractClosingTag { 216 | 217 | private static final long serialVersionUID = -1034616578492431113L; 218 | 219 | protected String href; 220 | protected String includeParams; 221 | protected String scheme; 222 | protected String action; 223 | protected String namespace; 224 | protected String method; 225 | protected String encode; 226 | protected String includeContext; 227 | protected String escapeAmp; 228 | protected String portletMode; 229 | protected String windowState; 230 | protected String portletUrlType; 231 | protected String anchor; 232 | protected String forceAddSchemeHostAndPort; 233 | 234 | @Override 235 | public int doEndTag() throws JspException { 236 | //当前登录用户 237 | User user = (User) pageContext.getSession().getAttribute("user"); 238 | 239 | //当前准备显示链接对应的权限URL 240 | String privUrl = action; 241 | 242 | //去掉参数 243 | int pos = privUrl.indexOf("?"); 244 | if(pos > -1) { 245 | privUrl = privUrl.substring(0, pos); 246 | } 247 | 248 | //去掉UI后缀 249 | if(privUrl.endsWith("UI")) { 250 | privUrl = privUrl.substring(0, privUrl.length() - 2); 251 | } 252 | 253 | //根据用户是否有这个权限,来判断是否在页面中显示链接信息 254 | if(user.hasPrivilegeByUrl("/" + privUrl)) { 255 | return super.doEndTag();//正常的生成并显示的超链接标签,并继续执行页面中后面的代码 256 | }else { 257 | return EVAL_PAGE;//不生成不显示超链接标签,只是继续执行页面中后面的代码 258 | } 259 | } 260 | 261 | public Component getBean(ValueStack stack, HttpServletRequest req, HttpServletResponse res) { 262 | return new Anchor(stack, req, res); 263 | } 264 | 265 | protected void populateParams() { 266 | super.populateParams(); 267 | 268 | Anchor tag = (Anchor) component; 269 | tag.setHref(href); 270 | tag.setIncludeParams(includeParams); 271 | tag.setScheme(scheme); 272 | tag.setValue(value); 273 | tag.setMethod(method); 274 | tag.setNamespace(namespace); 275 | tag.setAction(action); 276 | tag.setPortletMode(portletMode); 277 | tag.setPortletUrlType(portletUrlType); 278 | tag.setWindowState(windowState); 279 | tag.setAnchor(anchor); 280 | 281 | if (encode != null) { 282 | tag.setEncode(Boolean.valueOf(encode).booleanValue()); 283 | } 284 | if (includeContext != null) { 285 | tag.setIncludeContext(Boolean.valueOf(includeContext).booleanValue()); 286 | } 287 | if (escapeAmp != null) { 288 | tag.setEscapeAmp(Boolean.valueOf(escapeAmp).booleanValue()); 289 | } 290 | if (forceAddSchemeHostAndPort != null) { tag.setForceAddSchemeHostAndPort(Boolean.valueOf(forceAddSchemeHostAndPort).booleanValue()); 291 | } 292 | } 293 | 294 | public void setHref(String href) { 295 | this.href = href; 296 | } 297 | 298 | public void setEncode(String encode) { 299 | this.encode = encode; 300 | } 301 | 302 | public void setIncludeContext(String includeContext) { 303 | this.includeContext = includeContext; 304 | } 305 | 306 | public void setEscapeAmp(String escapeAmp) { 307 | this.escapeAmp = escapeAmp; 308 | } 309 | 310 | public void setIncludeParams(String name) { 311 | includeParams = name; 312 | } 313 | 314 | public void setAction(String action) { 315 | this.action = action; 316 | } 317 | 318 | public void setNamespace(String namespace) { 319 | this.namespace = namespace; 320 | } 321 | 322 | public void setMethod(String method) { 323 | this.method = method; 324 | } 325 | 326 | public void setScheme(String scheme) { 327 | this.scheme = scheme; 328 | } 329 | 330 | public void setValue(String value) { 331 | this.value = value; 332 | } 333 | 334 | public void setPortletMode(String portletMode) { 335 | this.portletMode = portletMode; 336 | } 337 | 338 | public void setPortletUrlType(String portletUrlType) { 339 | this.portletUrlType = portletUrlType; 340 | } 341 | 342 | public void setWindowState(String windowState) { 343 | this.windowState = windowState; 344 | } 345 | 346 | public void setAnchor(String anchor) { 347 | this.anchor = anchor; 348 | } 349 | 350 | public void setForceAddSchemeHostAndPort(String forceAddSchemeHostAndPort) { 351 | this.forceAddSchemeHostAndPort = forceAddSchemeHostAndPort; 352 | } 353 | } 354 | ``` 355 | 356 | ## 6、说明 357 | 358 | 系统会先加载classpath目录下的代码,如果没有则再去jar包里面的加载。一般我们覆盖doEndTag()方法即可。 359 | 360 | -------------------------------------------------------------------------------- /JavaScript/jQuery--day01.md: -------------------------------------------------------------------------------- 1 | # 一、jQuery介绍 2 | 3 | ## 1.1JS类库 4 | 5 | - JavaScript 库封装了很多预定义的 **对象** 和实用 **函数** 。能帮助使用者建立有高难度交互客户端页面, 并且兼容各大浏览器。 6 | 7 | ## 1.2当前流行的JavaScript 库有: 8 | 9 | - jQuery,最流行 10 | - EXT\_JS,2.0开始收费 11 | - Dojo ,很多js单独文件,优化:打包。(常见:开发小图标,一张图片) 12 | - Prototype,对js扩展,框架开发。 13 | - YUI(Yahoo! User Interface) ,taobao之前使用。 14 | - 淘宝UI:http://docs.kissyui.com/ 15 | - Bootstrap ,来自Twitter,是目前很受欢迎的前端框架。Bootstrap 是基于HTML、CSS、JAVASCRIPT 的,它简洁灵活,使得Web 开发更加快捷。基于jQuery 一个UI工具 16 | 17 | ## 1.3jQuery介绍 18 | 19 | - JQuery是继prototype之后又一个优秀的Javascript库。它是轻量级的js库,它兼容CSS3,还兼容各种浏览器(IE 6.0+, FF 1.5+, Safari 2.0+, Opera 9.0+),jQuery2.0及后续版本将不再支持IE6/7/8浏览器。jQuery使用户能更方便地处理HTML(标准通用标记语言下的一个应用)、events、实现动画效果,并且方便地为网站提供AJAX交互。jQuery还有一个比较大的优势是,它的文档说明很全,而且各种应用也说得很详细,同时还有许多成熟的插件可供选择。jQuery能够使用户的html页面保持代码和html内容分离,也就是说,不用再在html里面插入一堆js来调用命令了,只需要定义id即可。 20 | - 轻量级:依赖程序少,占用的资源的少 21 | - 特点:js代码和html代码分离 22 | - jQuery已经成为最流行的javascript库,在世界前10000个访问最多的网站中,有超过55%在使用jQuery。 23 | - 由美国人John Resig在2006年1月发布 24 | - jQuery是免费、开源的 25 | - jQuery分类: 26 | 27 | WEB版本:我们主要学习研究 28 | 29 | UI版本:集成了UI组件 30 | 31 | mobile版本:针对移动端开发 32 | 33 | qunit版本:用于js测试的 34 | 35 | 36 | 37 | ## 1.4版本介绍 38 | 39 | ![](http://upload-images.jianshu.io/upload_images/1540531-27a34af3af551d85.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 40 | 41 | ![](http://upload-images.jianshu.io/upload_images/1540531-cc97fdd1f3d264f6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 42 | 43 | ## 1.5优点 44 | 45 | - 核心理念是write less,do more(写得更少,做得更多) 46 | 47 | ![](http://upload-images.jianshu.io/upload_images/1540531-61471aadf95652a9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 48 | 49 | - 轻量级:源码1.11.js大小是286kb,压缩班1.11.min.js大小是94.1k。如果使用GZIP压缩更小。 50 | 51 | - 兼容各种浏览器(IE 6.0+, FF 1.5+, Safari 2.0+, Opera 9.0+) 52 | 53 | - jQuery的语法设计可以使开发者更加便捷 54 | 55 | - 例如操作文档对象、选择DOM元素、制作动画效果、事件处理、使用Ajax以及其他功能 56 | 57 | - jQuery能够使用户的html页面保持代码和html内容分离 58 | 59 | - 不用再在html里面插入一堆js来调用命令了,只需要定义id即可 60 | 61 | - jQuery提供API让开发者编写插件,有许多成熟的插件可供选择 62 | 63 | - 文档说明很全 64 | 65 | # 二、基本语法 66 | 67 | ## 2.1jQuery语法 68 | 69 | ```html 70 | 83 | ``` 84 | 85 | ## 2.2jQuery对象和dom对象转换 86 | 87 | ```html 88 | 107 | ``` 108 | 109 | 110 | 111 | # 三、选择器 112 | 113 | ## 3.1基本【掌握】 114 | 115 | ![](http://upload-images.jianshu.io/upload_images/1540531-c7c6596538f9e364.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 116 | 117 | id ,id选择器,<xxx id=""> 通过id值获得元素 118 | 119 | element,标签选择器,<xxx> 通过标签名获得元素 120 | 121 | **.** class ,类选择器,<xxx class=""> 通过class值获得元素。注意:使用点开头 122 | 123 | s1,s2,... 多选择器,将多个选择器的结果添加一个数组中。 124 | 125 | 有 126 | 127 | ## 3.2层级 128 | 129 | ![](http://upload-images.jianshu.io/upload_images/1540531-754417653ccb7e14.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 130 | 131 | A B ,获得A元素内部所有的B后代元素。(爷孙) 132 | 133 | A > B ,获得A元素内部所有的B子元素。(父子) 134 | 135 | A + B ,获得A元素后面的第一个兄弟B。(兄弟) 136 | 137 | A ~ B ,获得A元素后面的所有的兄弟B。(兄弟) 138 | 139 | 140 | 141 | ## 3.3基本过滤 142 | 143 | - 过滤选择器格式 ":关键字" 144 | 145 | ![](http://upload-images.jianshu.io/upload_images/1540531-81fbb7c1582d8fa6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 146 | 147 | :first , 第一个 148 | 149 | :last ,最后一个 150 | 151 | :eq(index) ,获得指定索引 152 | 153 | :gt(index) 大于 154 | 155 | :lt(index) 小于 156 | 157 | :even 偶数,从0 开始计数。例如:查找表格的1、3、5...行(即索引值0、2、4...) 158 | 159 | :odd 奇数 160 | 161 | :not(selector) 去除所有与给定选择器匹配的元素 162 | 163 | :header 获得所有标题元素。例如:<h1>...<h6> 164 | 165 | :animated 获得所有动画 166 | 167 | :focus 获得焦点 168 | 169 | ## 3.4内容过滤 170 | 171 | ![](http://upload-images.jianshu.io/upload_images/1540531-a503d0f081282b82.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 172 | 173 | :empty 当前元素是否为空(是否有标签体--子元素、文本) 174 | 175 | :has(...) 当前元素,是否含有指定的子元素 176 | 177 | :parent 当前元素是否是父元素 178 | 179 | :contains( text ) 标签体是否含有指定的文本 180 | 181 | ## 3.5可见性过滤[掌握] 182 | 183 | ![](http://upload-images.jianshu.io/upload_images/1540531-48d9a94423ee8f77.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 184 | 185 | :hidden 隐藏。特指<xxx style="display:none";> ,获得<input type="hidden"> 186 | 187 | :visible 可见(默认) 188 | 189 | ## 3.6属性【掌握】 190 | 191 | ![](http://upload-images.jianshu.io/upload_images/1540531-90d2caf5cc183a0e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 192 | 193 | [属性名] 获得指定的属性名的元素 194 | 195 | [属性名=值] 获得属性名等于指定值的的元素【1】 196 | 197 | [属性名!=值] 获得属性名不等于指定值的的元素 198 | 199 | \[as1\]\[as2\][as3].... 复合选择器,多个条件同时成立。类似where ...and...and【2】 200 | 201 | [属性名^=值] 获得以属性值开头的元素 202 | 203 | [属性名$=值] 获得以属性值结尾的元素 204 | 205 | [属性名\*=值] 获得含有属性值 的元素 206 | 207 | ## 3.7子元素过滤 208 | 209 | ![](http://upload-images.jianshu.io/upload_images/1540531-099cda60b37cf136.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 210 | 211 | :nth-child(index) ,获得第几个孩子,从1开始。 212 | 213 | :first-child ,获得第一个孩子 214 | 215 | :last-child ,获得最后孩子 216 | 217 | :only-child ,获得独生子 218 | 219 | ## 3.8表单过滤 220 | 221 | ![](http://upload-images.jianshu.io/upload_images/1540531-3a1cf359f09b371f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 222 | 223 | :input 所有的表单元素。(<input> / <select> / <textarea> / <button>) 224 | 225 | :text 文本框<input type="text"> 226 | 227 | :password 密码框<input type=" password "> 228 | 229 | :radio 单选<input type="radio"> 230 | 231 | :checkbox 复选框<input type="checkbox"> 232 | 233 | :submit 提交按钮<input type="submit"> 234 | 235 | :image 图片按钮<input type="image" src=""> 236 | 237 | :reset 重置按钮<input type="reset""> 238 | 239 | :file 文件上传<input type="file"> 240 | 241 | :hidden 隐藏域<input type="hidden"> ,还可以获得<xxx style="display:none"> 242 | 243 | ​ 其他值:<br> <option> ,存在浏览器兼容问题 244 | 245 | 246 | :button 所有普通按钮。<button > 或<input type="button"> 247 | 248 | ## 3.9表单对象属性过滤【掌握】 249 | 250 | ![](http://upload-images.jianshu.io/upload_images/1540531-b5e9ba79c353e734.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 251 | 252 | :enabled 可用 253 | 254 | :disabled 不可用。<xxx disabled="disabled"> 或<xxx disabled=""> 或 <xxx disabled> 255 | 256 | :checked 选中(单选框radio、复选框checkbox) 257 | 258 | :selected 选择(下拉列表select option) 259 | 260 | 261 | 262 | # 四、属性和CSS 263 | 264 | ## 4.1属性【掌握】 265 | 266 | ![](http://upload-images.jianshu.io/upload_images/1540531-c3c513309056cc89.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 267 | 268 | attr(name) 获得指定属性名的值 269 | 270 | attr(key ,val ) 给一个指定属性名设置值 271 | 272 | attr(prop ) 给多个属性名设置值。参数:prop json数据 273 | 274 | {k : v , k : v , .....} 275 | 276 | removeAttr(name) 移除指定属性 277 | 278 | ## 4.2CSS类 279 | 280 | - <xxx class="a b c d my "> 281 | 282 | ![](http://upload-images.jianshu.io/upload_images/1540531-ae88e92d486b7eb4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 283 | 284 | addClass("my") 追加一个类 285 | 286 | removeClass("my") 将指定类移除 287 | 288 | toggleClass("my") 如果有my将移除,如果没有将添加。 289 | 290 | ## 4.3HTML代码/文本/值【掌握】 291 | 292 | ![](http://upload-images.jianshu.io/upload_images/1540531-b9f5533016115cd5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 293 | 294 | val() 获得value的值 295 | 296 | val(text) 设置value的值 297 | 298 | html() 获得html代码,含有标签 299 | 300 | html(...) 设置html代码,如果有标签,将进行解析。 301 | 302 | text() 获得文本值,将标签进行过滤 303 | 304 | text(...) 设置文本值,如果有标签,将被转义 --> < &lt; & &amp; > &lt; 305 | 306 | ## 4.4CSS 307 | 308 | - <xxx style="key:value; key:value; "> 309 | 310 | ![](http://upload-images.jianshu.io/upload_images/1540531-dea59b865614f68c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 311 | 312 | css(name) 获得指定名称的css值 313 | 314 | css(name ,value) 设置一对值 315 | 316 | css(prop) 设置一组值 317 | 318 | ## 4.5位置 319 | 320 | ![](http://upload-images.jianshu.io/upload_images/1540531-d0d908920eef6593.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 321 | 322 | offset() 获得坐标,返回JSON对象,{"top":200, "left" : 100} 323 | 324 | ![](http://upload-images.jianshu.io/upload_images/1540531-75c7f475626ef955.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 325 | 326 | 327 | offset(...) 设置坐标。例如:$(this).offset({"top":0 , "left" : 0}) 328 | 329 | scrollTop() 垂直滚动条滚过的距离 330 | 331 | scrollLeft() 水平滚动条滚过的距离 332 | 333 | ## 4.6尺寸 334 | 335 | ![](http://upload-images.jianshu.io/upload_images/1540531-46cd9aeace593355.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 336 | 337 | height([...]) 获得或设置高度 338 | 339 | width([...])获得或设置宽度 340 | 341 | # 五、文档处理 342 | 343 | ## 5.1内部插入【掌握】 344 | 345 | ![](http://upload-images.jianshu.io/upload_images/1540531-0a2caa3c9cc8bed8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 346 | 347 | A.append(B) 将B插入到A的内部后面(之后的串联操作,操作A) 348 | 349 | <A> 350 | 351 | .... 352 | 353 | <B></A>。。。 465 | 466 | ![](http://upload-images.jianshu.io/upload_images/1540531-29792897bab796fe.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 467 | 468 | 469 | A.unwrap() ,将A的父元素删除,自己留着 -------------------------------------------------------------------------------- /Struts2/Struts2day02.md: -------------------------------------------------------------------------------- 1 | # 一、分文件编写框架配置文件 2 | 3 | ## 1、不分文件开发可能产生的问题 4 | 5 | 就类似于我们在写java类时,所有代码都写在一个类里,甚至写在一个方法里。 6 | 7 | ![](http://ww1.sinaimg.cn/large/005QU73Qly1fietucmd7tj30it0bajsw.jpg) 8 | 9 | ![](http://ww1.sinaimg.cn/large/005QU73Qly1fietv2lfjhj30a508vmxo.jpg) 10 | 11 | 当3个人都checkout了struts.xml文件时,第一个人提交了,后面的人在没有更新就提交时,第一个人写的可能就白写了。 12 | 13 | ## 2、分文件编写Struts2的配置文件 14 | 15 | ![](http://ww1.sinaimg.cn/large/005QU73Qly1fietvhste4j30i20nu0v2.jpg) 16 | 17 | 18 | # 二、封装请求正文到对象中(非常重要) 19 | 20 | ## 1、静态参数封装 21 | 22 | 在struts.xml配置文件中,给动作类注入值。调用的是setter方法。 23 | 24 | ![](http://ww1.sinaimg.cn/large/005QU73Qly1fietxqny5rj30sz0qdwia.jpg) 25 | 26 | 原因:是由一个staticParams的拦截器完成注入的。 27 | 28 | ![](http://ww1.sinaimg.cn/large/005QU73Qly1fietyfob0xj30pv0jlgp6.jpg) 29 | 30 | ![](http://upload-images.jianshu.io/upload_images/1540531-d56359fa67e1d5ef.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 31 | 32 | ## 2、动态参数封装:开发时用到的 33 | 34 | 通过用户的表单封装请求正文参数。 35 | 36 | ### 2.1、动作类作为实体模型 37 | 38 | ​ 实体模型:Entity,对应数据库中表的记录(注意类对应的是表结构,而对象对应的是一条记录) 39 | 40 | 41 | 42 | ![](http://upload-images.jianshu.io/upload_images/1540531-7d04942e87845bf7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 43 | 44 | ![](http://upload-images.jianshu.io/upload_images/1540531-3708f6bc80925b01.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 45 | 46 | 原因:是由params拦截器完成的。 47 | 48 | ### 2.2、动作类和实体模型分开 49 | 50 | ![](http://upload-images.jianshu.io/upload_images/1540531-62290362c637f729.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 51 | 52 | 问题: 53 | 54 | ​ 由于我们没有初始化user对象,默认为null,一调用setUser方法,就空指针异常了。但是框架却封装进去值了。 55 | 56 | 原因: 57 | 58 | ​ 通过执行过程: 59 | 60 | ![](http://upload-images.jianshu.io/upload_images/1540531-76b4203f4e3aea41.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 61 | 62 | ![](http://upload-images.jianshu.io/upload_images/1540531-e7f76d75ad1af44f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 63 | 64 | ### 2.3、模型驱动:建立动作类和模型分开的前提下(开发中采用的方式) 65 | 66 | 此处的学习目标:目前先记住怎么写,要想理解,必须等讲完OGNL表达式之后。 67 | 68 | ![](http://upload-images.jianshu.io/upload_images/1540531-37dc2981a69d01de.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 69 | 70 | 原因:是由一个modelDriven拦截器做的。 71 | 72 | # 三、用户注册案例(重点) 73 | 74 | ## 1、数据建模(实体模型和数据库) 75 | 76 | ![](http://upload-images.jianshu.io/upload_images/1540531-5896185c303a9825.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 77 | 78 | ## 2、建立业务层接口 79 | 80 | ![](http://upload-images.jianshu.io/upload_images/1540531-77309fc0ddfde1ab.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 81 | 82 | ## 3、建立持久层接口 83 | 84 | ![](http://upload-images.jianshu.io/upload_images/1540531-ded99cd4f92652b5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 85 | 86 | ## 4、数据源工具类 87 | 88 | ![](http://upload-images.jianshu.io/upload_images/1540531-4bde23ea60ff3335.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 89 | 90 | ![](http://upload-images.jianshu.io/upload_images/1540531-8475328fd7bb9099.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 91 | 92 | ## 5、表现层使用Struts2框架实现 93 | 94 | ### 5.1、动作类: 95 | 96 | ![](http://upload-images.jianshu.io/upload_images/1540531-6d69cf45ae48c375.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 97 | 98 | ### 5.2、配置文件 99 | 100 | ![](http://upload-images.jianshu.io/upload_images/1540531-6effecc8bc38a50d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 101 | 102 | ### 5.3、注册界面和结果视图 103 | 104 | 注册界面: 105 | 106 | ![](http://upload-images.jianshu.io/upload_images/1540531-6c1ddf9e9948b268.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 107 | 108 | 结果视图: 109 | 110 | ![](http://upload-images.jianshu.io/upload_images/1540531-539ed9da29a1341b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 111 | 112 | # 四、数据类型的转换(明白原理,实际开发中几乎不用) 113 | 114 | ## 1、开发中的情况: 115 | 116 | 实际开发中用户通过浏览器输入的数据都是String或者String[]。 117 | 118 | ​ String/String[]————>填充模型(set方法)————>POJO(plain old java object) pojo中有java的数据类型。 119 | 120 | ​ POJO————————>获取(get方法)————>页面展示:String 121 | 122 | 123 | ## 2、类型转换情况 124 | 125 | ​ 写数据:(增,删,改)都是String或String[]数组转换为其他类型。 126 | 127 | ​ 读数据:(查)其他类型转换为String。 128 | 129 | 130 | ## 3、Struts2提供的常用类型转换 131 | 132 | ​ a.基本数据类型自动转换。 133 | 134 | ​ b.日期类型:默认按照本地日期格式转换(yyyy-MM-dd)。 135 | 136 | ​ c.字符串数组:默认用逗号+空格,连接成一个字符串。 137 | 138 | 139 | ## 4、自定义类型转换器(知道) 140 | 141 | 示例:把日期格式按照 MM/dd/yyyy的格式转换 142 | 143 | ### 4.1、Struts2中的类型转换器结构: 144 | 145 | ![](http://upload-images.jianshu.io/upload_images/1540531-91568276114f3ace.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 146 | 147 | ![](http://upload-images.jianshu.io/upload_images/1540531-308884364935606c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 148 | 149 | ![](http://upload-images.jianshu.io/upload_images/1540531-0e7c6f169f22de0a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 150 | 151 | ![](http://upload-images.jianshu.io/upload_images/1540531-c2c9c304aeb0b84f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 152 | 153 | ### 4.2、编写类型转换器(编写一个类继承StrutsTypeConverter,实现抽象方法) 154 | 155 | ![](http://upload-images.jianshu.io/upload_images/1540531-262c535cd984a350.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 156 | 157 | ### 4.3、注册类型转换器 158 | 159 | ​ 局部类型转换器:只能指定javabean中的属性用 160 | 161 | 按照属性来注册。在属性所属的javabean的包下建立一个.properties文件。文件名称:javabean名称-conversion.properties 162 | 163 | ![](http://upload-images.jianshu.io/upload_images/1540531-83b6a0a7759b8d55.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 164 | 165 | ![](http://upload-images.jianshu.io/upload_images/1540531-cbacfde85602f2ae.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 166 | 167 | ​ 全局类型转换器:(推荐) 168 | 169 | 按照要转换的数据类型来注册。 170 | 171 | at the top op classpath,建立一个固定名称xwork-conversion.properties的属性文件。 172 | 173 | ![](http://upload-images.jianshu.io/upload_images/1540531-0daa41f1f638a92d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 174 | 175 | ![](http://upload-images.jianshu.io/upload_images/1540531-1ae3e21e76f51e52.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 176 | 177 | ## 5、转换失败后的处理(需要掌握) 178 | 179 | 当转换失败后,页面提示: 180 | 181 | ![](http://upload-images.jianshu.io/upload_images/1540531-bc715458b896cb80.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 182 | 183 | 解决办法:配置回显结果视图 184 | 185 | ![](http://upload-images.jianshu.io/upload_images/1540531-a49632c169a6bea7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 186 | 187 | ​ 问题: 188 | 189 | ​ 配置了回显视图后,当转换失败时,可以回到请求页面,但是表单数据都没了? 190 | 191 | ![](http://upload-images.jianshu.io/upload_images/1540531-5e5d940a6d31259a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 192 | 193 | ![](http://upload-images.jianshu.io/upload_images/1540531-da96b9495fa45004.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 194 | 195 | 显示错误提示:借助Struts2的标签库。 196 | 197 | ![](http://upload-images.jianshu.io/upload_images/1540531-3270e959b3da7f19.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 198 | 199 | 回显数据:使用struts2的标签库生成表单。(建议使用) 200 | 201 | ![](http://upload-images.jianshu.io/upload_images/1540531-39c150105692b2ea.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 202 | 203 | ![](http://upload-images.jianshu.io/upload_images/1540531-765f18362a37a8f0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 204 | 205 | 错误信息中文提示:使用的是struts2的国际化。 206 | 207 | ![](http://upload-images.jianshu.io/upload_images/1540531-f998076ff7c88cdb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 208 | 209 | ![](http://upload-images.jianshu.io/upload_images/1540531-f3fbb5d6c7107ba0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 210 | 211 | ​ 问题: 212 | 213 | ​ 类型转换器当转换失败后,如何进入input视图的? 214 | 215 | ​ 原因: 216 | 217 | ​ 是由一个叫做conversionError的拦截器完成的。 218 | 219 | ​ 注意: 220 | 221 | ​ 要想使用类型转换中的错误处理,在定义Action时必须继承ActionSupport 222 | 223 | 224 | # 五、数据验证 225 | 226 | **用户的输入验证,必须做,且工作量巨大。** 227 | 228 | ## 1、验证的方式 229 | 230 | 客户端验证:javascript 231 | 232 | 服务端验证:逻辑验证(我们的代码) 233 | 234 | 注意:如果客户端和服务端二选一的话,服务器端的不能省。 235 | 236 | 实际开发中:客户端+服务端 237 | 238 | 239 | ## 2、Struts2的服务端验证 240 | 241 | ### 2.1、编程式验证 242 | 243 | 前提 244 | 245 | 246 | 动作类必须继承ActionSupport 247 | 248 | 在代码中编写验证规则。 249 | 250 | ​ a、针对动作类中的所有动作方法进行验证: 251 | 252 | ​ 在动作类中覆盖public void validate()方法。 253 | 254 | ![](http://upload-images.jianshu.io/upload_images/1540531-f0ceba34723a2693.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 255 | 256 | ![](http://upload-images.jianshu.io/upload_images/1540531-978fd6af6d30d461.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 257 | 258 | ![](http://upload-images.jianshu.io/upload_images/1540531-bc960c499ff2cd5d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 259 | 260 | 但是当我们再写一个动作方法时: 261 | 262 | ![](http://upload-images.jianshu.io/upload_images/1540531-6deb3d51b942b7b6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 263 | 264 | ![](http://upload-images.jianshu.io/upload_images/1540531-105113e48bc2ab8a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 265 | 266 | ![](http://upload-images.jianshu.io/upload_images/1540531-cb5653b895554de0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 267 | 268 | ![](http://upload-images.jianshu.io/upload_images/1540531-3855b5dcdc483d52.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 269 | 270 | 由此可知,该验证方法会对动作类中的所有动作方法进行验证。 271 | 272 | ​ b、针对动作类中的某个动作方法进行验证 273 | 274 | ​ 针对上面的问题,解决办法1:给不需要验证的动作方法添加一个@SkipValidation注解。 275 | 276 | ![](http://upload-images.jianshu.io/upload_images/1540531-3b07f1086d251805.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 277 | 278 | 279 | 280 | ![](http://upload-images.jianshu.io/upload_images/1540531-22ce9add33bfff9c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 281 | 282 | 解决办法2:validation方法遵守书写规范。 283 | 284 | ![](http://upload-images.jianshu.io/upload_images/1540531-3f96e83e5e9cae98.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 285 | 286 | ![](http://upload-images.jianshu.io/upload_images/1540531-7c7b5717028b52d8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 287 | 288 | 解决办法1和解决办法2的使用时机:需要验证的动作方法少,用解决办法2。需要验证的方法多,用解决方式1。(简单一点:挑少的写) 289 | 290 | 所有编程式验证的弊端:硬编码。 291 | 292 | 293 | ### 2.2、声明式验证(推荐) 294 | 295 | 通过编写验证规则的xml文件。需要验证时,编写xml文件,不要验证,就不写。 296 | 297 | 298 | 优势:解决了2.1编程式验证的弊端 299 | 300 | ​ a、针对动作类中的所有动作进行验证:在动作类所在的包中,建立一个 **ActionClassName-validation.xml** 的文件,内容如下: 301 | 302 | ![](http://upload-images.jianshu.io/upload_images/1540531-573a42aedc0d8c86.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 303 | 304 | 注意:它是针对动作类中的所有动作方法。 305 | 306 | ![](http://upload-images.jianshu.io/upload_images/1540531-4a52b96318f17d62.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 307 | 308 | ![](http://upload-images.jianshu.io/upload_images/1540531-a7bb1ca286b564ba.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 309 | 310 | ​ b、针对动作类中的某个动作进行验证:在动作类所在的包中建立一个xml文件,名称为ActionClassName-ActionName-validation.xml 。内容如下: 311 | 312 | ![](http://upload-images.jianshu.io/upload_images/1540531-51e9109a6ec8b55d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 313 | 314 | 它是针对指定动作方法进行验证: 315 | 316 | ![](http://upload-images.jianshu.io/upload_images/1540531-a6db3a2e7d600bc1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 317 | 318 | ![](http://upload-images.jianshu.io/upload_images/1540531-f83b0d0fd140ee92.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 319 | 320 | ### 2.3、Struts2内置的常用声明式验证器 321 | 322 | #### 2.3.1位置: 323 | 324 | xwork-core-2.3.15.3.jar\com\opensymphony\xwork2\validator\validator\default.xml 325 | 326 | ![](http://upload-images.jianshu.io/upload_images/1540531-a24b0d3273c2511c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 327 | 328 | #### 2.3.2、验证器注入参数 329 | 330 | 例如:我们使用requiredstring,默认是去空格,当我们不想去空格时,就可以给验证器注入参数。 331 | 332 | 基于字段的: 333 | 334 | ![](http://upload-images.jianshu.io/upload_images/1540531-893c837297e41dc8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 335 | 336 | 另一种基于验证器的: 337 | 338 | 339 | 340 | ![](http://upload-images.jianshu.io/upload_images/1540531-2219408a3f90ade6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 341 | 342 | ![](http://upload-images.jianshu.io/upload_images/1540531-c653918ec731d1f0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 343 | 344 | 345 | 346 | ## 3、常用验证器示例 347 | 348 | ![](http://upload-images.jianshu.io/upload_images/1540531-d98d8607d1033bba.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 349 | 350 | ![](http://upload-images.jianshu.io/upload_images/1540531-0ede2e995f85d2e8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 351 | 352 | ![](http://upload-images.jianshu.io/upload_images/1540531-8160274eb30929ed.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 353 | 354 | ![](http://upload-images.jianshu.io/upload_images/1540531-276b323d5e2e254d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 355 | 356 | ![](http://upload-images.jianshu.io/upload_images/1540531-713040e2a42db9df.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 357 | 358 | 运行结果: 359 | 360 | ![](http://upload-images.jianshu.io/upload_images/1540531-251adecaf2b8e797.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) -------------------------------------------------------------------------------- /JavaScript/jQuery--day02.md: -------------------------------------------------------------------------------- 1 | # 一、回顾 2 | 3 | - 语法: 4 | 5 | \$("选择器") ,$(dom对象) ,$("<div>") 6 | 7 | - 选择器: 8 | 9 | 基本:#id、element、.class、s1,s2,... 、\* 10 | 11 | 层级:A B、A>B、A+B、A~B 12 | 13 | 基本过滤::first :last :eq() :gt() :lt() :even :odd :header :animated :focus 14 | 15 | 内容过滤::contains() :empty :parent :has() 16 | 17 | 可见过滤::visible :hidden 18 | 19 | 属性:[attr] [attr=val] [attr!=val] [attr^=val] [attr$=val] [attr\*=val] [attr=val][][] 20 | 21 | 子元素::nth-child() :first-child :last-child :only-child 22 | 23 | 表单过滤::input :text :password :radio :checkbox :file :submit :reset :image :button :hidden 24 | 25 | 表单对象属性过滤::enabled :disabled :checked :selected 26 | 27 | - 属性和CSS 28 | 29 | attr() 、removeAttr() 30 | 31 | addClass() removeClass() toggleClass() 32 | 33 | val() html() text() 34 | 35 | css() 36 | 37 | offset() --> {top , left} 38 | 39 | scrollTop() /scrollLeft() 40 | 41 | width() height() 42 | 43 | - 文档处理 44 | 45 | 内部:append prepend appendTo prependTo 46 | 47 | 外部:after before insertAfter insertBefore 48 | 49 | 删除:empty remove detach --> data() 50 | 51 | 复制:clone(true) 52 | 53 | 替换:replaceWith replaceAll 54 | 55 | 包裹:wrap wrapAll wrapInner unWrap() 56 | 57 | # 二、筛选 58 | 59 | - 选择器可以完成功能,筛选提供相同函数。 60 | 61 | 选择器 :first 62 | 63 | 筛选 first() 64 | 65 | - 对比: 66 | 67 | $("div:first") 直接获得第一个div (永远只能操作第一个) 68 | 69 | $("div").first() 先获得所有的div,从所有的中筛选出第一个。(可以操作第一个,也可以操作所有) 70 | 71 | ## 2.1过滤 72 | 73 | ![](http://upload-images.jianshu.io/upload_images/1540531-5b66fc71224b7d1b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 74 | 75 | eq(index | -index) 类型:eq() 76 | 77 | index:正数,从头开始获得指定索引的元素。这个元素的位置是从0算起。0表示第一个 78 | 79 | -index:负数,从尾开始获得指定索引的元素。1算起。-1表示最后一个 80 | 81 | first() 第一个 :first 82 | 83 | last() 最后一个 :last 84 | 85 | is() 判断 86 | 87 | hasClass() 判断是否是指定class 。<xxx class="my"> 88 | 89 | 这其实就是is("." + class)。 90 | 91 | filter() 筛选出与指定表达式匹配的元素集合 92 | 93 | not() 将指定内容删除 94 | 95 | has() 子元素是否有 96 | 97 | slice(start , end) 截取元素,[2,4) --> 2,3 98 | 99 | map() jQuery对象拆分成 jQuery对象数组 100 | 101 | ## 2.2查找 102 | 103 | ![](http://upload-images.jianshu.io/upload_images/1540531-d27b77d8b01f096a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 104 | 105 | <A> 106 | 107 | <B> 108 | 109 | <C>标签查看: 121 | 122 | ![](http://upload-images.jianshu.io/upload_images/1540531-6dc2d208fb94a150.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 123 | 124 | ​ c、findValue:我们在Jsp上调用的都是findValue 125 | 126 | ![](http://upload-images.jianshu.io/upload_images/1540531-619c54cca5844831.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 127 | 128 | ![](http://upload-images.jianshu.io/upload_images/1540531-c6113bb9832aecd1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 129 | 130 | # 二、Struts2对EL的改变 131 | 132 | ## 1、Struts2中使用EL的问题: 133 | 134 | **前提:** 135 | 136 | 我们应该知道,如果我们没有往值栈(根)中放入数据的话,那么我们的动作类默认是在值栈的栈顶。 137 | 138 | ![](http://upload-images.jianshu.io/upload_images/1540531-9fe0c209b59af591.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 139 | 140 | ![](http://upload-images.jianshu.io/upload_images/1540531-1e42dd1d147324e3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 141 | 142 | 问题: 143 | 144 | 我们放到请求域中的属性,使用EL表达式取出来了。但是放到应用域中的属性,使用EL表达式没取出来。 145 | 146 | 147 | ## 2、关于EL问题的分析: 148 | 149 | 分析: 150 | 151 | 152 | 我们知道EL表达式是从四大域对象中依次查找属性。搜索范围是由小到大。page Scope————>request Scope————>sessionScope————>application Scope 153 | 154 | 但是通过测试发现,搜索完request范围后就没有继续搜索,而是返回了ValueStack中栈顶对象name属性的值。 155 | 156 | ![](http://upload-images.jianshu.io/upload_images/1540531-cdd4a157060186ec.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 157 | 158 | ![](http://upload-images.jianshu.io/upload_images/1540531-de3cfaa7eb039e2a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 159 | 160 | ## 3、Struts2中EL查找顺序改变总结: 161 | 162 | EL表达式: page Scope————>request Scope————>sessionScope————>application Scope 163 | 164 | OGNL表达式:page Scope————>request Scope————> valueStack(根中)————>contextMap ————>sessionScope————>application Scope 165 | 166 | ## 4、OGNL的特殊说明: 167 | 168 | ![](http://upload-images.jianshu.io/upload_images/1540531-7194d87ac9081fdb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 169 | 170 | ![](http://upload-images.jianshu.io/upload_images/1540531-0325983a1c054f1a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 171 | 172 | 注意:以下内容知道即可。 173 | 174 | ![](http://upload-images.jianshu.io/upload_images/1540531-cf4a6346c7ef2b2c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 175 | 176 | # 三、OGNL配合通用标签的其他使用 177 | 178 | ## 1、iterator标签(很重要) 179 | 180 | ![](http://upload-images.jianshu.io/upload_images/1540531-c48a56c726e505df.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 181 | 182 | ![](http://upload-images.jianshu.io/upload_images/1540531-80105c22fd38a263.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 183 | 184 | ![](http://upload-images.jianshu.io/upload_images/1540531-a18eddec92a65c3a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 185 | 186 | ## 2、OGNL投影(了解) 187 | 188 | ### 2.1、使用过滤条件投影 189 | 190 | ![](http://upload-images.jianshu.io/upload_images/1540531-f83a664bb86c4f8b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 191 | 192 | ### 2.2、投影指定属性 193 | 194 | ![](http://upload-images.jianshu.io/upload_images/1540531-dc219a5d085256f6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 195 | 196 | ## 3、Struts2中#,$,%符号的使用(重要) 197 | 198 | ### 3.1、# 199 | 200 | ​ a、取contextMap中key时使用,例如 201 | 202 | ​ b、OGNL中创建Map对象时使用,例如: 203 | 204 | 205 | ### 3.2、$ 206 | 207 | a、在JSP中使用EL表达式时使用,例如${name} 208 | 209 | ​ b、在xml配置文件中,编写OGNL表达式时使用,例如文件下载时,文件名编码。 210 | 211 | ​ struts.xml——>${@java.net.URLEncoder.encode(filename)} 212 | 213 | 214 | ### 3.3、% 215 | 216 | 在struts2中,有些标签的value属性取值就是一个OGNL表达式,例如 217 | 218 | ​ 还有一部分标签,value属性的取值就是普通字 符串,例如,如果想把一个普通的字符串强制看成时OGNL,就需要使用%{}把字符串套起来。 219 | 220 | 例如<s:textfield value="%{username}"/>。当然在<s:property value="%{OGNL Expression}" />也可以使用,但不会这么用。 221 | 222 | 223 | ## 4、其他标签 224 | 225 | ### 4.1、set标签 226 | 227 | ![](http://upload-images.jianshu.io/upload_images/1540531-03034499be3263c0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 228 | 229 | ![](http://upload-images.jianshu.io/upload_images/1540531-ef559c3b99b8c9b0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 230 | 231 | ### 4.2、action标签 232 | 233 | ![](http://upload-images.jianshu.io/upload_images/1540531-47d70a673e55d1f7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 234 | 235 | ![](http://upload-images.jianshu.io/upload_images/1540531-2e9bb2fc8e79fa96.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 236 | 237 | ### 4.3、if标签,elseif标签 else标签 238 | 239 | ![](http://upload-images.jianshu.io/upload_images/1540531-a6a78219d8ced7d2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 240 | 241 | ![](http://upload-images.jianshu.io/upload_images/1540531-23b2e6326e869ebd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 242 | 243 | ### 4.4、url和a标签(很有用) 244 | 245 | ![](http://upload-images.jianshu.io/upload_images/1540531-4644575ff47c4915.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 246 | 247 | 248 | # 四、Struts2的UI标签和主题 249 | 250 | ## 1、Struts2中UI标签的优势 251 | 252 | 自动的数据回显和错误提示功能 253 | 254 | 自带的简单样式和排版 255 | 256 | 257 | ## 2、表单标签的通用属性 258 | 259 | 说明:UI标签中value的取值一般都是字符串。 260 | 261 | ### 2.1、UI标签的通用属性 262 | 263 | ![](http://upload-images.jianshu.io/upload_images/1540531-bf3eb258bdeb1448.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 264 | 265 | ### 2.2、关于checkboxlist的使用: 266 | 267 | ![](http://upload-images.jianshu.io/upload_images/1540531-0ae421ca26a4243a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 268 | 269 | ![](http://upload-images.jianshu.io/upload_images/1540531-3f6c7684c2f923b5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 270 | 271 | ![](http://upload-images.jianshu.io/upload_images/1540531-2c53f79fb86ff97c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 272 | 273 | ![](http://upload-images.jianshu.io/upload_images/1540531-66d0d22185d14cc8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 274 | 275 | ### 2.3、UI标签的小案例以及模型驱动的分析 276 | 277 | ![](http://upload-images.jianshu.io/upload_images/1540531-e04a942507d28523.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 278 | 279 | ![](http://upload-images.jianshu.io/upload_images/1540531-cedb752ed23b09e9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 280 | 281 | ![](http://upload-images.jianshu.io/upload_images/1540531-c1f07c9fd2dad6db.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 282 | 283 | ## 3、UI标签的模板(主题) 284 | 285 | ### 3.1、struts2中默认主题 286 | 287 | 默认主题 的名称是XHTML,都是在struts的默认属性文件中定义着:default.properties 288 | 289 | ![](http://upload-images.jianshu.io/upload_images/1540531-f4fdc48f396e1e25.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 290 | 291 | ![](http://upload-images.jianshu.io/upload_images/1540531-d32cf381f03b4019.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 292 | 293 | ![](http://upload-images.jianshu.io/upload_images/1540531-e582ece52cd6e6b4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 294 | 295 | ### 3.2、更改默认主题 296 | 297 | ​ a、更改表单某个元素的默认主题:使用的是表单元素的theme属性。 298 | 299 | ![](http://upload-images.jianshu.io/upload_images/1540531-c26d60e69f408c7f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 300 | 301 | ​ b、更改表单所有主题:使用的是form标签的theme属性。 302 | 303 | ![](http://upload-images.jianshu.io/upload_images/1540531-a9cd4b93aca7e997.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 304 | 305 | ​ c、更改全站所有表单主题:是在struts.xml配置文件中,覆盖原有主题的设置。 306 | 307 | ![](http://upload-images.jianshu.io/upload_images/1540531-e3c963d991b449f5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 308 | 309 | # 五、防止表单重复提交(拦截器) 310 | 311 | ## 1、回顾之前的解决办法: 312 | 313 | ![](http://upload-images.jianshu.io/upload_images/1540531-fc940ccecf1e2d50.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 314 | 315 | ## 2、Struts2中的解决办法: 316 | 317 | ### 2.1、使用重定向 318 | 319 | ![](http://upload-images.jianshu.io/upload_images/1540531-5291f098c79b39bf.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 320 | 321 | 遗留的问题:防不住后退,再提交。 322 | 323 | ### 2.2、使用\生成令牌配合token拦截器 324 | 325 | ![](http://upload-images.jianshu.io/upload_images/1540531-648f29c3f34ee075.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 326 | 327 | ![](http://upload-images.jianshu.io/upload_images/1540531-aebecb838603112f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 328 | 329 | 点击后退的时候,会提示: 330 | 331 | ![](http://upload-images.jianshu.io/upload_images/1540531-758aaf26bea4562d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 332 | 333 | 配置结果视图: 334 | 335 | ![](http://upload-images.jianshu.io/upload_images/1540531-066156ce33f02b16.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 336 | 337 | 遗留的问题:此种解决方式,是产生了错误之后再告知用户,你错了。 338 | 339 | ### 2.3、使用\生成令牌配合tokensession拦截器 340 | 341 | ![](http://upload-images.jianshu.io/upload_images/1540531-22858903ea056309.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) -------------------------------------------------------------------------------- /Hibernate/Hibernate--day04.md: -------------------------------------------------------------------------------- 1 | # 一、整合log4j(了解) 2 | 3 | - slf4j 核心jar :slf4j-api-1.6.1.jar 。slf4j是日志框架,将其他优秀的日志第三方进行整合。 4 | 5 | ![](http://upload-images.jianshu.io/upload_images/1540531-6cf6b204edb1a043.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 6 | 7 | - 整合导入jar包 8 | 9 | log4j 核心包:log4j-1.2.17.jar 10 | 11 | 过渡jar(整合jar):slf4j-log4j12-1.7.5.jar 12 | 13 | - 导入配置文件 14 | 15 | log4j.properties ,此配置文件通知log4j 如何输出日志 16 | 17 | - 配置文件内容: 18 | 19 | 1.记录器 20 | 21 | 2.输出源 22 | 23 | 3.布局 24 | 25 | - 记录器 26 | 27 | 例如:log4j.rootLogger=info, stdout,file 28 | 29 | 格式:log4j.rootLogger=日志级别, 输出源1,输出源2,。。。。 30 | 31 | log4j 日志级别:fatal 致命错误error 错误warn 警告info 信息debug 调试信息trace 堆栈信息(由高到底顺序) 32 | 33 | - 输出源: 34 | 35 | 例如:log4j.appender.file=org.apache.log4j.FileAppender 36 | 37 | 格式:log4j.appender.输出源的名称=输出源的实现类 38 | 39 | 名称:自定义 40 | 41 | 实现类:log4j提供 42 | 43 | 输出源属性例如:log4j.appender.file.File=d\:mylog.log 44 | 45 | 输出源属性格式:log4j.appender.名称.属性=值 46 | 47 | 每一个输出源对应一个实现类,实现类都属性(setter),底层执行setter方法进行赋值 48 | 49 | - 常见的输出源实现类 50 | 51 | org.apache.log4j.FileAppender 输出文件中 52 | 53 | file ,表示文件输出位置 54 | 55 | org.apache.log4j.ConsoleAppender 输出到控制台 56 | 57 | Target ,表示使用哪种输出方式,在控制台打印内容,取值:System.out / System.err 58 | 59 | - 布局 -- 确定输出格式 60 | 61 | 例如:log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 62 | 63 | 格式:log4j.appender.数据源.layout=org.apache.log4j.PatternLayout 64 | 65 | 布局属性:log4j.appender. 数据源.layout.ConversionPattern=值 66 | 67 | 12:56:30,123 info 68 | 69 | - 扩展:对指定的目录设置日志级别 70 | 71 | 例如:log4j.logger.org.hibernate.transaction=debug 72 | 73 | 格式:log4j.logger.包结构=级别 74 | 75 | # 二、一对一(了解) 76 | 77 | - .情况1:主表的主键,与从表的外键(唯一),形成主外键关系 78 | - .情况2:主表的主键,与从表的主键,形成主外键关系(从表的主键又是外键) 79 | 80 | ### 2.0.1情况1 81 | 82 | ​ ![](http://upload-images.jianshu.io/upload_images/1540531-e8ed17e69c213331.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 83 | 84 | ![](http://upload-images.jianshu.io/upload_images/1540531-4e653b4f6d4edfc5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 85 | 86 | ### 2.0.2情况2 87 | 88 | ![](http://upload-images.jianshu.io/upload_images/1540531-7c0472e1281e8119.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 89 | 90 | ![](http://upload-images.jianshu.io/upload_images/1540531-e5470f7b353f68ff.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 91 | 92 | # 三、二级缓存【掌握】 93 | 94 | ## 3.1介绍 95 | 96 | ### 3.1.1缓存 97 | 98 | 缓存(Cache): 计算机领域非常通用的概念。它介于 **应用程序** 和 **永久性数据存储源** (如硬盘上的文件或者数据库)之间,其作用是降低应用程序直接读写硬盘(永久性数据存储源)的频率,从而提高应用的运行 **性能** 。缓存中的数据是数据存储源中数据的拷贝。缓存的物理介质通常是 **内存** 99 | 100 | 缓存:程序<--(内存)-->硬盘 101 | 102 | ### 3.1.2什么是二级缓存 103 | 104 | - hibernate 提供缓存机制:一级缓存、二级缓存 105 | 106 | 一级缓存:session级别缓存,在一次请求中共享数据。 107 | 108 | 二级缓存:sessionFactory级别缓存,整个应用程序共享一个会话工厂,共享一个二级缓存。 109 | 110 | - SessionFactory的缓存两部分: 内置缓存:使用一个Map,用于存放配置信息,预定义HQL语句等,提供给Hibernate框架自己使用,对外只读的。不能操作。 111 | 112 | 外置缓存:使用另一个Map,用于存放用户自定义数据。默认不开启。外置缓存hibernate只提供规范(接口),需要第三方实现类。外置缓存有成为二级缓存。 113 | 114 | ### 3.1.3二级缓存内部结构 115 | 116 | ![](http://upload-images.jianshu.io/upload_images/1540531-16e18ea51c709b62.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 117 | 118 | - 二级就是由4部分构成 119 | - 类级别缓存 120 | - 集合级别缓存 121 | - 时间戳缓存 122 | - 查询缓存(二级缓存的第2大部分,三级缓存) 123 | 124 | ### 3.1.4并发访问策略 125 | 126 | ![](http://upload-images.jianshu.io/upload_images/1540531-536e2adefbe2ce48.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 127 | 128 | - 访问策略:读写型(read-write)、只读型(read-only) 129 | 130 | ### 3.1.5应用场景 131 | 132 | - 适合放入二级缓存中的数据: 133 | 134 | 很少被修改 135 | 136 | 不是很重要的数据, 允许出现偶尔的并发问题 137 | 138 | - 不适合放入二级缓存中的数据: 139 | 140 | 经常被修改 141 | 142 | 财务数据, 绝对不允许出现并发问题 143 | 144 | 与其他应用数据共享的数据 145 | 146 | ### 3.1.6二级缓存提供商 147 | 148 | - **EHCache** : 可作为进程(单机)范围内的缓存, 存放数据的物理介质可以是内存或硬盘, 对Hibernate 的查询缓存提供了支持。--支持集群。 149 | - OpenSymphony `:可作为进程范围内的缓存, 存放数据的物理介质可以是内存或硬盘, 提供了丰富的缓存数据过期策略, 对Hibernate 的查询缓存提供了支持 150 | - SwarmCache: 可作为集群范围内的缓存, 但不支持Hibernate 的查询缓存 151 | - JBossCache:可作为集群范围内的缓存, 支持Hibernate 的查询缓存 152 | 153 | ![](http://upload-images.jianshu.io/upload_images/1540531-d8b3a1723aa2f634.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 154 | 155 | X表示支持 156 | 157 | ## 3.2配置(操作) 158 | 159 | 1.导入jar包:ehcache-1.5.0.jar/ commons-logging.jar/ backport-util-concurrent.jar 160 | 161 | 2.开启二级缓存(我要使用二级缓存) 162 | 163 | 3.确定二级缓存提供商(我要使用哪个二级缓存) 164 | 165 | 4.确定需要缓存内容 166 | 167 | ​ 1>配置需要缓存的类 168 | 169 | 2>配置需要缓存的集合 170 | 171 | 5.配置ehcache自定义配置文件 172 | 173 | 174 | 175 | ### 3.2.1导入jar包 176 | 177 | ![](http://upload-images.jianshu.io/upload_images/1540531-847c6fe9ceee327f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 178 | 179 | ### 3.2.2开启二级缓存 180 | 181 | ![](http://upload-images.jianshu.io/upload_images/1540531-1a5f261a8cadc1ff.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 182 | 183 | - 在hibernate.cfg.xml 配置二级缓存 184 | 185 | ```xml 186 | 187 | true 188 | ``` 189 | 190 | ### 3.2.3确定提供商 191 | 192 | ![](http://upload-images.jianshu.io/upload_images/1540531-f18347ba24b4ef2a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 193 | 194 | - hibernate.cfg.xml 配置 195 | 196 | ```xml 197 | 198 | org.hibernate.cache.EhCacheProvider 199 | ``` 200 | 201 | ### 3.2.4确定缓存内容 202 | 203 | - 在hibernate.cfg.xml 确定类缓存和集合缓存配置项 204 | 205 | ![](http://upload-images.jianshu.io/upload_images/1540531-b73041cbd3b7ea6c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 206 | 207 | - 配置 208 | 209 | ```xml 210 | 211 | 212 | 213 | 214 | 215 | 216 | ``` 217 | 218 | ### 3.2.5ehcache配置文件 219 | 220 | 步骤1:从jar包复制xml文件 221 | 222 | ![](http://upload-images.jianshu.io/upload_images/1540531-507f7cdbf5a30cba.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 223 | 224 | 225 | 步骤2:将xml重命名"ehcache.xml" 226 | 227 | ![](http://upload-images.jianshu.io/upload_images/1540531-749e059ec406f6c7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 228 | 229 | 230 | 步骤3:将修改后的xml,拷贝到src下 231 | 232 | ![](http://upload-images.jianshu.io/upload_images/1540531-968ad12b4a0a82f6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 233 | 234 | 235 | ## 3.3演示 236 | 237 | ### 3.3.1证明 238 | 239 | ```java 240 | @Test 241 | public void demo01(){ 242 | //1 证明二级缓存存在 243 | // * 修改toString() 244 | // * 如果二级缓存开启,查询3 没有select语句,表示从二级缓存获得的。 245 | // * 将二级缓存关闭,查询3将触发select语句。 246 | Session s1 = factory.openSession(); 247 | s1.beginTransaction(); 248 | 249 | //1 查询id=1 -- 执行select (查询后,将数据存放在一级缓存,之后由一级缓存同步到二级缓存) 250 | Customer c1 = (Customer) s1.get(Customer.class, 1); 251 | System.out.println(c1); 252 | //2 查询id=1 --从一级缓存获取 253 | Customer c2 = (Customer) s1.get(Customer.class, 1); 254 | System.out.println(c2); 255 | 256 | s1.getTransaction().commit(); 257 | s1.close(); 258 | 259 | System.out.println("----------"); 260 | 261 | Session s2 = factory.openSession(); 262 | s2.beginTransaction(); 263 | 264 | //3 查询id=1 -- 从二级缓存获取 265 | Customer c3 = (Customer) s2.get(Customer.class, 1); 266 | System.out.println(c3); 267 | 268 | s2.getTransaction().commit(); 269 | s2.close(); 270 | } 271 | 272 | ``` 273 | 274 | 275 | 276 | ### 3.3.2类缓存 277 | 278 | - 类缓存:只存放数据 279 | - 一级缓存:存放对象本身 280 | 281 | ![](http://upload-images.jianshu.io/upload_images/1540531-7eb26e9e4545189c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 282 | 283 | ```java 284 | @Test 285 | public void demo02(){ 286 | //2 类缓存:只存放数据,散装数据。 287 | // * 使用默认的toString(); 288 | Session s1 = factory.openSession(); 289 | s1.beginTransaction(); 290 | 291 | //1 查询id=1 -- 执行select 292 | Customer c1 = (Customer) s1.get(Customer.class, 1); 293 | System.out.println(c1); 294 | //2 查询id=1 -- 从一级缓存获取,一级缓存存放对象本身 295 | Customer c2 = (Customer) s1.get(Customer.class, 1); 296 | System.out.println(c2); 297 | 298 | s1.getTransaction().commit(); 299 | s1.close(); 300 | 301 | System.out.println("----------"); 302 | 303 | Session s2 = factory.openSession(); 304 | s2.beginTransaction(); 305 | 306 | //3 查询id=1 -- 对象不一样,数据一样 307 | Customer c3 = (Customer) s2.get(Customer.class, 1); 308 | System.out.println(c3); 309 | 310 | s2.getTransaction().commit(); 311 | s2.close(); 312 | } 313 | 314 | ``` 315 | 316 | 317 | 318 | ### 3.3.3集合缓存 319 | 320 | ![](http://upload-images.jianshu.io/upload_images/1540531-23d1d6909ef19aa7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 321 | 322 | ![](http://upload-images.jianshu.io/upload_images/1540531-e6cc1decd370f386.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 323 | 324 | ```java 325 | @Test 326 | public void demo03(){ 327 | //3 集合缓存:只存放关联对象OID的值,如果需要数据,从类缓存中获取。 328 | // * 3.1 默认:第一条select 查询客户,第二天 select 查询客户所有订单 329 | // * 3.2 操作:在hibernate.cfg.xml 将 Order 类缓存删除 330 | // *** 331 | // *** 多了10条select,通过订单的id查询订单 332 | Session s1 = factory.openSession(); 333 | s1.beginTransaction(); 334 | 335 | //1 查询id=1 336 | Customer c1 = (Customer) s1.get(Customer.class, 1); 337 | System.out.println(c1); 338 | //2 获得订单 339 | for (Order o1 : c1.getOrderSet()) { 340 | System.out.println(o1); 341 | } 342 | 343 | 344 | s1.getTransaction().commit(); 345 | s1.close(); 346 | 347 | System.out.println("----------"); 348 | 349 | Session s2 = factory.openSession(); 350 | s2.beginTransaction(); 351 | 352 | //3 查询id=1 353 | Customer c3 = (Customer) s2.get(Customer.class, 1); 354 | System.out.println(c3); 355 | //4 获得订单 356 | for (Order o2 : c3.getOrderSet()) { 357 | System.out.println(o2); 358 | } 359 | 360 | s2.getTransaction().commit(); 361 | s2.close(); 362 | } 363 | 364 | ``` 365 | 366 | 367 | 368 | ### 3.3.4时间戳 369 | 370 | - 时间戳:任何操作都在时间戳中记录操作时间。 371 | 372 | ![](http://upload-images.jianshu.io/upload_images/1540531-223ebecaef992523.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 373 | 374 | ```java 375 | @Test 376 | public void demo04(){ 377 | //4 时间戳: 所有的操作都会在时间戳中进行记录,如果数据不一致,将触发select语句进行查询 378 | // * 修改toString() 379 | Session s1 = factory.openSession(); 380 | s1.beginTransaction(); 381 | 382 | //1 查询id=1 383 | Integer cid = 1; 384 | Customer c1 = (Customer) s1.get(Customer.class, cid); 385 | System.out.println(c1); 386 | //2 绕过一级和二级缓存,修改数据库,修改客户cname=大东哥 387 | s1.createQuery("update Customer set cname = ? where cid = ?") 388 | .setString(0, "大东哥") 389 | .setInteger(1, cid) 390 | .executeUpdate(); 391 | //3打印 392 | System.out.println(c1); 393 | 394 | s1.getTransaction().commit(); 395 | s1.close(); 396 | 397 | System.out.println("----------"); 398 | 399 | Session s2 = factory.openSession(); 400 | s2.beginTransaction(); 401 | 402 | //4 查询id=1 -- ? 403 | Customer c3 = (Customer) s2.get(Customer.class, 1); 404 | System.out.println(c3); 405 | 406 | s2.getTransaction().commit(); 407 | s2.close(); 408 | } 409 | ``` 410 | 411 | ### 3.3.5查询缓存 412 | 413 | - 查询缓存又称为三级缓存(民间) 414 | - 查询缓存默认不使用。需要手动开启 415 | - 查询缓存:将HQL语句与查询结果进行绑定。通过HQL相同语句可以缓存内容。 416 | 417 | 默认情况Query对象只将查询结果存放在一级和二级缓存,不从一级或二级缓存获取。 418 | 419 | 查询缓存就是让Query可以从二级缓存获得内容。 420 | 421 | 步骤一:开启查询缓存 422 | 423 | ![](http://upload-images.jianshu.io/upload_images/1540531-ed88b8ebff192a85.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 424 | 425 | ```xml 426 | 427 | true 428 | ``` 429 | 430 | 步骤二:在查询query对象,设置缓存内容(注意:存放和查询都需要设置) 431 | 432 | ![](http://upload-images.jianshu.io/upload_images/1540531-ea90d27f9d948cb0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 433 | 434 | ![](http://upload-images.jianshu.io/upload_images/1540531-2e8a44bb686922c1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 435 | 436 | ```java 437 | @Test 438 | public void demo05(){ 439 | //5 查询缓存 440 | Session s1 = factory.openSession(); 441 | s1.beginTransaction(); 442 | 443 | //1 query查询 444 | Query q1 = s1.createQuery("from Customer"); 445 | q1.setCacheable(true); 446 | List a1 = q1.list(); 447 | for (Customer c1 : a1) { 448 | System.out.println(c1); 449 | } 450 | 451 | //2 cid =1 -- 一级缓存获得 452 | Customer customer = (Customer) s1.get(Customer.class, 1); 453 | System.out.println(customer); 454 | 455 | s1.getTransaction().commit(); 456 | s1.close(); 457 | 458 | System.out.println("----------"); 459 | 460 | Session s2 = factory.openSession(); 461 | s2.beginTransaction(); 462 | 463 | //2 cid =1 -- 二级缓存获得 464 | Customer customer2 = (Customer) s2.get(Customer.class, 1); 465 | System.out.println(customer2); 466 | 467 | //3 query查询 468 | Query q2 = s2.createQuery("from Customer"); 469 | q2.setCacheable(true); 470 | List a2 = q2.list(); 471 | for (Customer c2 : a2) { 472 | System.out.println(c2); 473 | } 474 | 475 | s2.getTransaction().commit(); 476 | s2.close(); 477 | } 478 | ``` 479 | 480 | 481 | 482 | ## 3.4ehcache配置文件 483 | 484 | - <diskStore path="java.io.tmpdir"/> 设置临时文件存放位置。(缓存一般内存,一定程度时,写入硬盘。) 485 | 486 | ![](http://upload-images.jianshu.io/upload_images/1540531-cc9a5cf1efe96977.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 487 | 488 | - 缓存详细设置 489 | 490 | <defaultCache> 所有的缓存对象默认的配置 491 | 492 | <cache name="类"> 指定对象单独配置 493 | 494 | - 参数设置 495 | 496 | maxElementsInMemory="10000" 内存最大数 497 | 498 | eternal="false" 是否永久(内存常驻留) 499 | 500 | timeToIdleSeconds="120" 501 | 502 | timeToLiveSeconds="120" 503 | 504 | overflowToDisk="true" 内存满了,是否写入到硬盘 505 | 506 | maxElementsOnDisk="10000000" 硬盘最大数 507 | 508 | diskPersistent="false" 关闭JVM,是否将内存保存硬盘中 509 | 510 | diskExpiryThreadIntervalSeconds="120" 轮询 511 | 512 | memoryStoreEvictionPolicy="LRU" 513 | 514 | Least Recently Used (specified as LRU). 515 | 516 | First In First Out (specified as FIFO) 517 | 518 | Less Frequently Used (specified as LFU) 519 | 520 | ``` 521 | • maxElementsInMemory :设置基于内存的缓存中可存放的对象最大数目 522 | • eternal:设置对象是否为永久的,true表示永不过期,此时将忽略timeToIdleSeconds 和 timeToLiveSeconds属性; 默认值是false 523 | • timeToIdleSeconds:设置对象空闲最长时间,以秒为单位, 超过这个时间,对象过期。当对象过期时,EHCache会把它从缓存中清除。如果此值为0,表示对象可以无限期地处于空闲状态。 524 | • timeToLiveSeconds:设置对象生存最长时间,超过这个时间,对象过期。 525 | 如果此值为0,表示对象可以无限期地存在于缓存中. 该属性值必须大于或等于 timeToIdleSeconds 属性值 526 | • overflowToDisk:设置基于内在的缓存中的对象数目达到上限后,是否把溢出的对象写到基于硬盘的缓存中 527 | • diskPersistent 当jvm结束时是否持久化对象 true false 默认是false 528 | • diskExpiryThreadIntervalSeconds 指定专门用于清除过期对象的监听线程的轮询时间 529 | • memoryStoreEvictionPolicy - 当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。默认是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO(先进先出) 530 | 531 | ``` 532 | 533 | -------------------------------------------------------------------------------- /多线程/多线程.md: -------------------------------------------------------------------------------- 1 | # 多线程 2 | 3 | ## 进程和线程概述 4 | 5 | ### 进程 6 | 7 | 正在执行中的程序,其实是应用程序在内存中运行的那片空间 8 | 9 | ### 线程 10 | 11 | 进程中的一个执行单元,负责进程中的程序的运行,一个进程中至少要有一个线程。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序 12 | 13 | [线程百度百科](https://baike.baidu.com/item/%E7%BA%BF%E7%A8%8B/103101?fr=aladdin) 14 | 15 | ## 应用 16 | 17 | 可以实现多部分程序同时执行,专业术语称之为并发 18 | 19 | ## 主线程的运行 20 | 21 | jvm启动之后,必然有一个执行路径(线程)从main开始的。一直执行到main方法结束,这个线程在Java中称之为主线程 22 | 23 | 在主线程在这个程序中执行时,如果遇到了循环而导致在指定为停留时间过长,无法执行下面的程序 24 | 25 | ## 创建线程的方式 26 | 27 | ### 方式一 28 | 29 | 继承Thread类 30 | 31 | 1. 定义一个类继承Thread类 32 | 2. 重写run方法 33 | 3. 创建子类对象,就是创建线程对象 34 | 4. 调用start方法 35 | 36 | #### 继承Thread类的原理 37 | 38 | Thread类描述线程事务,具备线程应该有的功能 39 | 40 | 创建线程是为了建立单独的执行代码,让多部分代码同时执行。自定义线程需要执行的任务都定义在run方法中 41 | 42 | #### 线程对象调用start方法和run方法的区别 43 | 44 | 调用run方法不开启线程。仅仅是对象调用方法 45 | 46 | 调用start方法开启线程,并让jvm调用run方法在开启的线程中执行 47 | 48 | #### 多线程的内存图 49 | 50 | ```java 51 | package cn.zzuli.lzh; 52 | 53 | class Demo extends Thread { 54 | private String name; 55 | Demo(String name) { 56 | this.name = name; 57 | } 58 | 59 | @Override 60 | public void run() { 61 | for(int i = 1; i <= 20; i++) { 62 | System.out.println("name = "+name+"......"+i); 63 | } 64 | } 65 | 66 | } 67 | 68 | public class HelloWorld { 69 | 70 | public static void main(String[] args) { 71 | Demo d1 = new Demo("小强"); 72 | Demo d2 = new Demo("旺财"); 73 | 74 | d2.start(); 75 | d1.run(); 76 | } 77 | 78 | } 79 | ``` 80 | 81 | ![](http://upload-images.jianshu.io/upload_images/1540531-9f9a5c196a05cefe.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 82 | 83 | ### 方式二 84 | 85 | #### 实现Runnable接口 86 | 87 | 1. 定义类实现Runnable接口 88 | 2. 覆盖接口中的run方法,将线程任务代码定义到run方法中 89 | 3. 创建Thread类的对象 90 | 4. 将Runnable接口的子类对象作为参数传递给Thread类的构造参数。因为线程已被封装到Runnable接口的run方法中,而这个run方法所属于Runnable接口的子类对象。 91 | 5. 调用Thread类的start方法开启线程 92 | 93 | #### 实现Runnable接口的好处 94 | 95 | 避免了单继承的局限性 96 | 97 | 将线程任务单独分离出来封装成对象 98 | 99 | Runnable接口对线程对象和线程任务进行解耦 100 | 101 | #### 源码以及原理 102 | 103 | Thread类 104 | 105 | ```java 106 | public class Thread implements Runnable { 107 | /* What will be run. */ 108 | private Runnable target; //目标的Runnable接口的实现类 109 | /** 110 | * Allocates a new {@code Thread} object. This constructor has the same 111 | * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread} 112 | * {@code (null, target, gname)}, where {@code gname} is a newly generated 113 | * name. Automatically generated names are of the form 114 | * {@code "Thread-"+}n, where n is an integer. 115 | * 116 | * @param target 117 | * the object whose {@code run} method is invoked when this thread 118 | * is started. If {@code null}, this classes {@code run} method does 119 | * nothing. 120 | */ 121 | public Thread(Runnable target) {//将Runnable接口的实现类通过构造参数传进来,然后进行初始化和线程名称赋值 122 | init(null, target, "Thread-" + nextThreadNum(), 0); 123 | } 124 | /** 125 | * Initializes a Thread with the current AccessControlContext. 126 | * @see #init(ThreadGroup,Runnable,String,long,AccessControlContext) 127 | */ 128 | private void init(ThreadGroup g, Runnable target, String name, 129 | long stackSize) { 130 | init(g, target, name, stackSize, null); 131 | } 132 | 133 | /** 134 | * Initializes a Thread. 135 | * 136 | * @param g the Thread group 线程组表示一个线程的集合 137 | * @param target the object whose run() method gets called 目标的Runnable接口的实现类 138 | * @param name the name of the new Thread 线程名称 139 | * @param stackSize the desired stack size for the new thread, or 140 | * zero to indicate that this parameter is to be ignored. 栈大小 141 | * @param acc the AccessControlContext to inherit, or 142 | * AccessController.getContext() if null 143 | */ 144 | private void init(ThreadGroup g, Runnable target, String name, 145 | long stackSize, AccessControlContext acc) { 146 | if (name == null) { //如果线程名称为null,那么抛出空指针异常 147 | throw new NullPointerException("name cannot be null"); 148 | } 149 | 150 | this.name = name.toCharArray();//将此字符串转换为一个新的字符数组 151 | 152 | Thread parent = currentThread(); //当前运行的线程 153 | SecurityManager security = System.getSecurityManager(); //获取安全管理器 154 | if (g == null) { 155 | /* Determine if it's an applet or not */ 156 | 157 | /* If there is a security manager, ask the security manager 158 | what to do. */ 159 | if (security != null) { 160 | g = security.getThreadGroup(); //将安全管理器所有新创建的线程实例化后所在的线程组 161 | } 162 | 163 | /* If the security doesn't have a strong opinion of the matter 164 | use the parent thread group. */ 165 | if (g == null) { 166 | g = parent.getThreadGroup();//将当前正在运行的线程的该线程所属的线程组赋值给g 167 | } 168 | } 169 | 170 | /* checkAccess regardless of whether or not threadgroup is 171 | explicitly passed in. */ 172 | g.checkAccess();//确定当前运行的线程是否有权修改此线程组。 173 | 174 | /* 175 | * Do we have the required permissions? 176 | */ 177 | if (security != null) { 178 | if (isCCLOverridden(getClass())) { 179 | security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);//如果基于当前有效的安全策略,不允许执行根据给定权限所指定的请求访问 180 | } 181 | } 182 | 183 | g.addUnstarted(); 184 | 185 | //一系列赋值操作 186 | this.group = g; 187 | this.daemon = parent.isDaemon(); 188 | this.priority = parent.getPriority(); 189 | if (security == null || isCCLOverridden(parent.getClass())) 190 | this.contextClassLoader = parent.getContextClassLoader(); 191 | else 192 | this.contextClassLoader = parent.contextClassLoader; 193 | this.inheritedAccessControlContext = 194 | acc != null ? acc : AccessController.getContext(); 195 | this.target = target;//构造参数里面传递的Runnable接口的实现类传递进来赋值给全局的Runnable接口实现类 196 | setPriority(priority); 197 | if (parent.inheritableThreadLocals != null) 198 | this.inheritableThreadLocals = 199 | ThreadLocal.createInheritedMap(parent.inheritableThreadLocals); 200 | /* Stash the specified stack size in case the VM cares */ 201 | this.stackSize = stackSize; 202 | 203 | /* Set thread ID */ 204 | tid = nextThreadID(); 205 | } 206 | /** 207 | * If this thread was constructed using a separate 208 | * Runnable run object, then that 209 | * Runnable object's run method is called; 210 | * otherwise, this method does nothing and returns. 211 | *

212 | * Subclasses of Thread should override this method. 213 | * 214 | * @see #start() 215 | * @see #stop() 216 | * @see #Thread(ThreadGroup, Runnable, String) 217 | */ 218 | @Override 219 | public void run() { 220 | if (target != null) { //如果Runnable接口的实现类不为null,那么就是执行run里面的任务代码 221 | target.run(); 222 | } 223 | } 224 | } 225 | ``` 226 | 227 | Runnable接口 228 | 229 | ```java 230 | /* 231 | * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved. 232 | * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 233 | */ 234 | package java.lang; 235 | 236 | /** 237 | * The Runnable interface should be implemented by any 238 | * class whose instances are intended to be executed by a thread. The 239 | * class must define a method of no arguments called run. 240 | *

241 | * This interface is designed to provide a common protocol for objects that 242 | * wish to execute code while they are active. For example, 243 | * Runnable is implemented by class Thread. 244 | * Being active simply means that a thread has been started and has not 245 | * yet been stopped. 246 | *

247 | * In addition, Runnable provides the means for a class to be 248 | * active while not subclassing Thread. A class that implements 249 | * Runnable can run without subclassing Thread 250 | * by instantiating a Thread instance and passing itself in 251 | * as the target. In most cases, the Runnable interface should 252 | * be used if you are only planning to override the run() 253 | * method and no other Thread methods. 254 | * This is important because classes should not be subclassed 255 | * unless the programmer intends on modifying or enhancing the fundamental 256 | * behavior of the class. 257 | * 258 | * @author Arthur van Hoff 259 | * @see java.lang.Thread 260 | * @see java.util.concurrent.Callable 261 | * @since JDK1.0 262 | */ 263 | @FunctionalInterface 264 | public interface Runnable { 265 | /** 266 | * When an object implementing interface Runnable is used 267 | * to create a thread, starting the thread causes the object's 268 | * run method to be called in that separately executing 269 | * thread. 270 | *

271 | * The general contract of the method run is that it may 272 | * take any action whatsoever. 273 | * 274 | * @see java.lang.Thread#run() 275 | */ 276 | public abstract void run(); //抽象的run方法 277 | } 278 | ``` 279 | 280 | ## 线程的状态图 281 | 282 | 本线程状态图不一定正确,可以参考[线程状态图](http://www.cnblogs.com/wangle1001986/p/3593674.html) 283 | 284 | ![](http://upload-images.jianshu.io/upload_images/1540531-ef7d726dfb9a23cd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 285 | 286 | ## 线程的安全问题 287 | 288 | ### 发生 289 | 290 | ```java 291 | package cn.zzuli.lzh; 292 | 293 | public class ThreadDemo { 294 | public static void main(String[] args) { 295 | Ticket t = new Ticket(); 296 | 297 | Thread t1 = new Thread(t); 298 | Thread t2 = new Thread(t); 299 | Thread t3 = new Thread(t); 300 | Thread t4 = new Thread(t); 301 | 302 | t1.start(); 303 | t2.start(); 304 | t3.start(); 305 | t4.start(); 306 | } 307 | 308 | } 309 | 310 | /** 311 | * 火车票售票 312 | * 313 | * @title: Ticket 314 | * @Description: 315 | * @author: 李正浩 316 | * @Date:2017年9月22日 317 | */ 318 | class Ticket implements Runnable { 319 | 320 | private int tickets = 100; 321 | 322 | @Override 323 | public void run() { 324 | while (true) { 325 | if (tickets > 0) { 326 | try { 327 | Thread.sleep(10);// 线程停10毫秒 328 | } catch (InterruptedException e) { 329 | e.printStackTrace(); 330 | } 331 | System.out.println(Thread.currentThread().getName() + "=====" + tickets--); 332 | } 333 | } 334 | 335 | } 336 | } 337 | ``` 338 | 339 | ![](http://upload-images.jianshu.io/upload_images/1540531-a47904c762391c85.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 340 | 341 | 出现了0、-1、-2的票 342 | 343 | ### 原因 344 | 345 | 内存分析图 346 | 347 | ![](http://upload-images.jianshu.io/upload_images/1540531-b820a73cf4c7861f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 348 | 349 | 1. 多个线程操作共享的数据 350 | 2. 线程任务操作共享数据的代码有多条(运算有多个) 351 | 352 | ### 同步解决 353 | 354 | 只要让一个线程在执行线程任务时将多个操作共享数据的代码执行完,在执行过程中,不要让其他线程参与运算 355 | 356 | ```java 357 | package cn.zzuli.lzh; 358 | 359 | public class ThreadDemo { 360 | public static void main(String[] args) { 361 | Ticket t = new Ticket(); 362 | 363 | Thread t1 = new Thread(t); 364 | Thread t2 = new Thread(t); 365 | Thread t3 = new Thread(t); 366 | Thread t4 = new Thread(t); 367 | 368 | t1.start(); 369 | t2.start(); 370 | t3.start(); 371 | t4.start(); 372 | } 373 | 374 | } 375 | 376 | /** 377 | * 火车票售票 378 | * 379 | * @title: Ticket 380 | * @Description: 381 | * @author: 李正浩 @Date:2017年9月22日 382 | */ 383 | class Ticket implements Runnable { 384 | 385 | private int tickets = 100; 386 | 387 | private Object obj = new Object(); 388 | 389 | @Override 390 | public void run() { 391 | while (true) { 392 | synchronized (obj) { 393 | if (tickets > 0) { 394 | try { 395 | Thread.sleep(10);// 线程停10毫秒 396 | } catch (InterruptedException e) { 397 | e.printStackTrace(); 398 | } 399 | System.out.println(Thread.currentThread().getName() + "=====" + tickets--); 400 | } 401 | } 402 | } 403 | } 404 | } 405 | ``` 406 | 407 | 效果 408 | 409 | ![](http://upload-images.jianshu.io/upload_images/1540531-e7a8940058e808f8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 410 | 411 | #### 好处和弊端 412 | 413 | 同步好处:解决多线程的安全问题 414 | 415 | 同步弊端:降低了程序的性能 416 | 417 | #### 同步前提 418 | 419 | 必须保证多个线程在同步中使用的是同一把锁 420 | 421 | 当多线程安全问题发生时,加入同步后,问题依旧,就要通过这个同步的前提来判断是否正确 422 | 423 | ### 锁对象 424 | 425 | #### 同步函数使用的锁对象是this 426 | 427 | #### 同步代码块使用的锁对象是任意对象 428 | 429 | 当线程任务只需要一个同步时完全可以使用同步函数,当线程任务中需要多个同步时,必须通过锁来区分,必须使用同步代码块 430 | 431 | #### 静态同步函数使用的锁对象是类名.class 432 | 433 | ### 单例懒汉模式的并发访问 434 | 435 | 单例设计模式饿汉式 436 | 437 | ```java 438 | package cn.zzuli.lzh; 439 | 440 | /** 441 | * @title: Single 442 | * @Description: 单例模式 饿汉式 443 | * @author: 李正浩 444 | * @Date:2017年9月27日 445 | */ 446 | public class Single { 447 | 448 | private static final Single s = new Single(); 449 | 450 | private Single() { 451 | 452 | } 453 | 454 | public static Single getInstance() { 455 | return s; 456 | } 457 | 458 | } 459 | ``` 460 | 461 | 单例设计模式懒汉式 462 | 463 | ```java 464 | package cn.zzuli.lzh; 465 | 466 | /** 467 | * @title: Single 468 | * @Description: 单例模式 懒汉式 469 | * @author: 李正浩 470 | * @Date:2017年9月27日 471 | */ 472 | public class Single { 473 | 474 | private static Single s = null; 475 | 476 | private Single() { 477 | 478 | } 479 | 480 | public static Single getInstance() { 481 | if(s == null) { 482 | //线程安全隐患 483 | s = new Single(); 484 | } 485 | return s; 486 | } 487 | 488 | } 489 | ``` 490 | 491 | 单例模式下的高并发访问懒汉模式 492 | 493 | ```java 494 | package cn.zzuli.lzh; 495 | 496 | /** 497 | * @title: Single 498 | * @Description: 单例模式 懒汉式 499 | * @author: 李正浩 500 | * @Date:2017年9月27日 501 | */ 502 | public class Single { 503 | 504 | private static Single s = null; 505 | 506 | private Single() { 507 | 508 | } 509 | 510 | /** 511 | * 并发访问会有安全隐患,所以加入同步机制解决安全问题 512 | * 但是,同步的出现降低了效率 513 | * 通过双重判断的方式,解决效率问题,减少判断锁的次数 514 | * @return Single 515 | */ 516 | public static Single getInstance() { 517 | if(s == null) { 518 | synchronized (Single.class) { 519 | if(s == null) { 520 | s = new Single(); 521 | } 522 | } 523 | } 524 | return s; 525 | } 526 | 527 | } 528 | ``` 529 | 530 | ## 死锁示例 531 | 532 | 当线程任务中出现了多个同步(多个锁)时,如果同步中嵌套了其他的同步,容易引发死锁,一定要避免死锁 533 | 534 | ```java 535 | 536 | class Test implements Runnable 537 | { 538 | private boolean flag; 539 | Test(boolean flag) 540 | { 541 | this.flag = flag; 542 | } 543 | 544 | public void run() 545 | { 546 | 547 | if(flag) 548 | { 549 | while(true) 550 | synchronized(MyLock.locka) 551 | { 552 | System.out.println(Thread.currentThread().getName()+"..if locka...."); 553 | synchronized(MyLock.lockb) { 554 | 555 | System.out.println(Thread.currentThread().getName()+"..if lockb...."); 556 | } 557 | } 558 | } 559 | else 560 | { 561 | while(true) 562 | synchronized(MyLock.lockb) 563 | { 564 | System.out.println(Thread.currentThread().getName()+"..else lockb...."); 565 | synchronized(MyLock.locka) 566 | { 567 | System.out.println(Thread.currentThread().getName()+"..else locka...."); 568 | } 569 | } 570 | } 571 | 572 | } 573 | 574 | } 575 | 576 | class MyLock 577 | { 578 | public static final Object locka = new Object(); 579 | public static final Object lockb = new Object(); 580 | } 581 | 582 | 583 | class DeadLockTest 584 | { 585 | public static void main(String[] args) 586 | { 587 | Test a = new Test(true); 588 | Test b = new Test(false); 589 | 590 | Thread t1 = new Thread(a); 591 | Thread t2 = new Thread(b); 592 | t1.start(); 593 | t2.start(); 594 | } 595 | } 596 | ``` 597 | 598 | --------------------------------------------------------------------------------