只看原创   查看文章

数据结构学习(八)—— 链式存储队列(链表队列)

/**
 * 链表队列
 *
 * @author Neal
 */
public class LinkedQueue<T> {
    private class Node {
        private T data;
        private Node next;

        Node(T data) {
            this.data = data;
        }
    }

    private Node front;
    private Node rear;
    private Node node;

    public LinkedQueue() {
        this.front = this.rear = null;
    }

    public void enQueue(T element) {
        if (rear == null && front == null) {
            front = rear = new Node(element);
        } else {
            // 构建一个节点
            // 节点下一个指向为空
            // 将尾部节点的下一个指向指向这个节点
            rear.next = new Node(element);
            // 再讲尾部节点移动到这个节点
            rear = rear.next;
        }
    }

    public T deQueue() {
        // 如果尾部节点跟头部节点一样,则代表是个空队列
        if (front == rear) {
            throw new IndexOutOfBoundsException("这是个空队列");
        } else {
            // 获取头节点的下个节点
            T element = front.data;
            // 将头的下一个指向,改成当前要删除的节点的下一个指向
            front = front.next;
            if (rear == node) {
                // 则说明删除到底了,成了空队列
                rear = front;
            }
            return element;
        }
    }

    public int length() {
        int count = 0;
        while (front != null) {
            count++;
            front = front.next;
        }
        return count;
    }
}


原创 Mar 24, 2018 11:55:33 AM 56 0

数据结构学习(七)—— 顺序存储队列

/**
 * 循环队列(添加时,需要注意:添加元素的长度为指定size-1)
 * 会浪费一个空间
 *
 * @author Neal
 */
public class LoopQueue<T> {
    private class Node {
        private T[] data;
        private int front;
        private int rear;

        @SuppressWarnings("unchecked")
        Node(int size) {
            data = (T[]) new Object[size];
            this.front = this.rear = 0;
        }
    }

    private Node node;

    public LoopQueue(int size) {
        node = new Node(size);
    }

    public int queueLength() {
        return (node.rear - node.front + node.data.length) % node.data.length;
    }

    public void enQueue(T element) {
        if ((node.rear + 1) % node.data.length == node.front) {
            throw new IndexOutOfBoundsException("队列已经满了");
        } else {
            node.data[node.rear] = element;
            node.rear = (node.rear + 1) % node.data.length;
        }
    }

    public T deQueue() {
        if (node.front == node.rear) {
            throw new IndexOutOfBoundsException("队列为空");
        }
        T data = node.data[node.front];
        node.front = (node.front + 1) % node.data.length;
        return data;
    }
}

小心坑..............

原创 Mar 24, 2018 11:52:29 AM 57 0

机器学习(2)-- python决策树

#!/usr/bin/python3
# coding:utf-8
# Filename:np3.py
# Author:Neal
# Time:2018.03.20 17:11
import operator
from math import log
from matplotlib.font_manager import FontProperties
import matplotlib.pyplot as plt


def createDataSet():
    dataSet = [[0, 0, 0, 0, 'no'],  # 数据集
               [0, 0, 0, 1, 'no'],
               [0, 1, 0, 1, 'yes'],
               [0, 1, 1, 0, 'yes'],
               [0, 0, 0, 0, 'no'],
               [1, 0, 0, 0, 'no'],
               [1, 0, 0, 1, 'no'],
               [1, 1, 1, 1, 'yes'],
               [1, 0, 1, 2, 'yes'],
               [1, 0, 1, 2, 'yes'],
               [2, 0, 1, 2, 'yes'],
               [2, 0, 1, 1, 'yes'],
               [2, 1, 0, 1, 'yes'],
               [2, 1, 0, 2, 'yes'],
               [2, 0, 0, 0, 'no']]
    # 分类属性
    labels = ['年龄', '有工作', '有自己的房子', '信贷情况']
    # 返回数据集跟分类属性
    return dataSet, labels


def calcShannonEnt(dataSet):
    """
    计算给定数据集的经验熵
    :param dataSet: 数据集
    :return: 经验熵(香农熵)
    """
    numEntires = len(dataSet)  # 返回数据集行数
    labelCounts = {}  # 保存每个标签(Label)出现次数的字典
    for featVec in dataSet:  # 对于每组特征向量进行统计
        currentLabel = featVec[-1]  # 提取标签(Label)信息
        if currentLabel not in labelCounts.keys():  # 如果标签(Label)没有放入统计次数
            labelCounts[currentLabel] = 0
        labelCounts[currentLabel] += 1  # Label计数
    shannoEnt = 0.0  # 经验熵(香农熵)
    for key in labelCounts:  # 计算香农熵
        prob = float(labelCounts[key]) / numEntires  # 选择该标签的概率
        shannoEnt -= prob * log(prob, 2)  # 利用公式计算
    return shannoEnt  # 返回经验熵(香农熵)


def splitDataSet(dataSet, axis, value):
    """
    按照给定特征划分数据集
    :param dataSet: 数据集
    :param axis: 划分数据集的特征
    :param value: 需要返回的特征值
    :return:
    """
    retDataSet = []  # 创建返回的数据集列表
    for featVec in dataSet:  # 遍历数据集
        if featVec[axis] == value:
            reducedFeatVec = featVec[:axis]  # 去掉axis特征
            reducedFeatVec.extend(featVec[axis + 1:])  # 将符合条件的添加到返回的数据集
            retDataSet.append(reducedFeatVec)
    return retDataSet  # 返回划分后的数据集


def chooseBestFeatureToSplit(dataSet):
    """
    选择最优特征
    :param dataSet:数据集
    :return:信息增益最大的(最优)特征的索引值
    """
    numFeatures = len(dataSet[0]) - 1  # 特征数量
    baseEntropy = calcShannonEnt(dataSet)  # 计算数据集的香农熵
    bestInfoGain = 0.0  # 信息增益
    bestFeature = -1  # 最优特征的索引值
    for i in range(numFeatures):  # 遍历所有特征
        # 获取dataSet的第i个所有特征
        featList = [example[i] for example in dataSet]
        uniqueVals = set(featList)  # 创建set集合{},元素不可重复
        newEntroy = 0.0  # 经验条件熵
        for value in uniqueVals:  # 计算信息增益
            subDataSet = splitDataSet(dataSet, i, value)  # subDataSet划分后的子集
            prob = len(subDataSet) / float(len(dataSet))  # 计算子集的概率
            newEntroy += prob * calcShannonEnt(subDataSet)  # 根据公式计算经验条件熵
        infoGain = baseEntropy - newEntroy  # 信息增益
        print("第%d个特征的增益为%.3f" % (i, infoGain))
        if infoGain > bestInfoGain:  # 计算信息增益
            bestInfoGain = infoGain  # 更新信息增益
            bestFeature = i  # 记录信息增益的最大特征的索引值
    return bestFeature  # 返回信息增益的最大特征的索引值


def majorityCnt(classList):
    """
    统计classList中出现此处最多的元素(类标签)
    :param classList:
    :return:
    """
    classCount = {}
    for vote in classList:  # 统计classList中每个元素出现的次数
        if vote not in classCount.keys():
            classCount[vote] = 0
        classCount[vote] += 1
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
    return sortedClassCount[0][0]  # 返回classList中出现次数最多的元素


def createTree(dataSet, labels, featLabels):
    """
    创建决策树
    :param dataSet: 数据集
    :param labels: 标签
    :param featLabels:
    :return:
    """
    classList = [example[-1] for example in dataSet]  # 取分类标签(是否放贷)
    if classList.count(classList[0]) == len(classList):  # 如果类别完全相同则停止继续划分
        return classList[0]
    if len(dataSet[0]) == 1:  # 遍历完所有特征时返回出现次数最多的类标签
        return majorityCnt(classList)
    bestFeat = chooseBestFeatureToSplit(dataSet)  # 选择最优特征
    bestFeatLabel = labels[bestFeat]  # 最优特征标签
    featLabels.append(bestFeatLabel)
    my_tree = {bestFeatLabel: {}}  # 根据最优特征的标签生成树
    del (labels[bestFeat])  # 删除已经使用的特征标签
    featValues = [example[bestFeat] for example in dataSet]  # 得到训练集中所有最优特征的属性值
    uniqueVals = set(featValues)  # 去掉重复的属性值
    for value in uniqueVals:  # 遍历特征,创建决策树
        my_tree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value), labels, featLabels)
    return my_tree


def getNumLeafs(myTree):
    """
    获取决策树叶子节点的数目
    :param myTree:决策树
    :return: 决策树的叶子节点的数目
    """
    numLeafs = 0  # 初始化叶子
    firstStr = next(iter(myTree))  # python3中的myTree.keys()返回的是dict_keys,所以不能使员工myTree.keys()[0]方法获取
    secondDict = myTree[firstStr]  # 获取下一组字典
    for key in secondDict.keys():
        if type(secondDict[key]).__name__ == 'dict':  # 测试该节点是否为字典,如果不是字典,代表此节点为叶子节点
            numLeafs += getNumLeafs(secondDict[key])
        else:
            numLeafs += 1
    return numLeafs


def getTreeDepth(myTree):
    """
    获取决策树的层数
    :param myTree: 决策树
    :return: 决策树的层数
    """
    maxDepth = 0  # 初始化决策树深度
    firstStr = next(iter(myTree))
    secondDict = myTree[firstStr]  # 获取下一个字典
    for key in secondDict.keys():
        if type(secondDict[key]).__name__ == 'dict':  # 测试该节点是否为字段是否为字段,如果不是字典,则代表该节点是叶子节点
            thisDepth = 1 + getTreeDepth(secondDict[key])
        else:
            thisDepth = 1
        if thisDepth > maxDepth:
            maxDepth = thisDepth  # 更新层数
    return maxDepth


def plotNode(nodeTxt, centerPt, parentPt, nodeType):
    """
    绘制节点
    :param nodeTxt: 节点名
    :param centerPt: 文本位置
    :param parentPt: 标注的箭头位置
    :param nodeType: 节点格式
    :return:
    """
    arrow_args = dict(arrowstyle='<-')  # 定义箭头格式
    font = FontProperties(fname=r"c:\windows\fonts\simsun.ttc", size=14)  # 设置字体
    createPlot.ax1.annotate(nodeTxt, xy=parentPt, xycoords='axes fraction', xytext=centerPt,
                            textcoords='axes fraction', va='center', ha='center',
                            bbox=nodeType, arrowprops=arrow_args, FontProperties=font)  # 绘制节点


def plotMidText(cntrPt, parentPt, txtString):
    """
    标注有向边属性值
    :param cntrPt:标注的位置
    :param parentPt: 标注的位置
    :param txtString: 标注的内容
    :return:
    """
    xMid = (parentPt[0] - cntrPt[0]) / 2.0 + cntrPt[0]  # 计算标注位置
    yMid = (parentPt[1] - cntrPt[1]) / 2.0 + cntrPt[1]
    createPlot.ax1.text(xMid, yMid, txtString, va='center', ha="center",
                        rotation=30)


def plotTree(myTree, parentPt, nodeTxt):
    """
    绘制决策树
    :param myTree: 决策树(字典)
    :param parentPt: 标注的内容
    :param nodeTxt: 节点名
    :return:
    """
    decisionNode = dict(boxstyle='sawtooth', fc="0.8")  # 设置节点格式
    leafNode = dict(boxstyle='round4', fc="0.8")  # 设置叶节点格式
    numLeafs = getNumLeafs(myTree)  # 获取决策树叶节点数目,决定了树的宽度
    depth = getTreeDepth(myTree)  # 获取决策树层度
    firstStr = next(iter(myTree))  # 下一个字典
    cntrPt = (plotTree.xOff + (1.0 + float(numLeafs)) / 2.0 / plotTree.totalW, plotTree.yOff)  # 中心位置
    plotMidText(cntrPt, parentPt, nodeTxt)  # 标注有向边属性值
    plotNode(firstStr, cntrPt, parentPt, decisionNode)  # 绘制节点
    secondDict = myTree[firstStr]  # 下一个字典,也就是继续绘制子节点
    plotTree.yOff = plotTree.yOff - 1.0 / plotTree.totalD  # y偏移
    for key in secondDict.keys():
        if type(secondDict[key]).__name__ == 'dict':
            plotTree(secondDict[key], cntrPt, str(key))  # 不是叶节点,递归继续绘制
        else:
            plotTree.xOff = plotTree.xOff + 1.0 / plotTree.totalW  # 是叶节点,绘制叶节点,并标注有向边属性值
            plotNode(secondDict[key], (plotTree.xOff, plotTree.yOff), cntrPt, leafNode)
            plotMidText((plotTree.xOff, plotTree.yOff), cntrPt, str(key))
    plotTree.yOff = plotTree.yOff + 1.0 / plotTree.totalD


def createPlot(inTree):
    fig = plt.figure(1, facecolor='white')
    fig.clf()
    axprops = dict(xticks=[], yticks=[])
    createPlot.ax1 = plt.subplot(111, frameon=False, **axprops)
    plotTree.totalW = float(getNumLeafs(inTree))
    plotTree.totalD = float(getTreeDepth(inTree))
    plotTree.xOff = -0.5 / plotTree.totalW
    plotTree.yOff = 1.0
    plotTree(inTree, (0.5, 1.0), "")
    plt.show()


def classsify(inputTree, featLabels, testVec):
    classLabel = None
    firstStr = next(iter(inputTree))
    secondDict = inputTree[firstStr]
    featIndex = featLabels.index(firstStr)
    for key in secondDict.keys():
        if testVec[featIndex] == key:
            if type(secondDict[key]).__name__ == 'dict':
                classLabel = classsify(secondDict[key], featLabels, testVec)
            else:
                classLabel = secondDict[key]
    return classLabel


if __name__ == '__main__':
    dataSet, labels = createDataSet()
    featLabels = []
    myTree = createTree(dataSet, labels, featLabels)
    # print(myTree)
    # createPlot(myTree)
    testVec = [0, 1]
    result = classsify(myTree, featLabels, testVec)
    if result == 'yes':
        print('放贷')
    elif result == 'no':
        print('不放贷')


原创 Mar 22, 2018 12:24:08 PM 51 0

机器学习(1)-- python实现KNN

#!/usr/bin/python3
# coding:utf-8
# Filename:test_girl.py
# Author:Neal
# Time:2018.03.21 17:09

import numpy as np
import operator

"""
测试该女性属于哪一身材阶层(纯属搞笑,切勿当真)
"""


def create_data_set():
    """
    创建数据集
    :return: 数据集跟标签集
    """
    data_set = np.array(
        [[171, 85], [160, 107], [158, 106], [158, 96], [160, 87],
         [162, 84], [165, 88], [170, 96], [167, 90], [168, 94]])
    label_set = ['1分', '2分', '3分', '4分', '5分', '6分', '7分', '8分', '9分', '10分']
    return data_set, label_set


def classify(in_x, data_set, labels, k):
    """
    KNN算法分类器
    :param in_x: 用于分类的数据(测试集)
    :param data_set: 用于训练的数据(训练集)
    :param labels: 分类标签
    :param k: KNN算法参数,选择距离最小的K个点
    :return: 分类结果
    """
    data_set_size = data_set.shape[0]
    df = np.tile(in_x, (data_set_size, 1))
    diff_mat = df - data_set
    sq_diff_mat = diff_mat ** 2
    sq_distance = sq_diff_mat.sum(axis=1)
    distances = sq_distance ** 0.5
    sorted_by_index_list = distances.argsort()
    class_count = {}
    for i in range(k):
        vote_label = labels[sorted_by_index_list[i]]
        class_count[vote_label] = class_count.get(vote_label, 0) + 1

    sorted_class_count = sorted(class_count.items(), key=operator.itemgetter(1), reverse=True)
    return sorted_class_count[0][0]


if __name__ == '__main__':
    group, labels = create_data_set()
    test = [165, 95]
    test_class = classify(test, group, labels, 3)
    print(test_class)


原创 Mar 22, 2018 12:22:10 PM 37 0

机器学习(1)-- java实现KNN

首先得弄个bean存储数据,因为Java无法直接返回两个数组

/**
 * @author Neal
 */
public class DataSetBean {
    private int[][] dataSet;
    private String[] labels;

    public int[][] getDataSet() {
        return dataSet;
    }

    public void setDataSet(int[][] dataSet) {
        this.dataSet = dataSet;
    }

    public String[] getLabels() {
        return labels;
    }

    public void setLabels(String[] labels) {
        this.labels = labels;
    }
}

再就是具体实现了,KNN的具体原理请自行百度,这里就不在详讲了。看代码

import java.util.*;

/**
 * KNN(K-近邻法) JAVA实现
 * 测试该女性(身高,体重)属于哪一身材阶层(纯属搞笑,切勿当真)
 *
 * @author Neal
 */
public class KnnCus {

    /**
     * 创建训练集数据,跟分类标签,并封装到JavaBean中
     *
     * @return DataSetBean
     */
    private DataSetBean createDataSet() {
        DataSetBean bean = new DataSetBean();
        int[][] dataSet = {
                {171, 85}, {160, 107}, {158, 106}, {158, 96}, {160, 87},
                {162, 84}, {165, 88}, {170, 96}, {167, 90}, {168, 94}
        };
        String[] labels = {"1分", "2分", "3分", "4分", "5分", "6分", "7分", "8分", "9分", "10分"};
        bean.setDataSet(dataSet);
        bean.setLabels(labels);
        return bean;
    }

    /**
     * Knn 分类器
     * 原理为:欧氏距离
     *
     * @param inX     测试集(需要测试的数据)
     * @param dataSet 训练集(初始数据)
     * @param labels  标注(标注的数据)
     * @param k       Knn算法的参数,表示,离的最近的K个元素
     * @return 该分类
     */
    private String classify(int[][] inX, int[][] dataSet, String[] labels, int k) {
        int dataSetSize = dataSet.length;
        int[][] df = new int[dataSetSize][2];
        // 将其测试数据,进行行的扩展
        for (int i = 0; i < dataSetSize; i++) {
            System.arraycopy(inX[0], 0, df[i], 0, 2);
        }
        int[][] diffMat = new int[dataSetSize][2];
        for (int i = 0; i < dataSetSize; i++) {
            for (int j = 0; j < 2; j++) {
                diffMat[i][j] = df[i][j] - dataSet[i][j];
            }
        }
        for (int i = 0; i < dataSetSize; i++) {
            for (int j = 0; j < 2; j++) {
                diffMat[i][j] *= diffMat[i][j];
            }
        }
        double[] distance = new double[dataSetSize];
        for (int i = 0; i < dataSetSize; i++) {
            double temp = diffMat[i][0] + diffMat[i][1];
            distance[i] = Math.sqrt(temp);
        }
        int[] sortedByIndex = sortedByIndex(distance);
        // 这里为了保证顺序要用linkedHashMap
        Map<String, Integer> classCount = new LinkedHashMap<>(3);
        for (int i = 0; i < k; i++) {
            String voteLabel = labels[sortedByIndex[i]];
            // 如果所得键不存在,默认给值设为1,再添加
            classCount.merge(voteLabel, 1, (a, b) -> a + b);
        }
        // 再根据值排序
        Map<String, Integer> list = sortMapByValue(classCount);
        // 返回最近的第一个元素
        return list.keySet().iterator().next();
    }

    /**
     * 按最小值排序,然后返回一列索引,
     * 原理:将原数组复制,再排序一个,然后再去对比是否相等,得到在原数组的索引位置,添加到新数组
     * 缺点:不稳定,对于重复元素,只记录后一个的索引
     *
     * @param old 需要排序的数组
     * @return 返回索引列表
     */
    private int[] sortedByIndex(double[] old) {
        double[] target = new double[old.length];
        System.arraycopy(old, 0, target, 0, old.length);
        int[] newIndex = new int[old.length];
        Arrays.sort(target);
        for (int i = 0; i < old.length; i++) {
            for (int j = 0; j < old.length; j++) {
                if (target[i] == old[j]) {
                    newIndex[i] = j;
                }
            }
        }
        return newIndex;
    }

    /**
     * Map按值排序
     *
     * @param oriMap 原本Map
     * @return Map
     */
    private Map<String, Integer> sortMapByValue(Map<String, Integer> oriMap) {
        Map<String, Integer> sortedMap = new LinkedHashMap<>();
        if (oriMap != null && !oriMap.isEmpty()) {
            List<Map.Entry<String, Integer>> entryList = new ArrayList<>(oriMap.entrySet());
            entryList.sort((o1, o2) -> {
                int value1, value2;
                try {
                    value1 = o1.getValue();
                    value2 = o2.getValue();
                } catch (NumberFormatException e) {
                    value1 = 0;
                    value2 = 0;
                }
                return value2 - value1;
            });
            Iterator<Map.Entry<String, Integer>> item = entryList.iterator();
            Map.Entry<String, Integer> tmpEntry;
            while (item.hasNext()) {
                tmpEntry = item.next();
                sortedMap.put(tmpEntry.getKey(), tmpEntry.getValue());
            }
        }
        return sortedMap;
    }

    public static void main(String[] args) {
        KnnCus knn = new KnnCus();
        DataSetBean bean = knn.createDataSet();
        // 该美女身高165,体重95
        int[][] inX = {{165, 95}};
        int k = 3;
        String result = knn.classify(inX, bean.getDataSet(), bean.getLabels(), k);
        System.out.println(result);
    }
}


原创 Mar 22, 2018 12:18:36 PM 46 0

数据结构学习(六)—— 链栈

/**
 * 链栈
 *
 * @author Neal
 */
public class LinkedStack<T> {
    private class Node {
        private T data;
        private Node next;

        Node(T data, Node next) {
            this.data = data;
            this.next = next;
        }
    }

    /**
     * 头指针,跟计数器
     */
    private Node head;
    private int size;

    public LinkedStack() {
        this.head = null;
        this.size = 0;
    }

    public void push(T element) {
        head = new Node(element, head);
        size++;
    }

    public int length() {
        return size;
    }

    public T remove() {
        if (size == 0) {
            throw new IndexOutOfBoundsException("空栈无法执行删除操作");
        } else {
            Node nodePre = head;
            head = head.next;
            nodePre.next = null;
            size--;
            return nodePre.data;
        }
    }
}


原创 Mar 19, 2018 8:22:42 PM 37 0

数据结构学习(五)—— 两栈共享空间栈(未测试)

/**
 * 两栈共享空间
 *
 * @author Neal
 */
public class ShareOrderStack<T> {
    private Node node;

    public ShareOrderStack(int size) {
        node = new Node(size);
    }

    private class Node {
        /**
         * 数据区
         */
        private T[] data;
        /**
         * 栈1 栈顶指针
         */
        private int top1;
        /**
         * 栈2 栈顶指针
         */
        private int top2;

        @SuppressWarnings("unchecked")
        Node(int size) {
            this.data = (T[]) new Object[size];
            this.top1 = -1;
            this.top2 = size;
        }
    }

    public void push(T element, int choose) throws Exception {
        if (node.top1 + 1 == node.top2) {
            throw new IndexOutOfBoundsException("栈已经满了");
        }
        if (choose < 0 || choose > 2) {
            throw new Exception("没有这个选择");
        }
        if (choose == 1) {
            node.data[++node.top1] = element;
        } else if (choose == 2) {
            node.data[--node.top1] = element;
        }
    }

    public T pop(int choose) throws Exception {
        if (choose < 0 || choose > 2) {
            throw new Exception("没有这个选择");
        }
        if (choose == 1) {
            if (node.top1 == -1) {
                throw new IndexOutOfBoundsException("栈1是空的");
            }
            return node.data[node.top1--];
        } else if (choose == 2) {
            if (node.top2 == node.data.length) {
                throw new IndexOutOfBoundsException("栈2是空的");
            }
            return node.data[node.top2--];
        }
        return null;
    }
}


原创 Mar 19, 2018 8:21:46 PM 39 0

数据结构学习(四)—— 栈的顺序存储结构

/**
 * 线性栈(基于顺序存储结构)
 *
 * @author Neal
 */
public class OrderStack<T> {
    private Node node;

    public OrderStack(int size) {
        this.node = new Node(size);
    }

    private class Node {
        T[] data;
        /**
         * 栈顶指针
         */
        int top;

        @SuppressWarnings("unchecked")
        Node(int size) {
            this.data = (T[]) new Object[size];
            this.top = -1;
        }
    }

    public void push(T element) {
        if (node.top == node.data.length - 1) {
            throw new IndexOutOfBoundsException("栈满了");
        }
        node.data[++node.top] = element;
    }

    public T pop() {
        if (node.top == -1) {
            throw new IndexOutOfBoundsException("栈是空的");
        }
        return node.data[node.top--];
    }

    public int length() {
        return node.top;
    }
}


原创 Mar 19, 2018 8:20:44 PM 42 0

数据结构学习(三)—— 双链表(双向链表)

/**
 * 双链表
 *
 * @author Neal
 */
public class LinkedListBySelf<T> {
    private class Node {
        private T data;
        private Node next;
        private Node prev;

        Node(T data, Node prev, Node next) {
            this.data = data;
            this.prev = prev;
            this.next = next;
        }
    }

    private Node head;
    private Node tail;
    private int size;

    public LinkedListBySelf() {
        this.head = null;
        this.tail = null;
        this.size = 0;
    }

    public void add(T element) {
        if (head == null) {
            head = new Node(element, null, null);
            tail = head;
        } else {
            // 新节点
            Node last = new Node(element, tail, null);
            // 尾部的下一个节点是新节点
            tail.next = last;
            // 将尾部指针到新节点
            tail = last;
        }
        size++;
    }

    public int length() {
        return size;
    }

    public T remove() {
        if (head == tail) {
            throw new IndexOutOfBoundsException("这是个空链表,无法删除");
        } else {
            return removeByIndex(size);
        }
    }

    public T removeByIndex(int index) {
        if (index > size || index < 0) {
            throw new IndexOutOfBoundsException("越界了");
        } else {
            Node lastPrev = loopThis(index - 1);
            Node delNode = lastPrev.next;
            lastPrev.prev = delNode.prev;
            lastPrev.next = delNode.next;

            delNode.prev = null;
            delNode.next = null;
            size--;
            return delNode.data;
        }
    }

    private Node loopThis(int index) {
        if (head == tail || size == 0) {
            throw new IndexOutOfBoundsException("空链表");
        } else {
            Node current = tail;
            for (int i = size; i >= 0 && current.prev != null; current = current.prev, i--) {
                if (i == index) {
                    return current;
                }
            }
        }
        return null;
    }
}


原创 Mar 19, 2018 8:18:59 PM 52 0

数据结构学习(二)—— 单链表

/**
 * 单链表
 *
 * @author Neal
 */
public class LinkedListCus<T> {
    private class Node {

        /**
         * 数据域
         */
        private T item;
        /**
         * 指针域
         */
        private Node next;

        Node(T item, Node next) {
            this.item = item;
            this.next = next;
        }
    }

    /**
     * 链表头引用
     */
    private Node head;
    /**
     * 链表尾引用
     */
    private Node tail;
    /**
     * 链表长度
     */
    private int size;

    public LinkedListCus() {
        this.head = null;
        this.tail = null;
    }

    public LinkedListCus(T data) {
        // 指定一个头节点的数据域为data,不指向其他节点
        this.head = new Node(data, null);
        tail = head;
        size++;
    }

    public int length() {
        return size;
    }

    public T getElement(int index) {
        return findNodeByIndex(index).item;
    }

    private Node findNodeByIndex(int index) {
        if (index < 0 || index > size - 1) {
            throw new IndexOutOfBoundsException("线性表越界");
        }
        Node current = head;
        for (int i = 0; i < size && current.next != null;
             i++, current = current.next) {
            if (i == index) {
                return current;
            }
        }
        return null;
    }

    public int getIndexByElement(T elements) {
        // 从第一个节点开始遍历
        Node current = head;
        for (int i = 0; i < size && current.next != null;
             i++, current = current.next) {
            if (current.item.equals(elements)) {
                return i;
            }
        }
        return -1;
    }

    public void insert(int index, T element) {
        if (index < 0 || index > size) {
            throw new IndexOutOfBoundsException("线性表越界");
        }
        if (head == null) {
            add(element);
        } else {
            if (index == 0) {
                addAtHead(element);
            } else {
                // 找到要插入位置的前一个节点
                Node prev = findNodeByIndex(index - 1);
                // 插入后prev的next指向新节点,
                // 新节点的next指向原来prev的下一节点
                prev.next = new Node(element, prev.next);
            }
        }
        size++;
    }

    /**
     * 每次在尾部添加新节点
     *
     * @param element element
     */
    public void add(T element) {
        if (head == null) {
            head = new Node(element, null);
            tail = head;
        } else {
            Node node = new Node(element, null);
            tail.next = node;
            tail = node;
        }
        size++;
    }

    /**
     * 在头部插入节点
     *
     * @param element element
     */
    public void addAtHead(T element) {
        // 在头部插入新节点,就是让新节点的next指向原来的head,
        // 让新节点作为链表的头结点
        head = new Node(element, head);
        // 如果插入之前是空链表
        if (tail == null) {
            tail = head;
        }
    }

    public T delete(int index) {
        Node deleteNode;
        if (index < 0 || index > size - 1) {
            throw new IndexOutOfBoundsException("线性表越界");
        }
        if (index == 0) {
            deleteNode = head;
            head = head.next;
        } else {
            // 获取要删除的节点的前一个节点
            Node prev = findNodeByIndex(index - 1);
            // 要删除的节点就是prev的next指向的节点
            deleteNode = prev.next;
            // 删除以后prev的next指向被删除之前所指向的next
            prev.next = deleteNode.next;
            deleteNode.next = null;
        }
        size--;
        return deleteNode.item;
    }

    /**
     * 删除 链表的最后一个元素
     *
     * @return T
     */
    public T removeLast() {
        return delete(size - 1);
    }

    public void clear() {
        head = null;
        tail = null;
        size = 0;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    /**
     * 重写单链表的toString
     *
     * @return 链表元素列表
     */
    @Override
    public String toString() {
        if (isEmpty()) {
            return "[]";
        } else {
            StringBuilder sb = new StringBuilder("[");
            for (Node current = head; current != null; current = current.next) {
                sb.append(current.item.toString()).append(",");
            }
            int len = sb.length();
            return sb.delete(len - 1, len).append("]").toString();
        }
    }
}


原创 Mar 19, 2018 8:17:20 PM 49 0

爬取今日头条100条新闻,并统计出现“霍金”的次数

#!/usr/bin/python3
# coding:utf-8
# Filename:main_spider.py
# Author:Neal
# Time:2018.03.14 14:06

import urllib
from urllib.request import urlopen
import os
import time
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException

"""
    爬取今日头条热点新闻(有些html是转载在今日头条上,
    网站的规则都不一样,所以无法自动提取需要的信息)
    由于该网站使用AJAX,所有每次的加载都是加载新的li标签,
    所以需要从打开完的链接位置开始下一轮的链接打开
"""


def open_url_get_data(links):
    """
    打开链接列表的所有的链接,并返回一个html,用于解析器解析
    该方法需要耗时等待
    :param links:链接列表
    :return:html页面
    """
    for link in links:
        # 封装一个请求头对象
        fast = urllib.request.Request(url=link.get_attribute('href'), headers={
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                          'Chrome/65.0.3325.162 Safari/537.36'},
                                      method='GET')
        # 返回一个html页面
        return urllib.request.urlopen(fast).read().decode()


def get_once_page_links(driver, list_len):
    """
    分析获取该页面的所有需要的链接
    注意:因为每次都是记录从头记录的li列表,所以需要进行截取
    :param list_len: 当前列表的长度
    :param driver:
    :return:list
    """
    # 获取该页的所有文章链接
    links = []
    if list_len == 1:
        links = driver.find_elements_by_xpath(
            "/html/body/div/div[4]/div[2]/div[2]/div/div/div/ul/li/div/div[1]/div/div[1]/a")
    else:
        # 根据上一次的长度记录开始
        for index in range(1, 8):
            try:
                link = driver.find_element_by_xpath(
                    "/html/body/div/div[4]/div[2]/div[2]/div/div/div/ul/li[" + str(
                        list_len) + "]/div/div[1]/div/div[1]/a")
            except NoSuchElementException:
                pass
            else:
                links.append(link)
            finally:
                list_len += 1
    if links is not None:
        save_links(links, 'C:\\my\\resource\\profile\\', 'links')
    return links


def save_links(links, file_path, file_name):
    """
    将爬取的链接列表存入到文本(进行追加不覆盖)
    :param links: 链接列表
    :param file_path: 保存路径
    :param file_name: 文本名
    :return:None
    """
    for link in links:
        print(link.text)
        if not os.path.exists(file_path):
            os.makedirs(file_path)
        with open(file_path + file_name + '.txt', 'a+') as f:
            f.write('标题:\t' + link.text + '\t链接地址\t' + link.get_attribute('href') + '\r\n')
            f.flush()
            f.close()


def parse_data():
    """
    解析器,解析html,提取所需要的信息数据
    :return:json
    """
    pass


def do_script_to_next(driver):
    """
    自动滑动到该页面最底部,并且返回一个上次列表的长度(记录历史地址)
    :param driver:
    :return:int
    """
    driver.execute_script('window.scrollTo(0, document.body.scrollHeight)')
    lis = driver.find_elements_by_xpath("/html/body/div/div[4]/div[2]/div[2]/div/div/div/ul/li/div/div[1]/div/div[1]/a")
    # 每次的长度,还应该减去上一次的列表长度,否则将列表越界
    return len(lis)


if __name__ == '__main__':
    browser = webdriver.Chrome()
    browser.get('https://www.toutiao.com/ch/news_hot/')
    # 初始长度为空
    list_last_len = 1
    for i in range(100):
        # 获取该页的所有链接
        link_list = get_once_page_links(browser, list_last_len)
        # 开始滑动到页面底部,加载下一页的连接,并得到上一页的列表长度,防止重复打开链接,需要等待10s
        list_last_len = do_script_to_next(browser)
        time.sleep(5)
        # 打开链接列表的所有链接
        # html_page = open_url_get_data(link_list)
        # print(html_page)

统计

#!/usr/bin/python3
# coding:utf-8
# Filename:count_keywords.py
# Author:Neal
# Time:2018.03.14 17:08

"""
    统计“霍金”在随机50条头条新闻标题中出现的次数
"""

count = 0
index = 0
with open('C:\\my\\resource\\profile\\links.txt') as f:
    while index < 50:
        line = f.readline()
        if not line:
            break
        else:
            if line.count('霍金') > 0:
                count += 1
        index += 1
print(count)


原创 Mar 14, 2018 5:16:19 PM 64 0

Python3+pillow的简单图像处理

#!/usr/bin/python3
# coding:utf-8
# Filename:image_handle.py
# Author:Neal
# Time:2018.03.13 17:34
"""
    验证码处理
"""
from PIL import Image

image = Image.open("C:\\my\\resource\\img\\1520932974.0316732ldhrmk.jpg")
# 转化为灰度图
image_gray = image.convert('L')

# 打印详细信息
print(image.format, image.size, image.mode)
# 进行切割 crop((left,upper,right,lower))
box = (25, 10, 55, 50)
region = image.crop(box)
region.show()
box = (50, 10, 55, 50)
region = image.crop(box)
region.show()


def get_bin_table(threshold=140):
    """
    获取灰度转二值的映射table
    :return: table
    """
    table = []
    for i in range(256):
        if i < threshold:
            table.append(0)
        else:
            table.append(1)
    return table

table = get_bin_table()
out = image_gray.point(table, '1')
out.show()


原创 Mar 13, 2018 6:38:00 PM 64 0

Python3+selenium简单实现控制台汉译英翻译器

#!/usr/bin/python3
# coding:utf-8
# Filename:selenium_phantomjs.py
# Author:Neal
# Time:2018.03.12 16:55
import time
import sys
from selenium import webdriver

"""
    自动调用百度翻译,进行简单的汉译英操作
"""

# 自定义加载
driver = webdriver.Chrome()

# 设定get url最大等待时间,规定时间内没有响应就报错
driver.implicitly_wait(40)
driver.set_page_load_timeout(40)
# 设置脚本超时时间
driver.set_script_timeout(10)

driver.get("http://fanyi.baidu.com/?aldtype=16047#auto/zh")
# 停止加载
driver.execute_script('window.stop()')
words = str(input('请输入你想要翻译的单词或句子,按回车结束!\n'))
while True:
    # 获取输入文本域
    text_area = driver.find_element_by_xpath("//textarea[@id='baidu_translate_input' and @class='textarea']")
    # 将单词输入到文本域
    text_area.send_keys(words)
    time.sleep(1)
    # 获取输出信息域
    get_translate = driver.find_element_by_xpath("//div[@class='output-bd']/p[2]")
    # 获取翻译后的结果
    print('==================翻译结果=================')
    print(get_translate.text)
    words = str(input('\n退出请按q,清空请按任意键!\n'))
    if words is 'q':
        # 退出
        sys.exit()

    # 清除输入文本域
    clear = driver.find_element_by_xpath("//a[@class='textarea-clear-btn']")
    clear.click()


原创 Mar 13, 2018 6:35:44 PM 65 0

Python3简单使用openCV

#!/usr/bin/python3
# coding:utf-8
# Filename:selenium_cv.py
# Author:Neal
# Time:2018.03.12 18:26

import cv2

"""
    简单使用python-openCV
"""
# 进入色彩读取模式
img = cv2.imread('C:\\Programs\\resource\\img\\color.jpg', cv2.IMREAD_GRAYSCALE)

# 打印图片的一些信息
print(img.shape)
print(img.size)
print(img.dtype)

# 在图片上输入信息
# cv2.putText('')

# 缩放图片并保存
# cv2.resize()

# 图像平移
"""
    图像平移需要构建一个偏移矩阵M
    rows,cols,channel = img.shape
    M=np.float32([1,0,100],[0,1,50])
    dst = cv2.warpAffine(img,M,(cols,rows))
    cv2.imshow('img',dst)
"""
# 图像旋转
"""
    rows,cols = img.shape
    第一个参数为旋转中心,第二个参数为旋转角度,第三个为旋转后的缩放因子
    M = cv2.getRotationMatrix2D((cols/2,rows/2),45,0.06)
    第三个参数为图像的尺寸中心
    dst = cv2.warpAffine(img,M,(2*cols,2*rows))
"""

# 仿射变换
"""
    rows,cols,ch = img.shape
    pts1 = np.float32([[50,50],[200,50],[50,200]])
    pts2 = np.float32([[10,1000],[200,50],[100,250]])
    M = cv2.getAffineTransform(pts1,pts2)
    dst = cv2.warpAffine(img,M,(cols,rows))
    
"""

# 透视变换

# 图像regions of interest

# 通道的拆分/合并处理

# 创建一个窗口,可以指定窗口大小,也可以自动根据图片大小创建
cv2.namedWindow("image", cv2.WINDOW_AUTOSIZE)
# 显示图像,可以创建多个窗口
cv2.imshow("image", img)
# 键盘绑定函数,函数等待特定的几毫秒,看是否由键盘输入
k = cv2.waitKey(0)

# 等待esc键退出
if k == 27:
    cv2.destroyAllWindows()
elif k == ord('s'):
    cv2.imwrite('gray.jpg', img)
    cv2.destroyAllWindows()


原创 Mar 13, 2018 6:35:03 PM 54 0

Python3读取使用本地Cookie

#!/usr/bin/python3
# coding:utf-8
# Filename:spider_study2.py
# Author:Neal
# Time:2018.03.13 10:33

import urllib.request
import http.cookiejar

"""
    读取利用cookie
"""
cookie = http.cookiejar.MozillaCookieJar()
# 加载本地磁盘的cookie文件
cookie.load('cookie.txt', ignore_discard=True, ignore_expires=True)
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
response = opener.open('http://www.baidu.com')
if response.status == 200:
    print(response.read().decode("utf-8"))


原创 Mar 13, 2018 6:33:58 PM 54 0

Python3自带爬虫库的比较

#!/usr/bin/python3
# coding:utf-8
# Filename:spider_study.py
# Author:Neal
# Time:2018.03.13 9:48
import http.cookiejar
import urllib.request
import urllib.parse

# 传入参数时,data需是bytes类型
"""
    简单打开一个url
"""

data = bytes(urllib.parse.urlencode({'name': 'jack'}), encoding='UTF-8')
response = urllib.request.urlopen("http://www.baidu.com", data=data, timeout=1)

# 第二种,使用更强的Request
"""
    可填充请求头
"""
fast = urllib.request.Request("http://www.baidu.com", headers={
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                  'Chrome/65.0.3325.146 Safari/537.36'}, method="POST")

# 这次需要传一个Request对象做为urlopen的参数
response2 = urllib.request.urlopen(fast)

# 第三种,使用高级特性,handler
"""
    可设置代理,cookie,响应的错误
"""
# 添加用户名和密码的处理器,用于处理认证
# auth_handler = urllib.request.HTTPBasicAuthHandler()
# auth_handler.add_password(realm='PDQ Application',
#                           uri="https://mahler:8092/site-updates.py",
#                           user="klem",
#                           passwd="kadidd!ehopper")

# opener = urllib.request.build_opener(auth_handler)
# urllib.request.install_opener(opener)
# urllib.request.urlopen('http://www.example.com/login.html')

# 设置代理处理器
# proxy = urllib.request.ProxyHandler({
#     'http': 'http://120.24.2471.104:80',
# })
# opener2 = urllib.request.build_opener(proxy)
# response3 = opener2.open('http://www.baidu.com')

# 获取到cookie,也直接控制台输出,或者直接保存为txt文本
# cookie = http.cookiejar.CookieJar()

filename = 'cookie.txt'
cookie = http.cookiejar.MozillaCookieJar(filename)
handler = urllib.request.HTTPCookieProcessor(cookie)
opener3 = urllib.request.build_opener(handler)
response3 = opener3.open('http://www.baidu.com')
# 保存到磁盘
cookie.save(ignore_discard=True, ignore_expires=True)

if response.status == 200 and response2.status == 200 and response3.status == 200:
    print("====================Response Content=====================")
    print(response.read().decode("utf-8"))
    print("====================Response Content=====================")
    print(response2.read().decode("utf-8"))
    print("====================Response Content=====================")
    print(response3.read().decode("utf-8"))
    print("===================Headers======================")
    for i in response.getheaders():
        print(i)
    print("==================Cookie=======================")
    for item in cookie:
        print(item.name + "=" + item.value)


原创 Mar 13, 2018 6:33:06 PM 42 0

Python3+selenium+urllib爬取知乎的登录验证码

#!/usr/bin/python3
# coding:utf-8
# Filename:get_image.py
# Author:Neal
# Time:2018.03.13 13:53

"""
    自动点击验证码图片进行验证码的刷新,
    每次的验证码保存到本地

    知乎拥有反爬虫措施:
    每个Ip估计就只能访问多少次登录
    解决方案:
    爬取大量IP地址,进行切换爬取

    爬取到的IP地址,需要进行处理,是否可用于代理
"""
import random
import urllib
from urllib.request import urlopen

from selenium import webdriver
import time

from selenium.common.exceptions import NoSuchElementException


def random_name():
    """
        随机生成一个图片名
        最后名为6字母+日期
    :return:str
    """
    word = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
            'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
            's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
    names = ''
    ticks = time.time()
    for index in range(0, 6, 1):
        names += word[random.randint(0, 25)]
    return str((repr(ticks) + names))


def refresh_and_save(web_driver, save_resource_path):
    """
    刷新验证码区域,进行图片保存
    :param save_resource_path: 保存路径
    :param web_driver: webdriver
    :return: void
    """
    # 获取到验证码区域
    try:
        img_area = web_driver.find_element_by_xpath("//div[@class='Captcha-englishContainer']/img")
    except NoSuchElementException:
        img_area = web_driver.find_element_by_xpath("//div[@class='Captcha-chineseContainer']/img")
    if img_area is not None:
        image_url = img_area.get_attribute("src")
        response = urllib.request.urlopen(image_url)
        result = response.read()
        img_name = random_name()
        with open(save_resource_path + img_name + '.jpg', 'wb') as f:
            f.write(result)
            f.flush()
            f.close()
        time.sleep(1)
        img_area.click()

"""
    1.打开连接
    2.0.分析验证码地址,以及验证码刷新按钮
    2.1.有些网站需要填写账号和密码才能有验证码出现
    3.保存验证码
    
    刷新:
    点击图片区域,进行刷新,得到下一个验证码,然后保存,再进行刷新
"""
driver = webdriver.Chrome()
driver.get("https://www.zhihu.com/signup?next=%2F")
# 最大化浏览器
driver.maximize_window()
# 转到登录页面
driver.find_element_by_xpath("//div[@class='SignContainer-switch']/span").click()
# 等待页面加载
time.sleep(1)
input_user = driver.find_element_by_xpath("//input[contains(@placeholder,'手机号或邮箱')]")
input_password = driver.find_element_by_xpath("//input[contains(@placeholder,'密码')]")
input_user.send_keys("13037479765")
input_password.send_keys('99900999')
# 点击登录
driver.find_element_by_xpath("//button[@class='Button SignFlow-submitButton Button--primary Button--blue']").click()
time.sleep(2)
save_path = "C:\\my\\resource\\img\\"

for i in range(0, 100, 1):
    refresh_and_save(driver, save_path)
    time.sleep(1)

# 退出浏览器
driver.quit()

原创 Mar 13, 2018 6:31:11 PM 51 0

数据结构学习(一)—— 线性表

package per.neal.chapter01;

/**
 * 线性表规范接口
 *
 * @author neal
 */
public interface LinearTable<T> {

    /**
     * 是否为空表
     *
     * @return boolean
     */
    boolean isEmpty();

    /**
     * 清空整个表
     */
    void clear();

    /**
     * 获取索引元素
     *
     * @param i 索引
     * @return 元素
     */
    T getElement(int i);

    /**
     * 获取线性表长度
     *
     * @return int
     */
    int length();

    /**
     * 在指定位置插入数据
     *
     * @param i       索引
     * @param element 元素
     */
    void insert(int i, T element);

    /**
     * 删除指定位置元素,并返回该元素
     *
     * @param i 索引
     * @return 元素
     */
    T delete(int i);

    /**
     * 更新指定项的数据元素
     *
     * @param i       索引
     * @param element 元素
     */
    void setElement(int i, T element);

    /**
     * 查找判断是否还有该元素
     *
     * @param element 元素
     * @return boolean
     */
    T haveElement(T element);

    /**
     * 在线性表末尾添加元素
     *
     * @param element 元素
     */
    void add(T element);
}


package per.neal.chapter01;


/**
 * 线性表
 *
 * @author neal
 */
public class LinearTableImpl<T> implements LinearTable<T> {
    /**
     * 表容器
     */
    private T[] data;

    /**
     * 线性表长度
     */
    private int length;

    /**
     * 指定长度的线性表
     *
     * @param size 容量
     */
    @SuppressWarnings("unchecked")
    public LinearTableImpl(int size) {
        this.data = (T[]) new Object[size];
        this.length = 0;
    }

    /**
     * 默认构造的16长度的线性表
     */
    public LinearTableImpl() {
        this(16);
    }

    @Override
    public boolean isEmpty() {
        return this.length == 0;
    }

    @Override
    public void clear() {
        for (int i = 0; i < this.length; i++) {
            this.data[i] = null;
        }
        this.length = 0;
    }

    @Override
    public T getElement(int i) {
        if (i < 0 || i >= length) {
            throw new IndexOutOfBoundsException(i + "越界了");
        }
        return this.data[i];
    }

    @Override
    public int length() {
        return this.length;
    }

    @Override
    @SuppressWarnings("unchecked")
    public void insert(int i, T element) {
        if (i > this.length || i < 0) {
            throw new IndexOutOfBoundsException(i + "越界了");
        }
        if (element == null) {
            return;
        }
        if (this.length == this.data.length) {
            T[] elements = this.data;
            this.data = (T[]) new Object[elements.length * 3 >>> 1];
            System.arraycopy(elements, 0, this.data, 0, elements.length);
        }
        System.arraycopy(this.data, i, this.data, i + 1, this.length - i);
        this.data[i] = element;
        this.length++;
    }

    @Override
    public T delete(int i) {
        if (i < 0 || i > this.length) {
            throw new IndexOutOfBoundsException(i + "越界了");
        }
        T element = this.data[i];
        System.arraycopy(this.data, i + 1, this.data, i, this.length - 1 - i);
        this.length--;
        return element;
    }

    @Override
    public void setElement(int i, T element) {
        if (i < 0 || i > this.length) {
            throw new IndexOutOfBoundsException(i + "越界了");
        }
        if (element == null) {
            return;
        }
        this.data[i] = element;
    }

    @Override
    public T haveElement(T element) {
        int find = this.indexOf(element);
        return find == -1 ? null : this.data[find];
    }

    @Override
    public void add(T element) {
        this.insert(this.length, element);
    }

    private int indexOf(T element) {
        if (element != null) {
            for (int i = 0; i < this.length; i++) {
                if (this.data[i].equals(element)) {
                    return i;
                }
            }
        }
        return -1;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder("(");
        for (T element : this.data) {
            builder.append(element).append(",");
        }
        builder.append(")");
        return builder.toString();
    }
}


原创 Mar 4, 2018 9:12:36 AM 60 0

使用Zxing处理二维码

去maven仓库下载Google家的zxing的jar包,或者直接maven引入依赖,具体使用到了两个jar包,zxing javase.jar 还有zxing core核心jar包,下面是代码

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;

import javax.imageio.ImageIO;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.Binarizer;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.EncodeHintType;
import com.google.zxing.LuminanceSource;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.NotFoundException;
import com.google.zxing.Result;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;

/**
 * 二维码测试类
 *
 * @author 10614
 */
public class Test {
    public static void main(String[] args) throws IOException, WriterException {
//        testEncode();
        testDecode();
    }

    /**
     * 生成二维码
     *
     * @throws WriterException WriterException
     * @throws IOException     IOException
     */
    private static void testEncode() throws WriterException, IOException {
        String filePath = "D://";
        String fileName = "zxing.png";
        String content = "测试zxing生成二维码";
        // 图像宽度
        int width = 300;
        // 图像高度
        int height = 300;
        // 图像类型
        String format = "png";
        Map<EncodeHintType, Object> hints = new HashMap<>(16);
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
        // 生成矩阵
        BitMatrix bitMatrix = new MultiFormatWriter().encode(content,
                BarcodeFormat.QR_CODE, width, height, hints);
        Path path = FileSystems.getDefault().getPath(filePath, fileName);
        // 输出图像
        MatrixToImageWriter.writeToPath(bitMatrix, format, path);
        System.out.println("输出成功.");
    }

    /**
     * 解析二维码
     */
    private static void testDecode() {
        String filePath = "D:\\loginqrcode.jpg";
        BufferedImage image;
        try {
            image = ImageIO.read(new File(filePath));
            LuminanceSource source = new BufferedImageLuminanceSource(image);
            Binarizer binarizer = new HybridBinarizer(source);
            BinaryBitmap binaryBitmap = new BinaryBitmap(binarizer);
            Map<DecodeHintType, Object> hints = new HashMap<>(16);
            hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");
            // 对图像进行解码
            Result result = new MultiFormatReader().decode(binaryBitmap, hints);
            System.out.println("图片中内容:  ");
            System.out.println("author: " + result.getText());
            System.out.println("图片中格式:  ");
            System.out.println("encode: " + result.getBarcodeFormat());
        } catch (IOException | NotFoundException e) {
            e.printStackTrace();
        }
    }
}


原创 Feb 27, 2018 10:34:37 AM 81 1

封装Lucene日常操作

使用包装类对象,进行操作,请注意!!!

import com.neal.myblog.entity.TArticleVO;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;

import java.io.IOException;
import java.nio.file.Paths;

/*
   1.写一段传统的JDBC程序,将每条的用户信息从数据库读取出来
   2.针对每条用户记录,建立一个lucene document
        Document doc = new Document();
   3.并根据你的需要,将用户信息的各个字段对应luncene document中的field 进行添加,如:
        doc.add(new Field(“NAME”,”USERNAME”,Field.Store.YES,Field.Index.UN_TOKENIZED));
   4.然后将该条doc加入到索引中, 如: luceneWriter.addDocument(doc);
        这样就建立了lucene的索引库
   5.编写对索引库的搜索程序(看lucene文档),通过对lucene的索引库的查找,你可以快速找到对应记录的ID
   6.通过ID到数据库中查找相关记录
*/

/**
 * Lucene数据装填
 *
 * @author Neal
 */
public class DataBaseIndexUtil {

    /**
     * 设置默认索引位置
     */
    private static final String INDEX_PATH = "D://indexFile//dbIndex";
    private static Directory dir;
    private static Analyzer analyzer;
    private static IndexWriter writer;

    private DataBaseIndexUtil() {
        throw new AssertionError();
    }

    /**
     * 将Document对象更新索引(默认根据文章ID更新),用于文章更新时,对应的索引也应该更新
     *
     * @param tArticleVO TArticleVO
     * @throws IOException IOException
     */
    public static void updateIndex(TArticleVO tArticleVO) throws IOException {
        dir = FSDirectory.open(Paths.get(INDEX_PATH));
        analyzer = new StandardAnalyzer();
        IndexWriterConfig iwc = new IndexWriterConfig(analyzer);
        iwc.setOpenMode(IndexWriterConfig.OpenMode.APPEND);
        writer = new IndexWriter(dir, iwc);
        writer.updateDocument(new Term("article_id", tArticleVO.gettArticleEX().getArticleId() + ""), getDoc(tArticleVO));
        writer.commit();
        writer.close();
    }

    /**
     * 增加索引,用于文章发布时,添加对应索引
     *
     * @param tArticleVO TArticleVO
     * @throws IOException IOException
     */
    public static void addIndex(TArticleVO tArticleVO) throws IOException {
        dir = FSDirectory.open(Paths.get(INDEX_PATH));
        analyzer = new StandardAnalyzer();
        IndexWriterConfig iwc = new IndexWriterConfig(analyzer);
        iwc.setOpenMode(IndexWriterConfig.OpenMode.CREATE_OR_APPEND);
        writer = new IndexWriter(dir, iwc);
        writer.addDocument(getDoc(tArticleVO));
        writer.commit();
        writer.close();
    }

    /**
     * 删除指定索引,用于文章删除时,对应索引也应该删除
     *
     * @throws IOException IOException
     */
    public static void deleteIndex(long articleId) throws IOException {
        dir = FSDirectory.open(Paths.get(INDEX_PATH));
        analyzer = new StandardAnalyzer();
        IndexWriterConfig iwc = new IndexWriterConfig(analyzer);
        writer = new IndexWriter(dir, iwc);
        writer.deleteDocuments(new Term("article_id", articleId + ""));
        writer.commit();
        writer.close();
    }

    /**
     * 返回一个更新后的Document对象,用于更新,添加索引
     *
     * @param tArticleVO TArticleVO,包装类
     * @return Document
     */
    private static Document getDoc(TArticleVO tArticleVO) {
        Document doc = new Document();
        doc.add(new TextField("article_id", tArticleVO.gettArticleEX().getArticleId() + "", Field.Store.YES));
        doc.add(new TextField("article_title", tArticleVO.gettArticleEX().getArticleTitle() + "", Field.Store.YES));
        doc.add(new TextField("article_time", tArticleVO.gettArticleEX().getArticleTime() + "", Field.Store.YES));
        doc.add(new TextField("article_content", tArticleVO.gettArticleEX().getArticleContent() + "", Field.Store.YES));
        doc.add(new TextField("article_tag", tArticleVO.gettArticleEX().getArticleTag() + "", Field.Store.YES));
        doc.add(new TextField("category_name", tArticleVO.gettCategory().getCategoryName() + "", Field.Store.YES));
        return doc;
    }
}

当然,还有测试查询

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;

import java.io.IOException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;


/**
 * Lucene数据查找
 *
 * @author dell
 */
public class DataBaseSearcherUtil {

    /**
     * 默认索引位置
     */
    private static final String INDEX_PATH = "D://indexFile//dbIndex";

    private DataBaseSearcherUtil() {
        throw new AssertionError();
    }

    /**
     * 返回文章ID list
     *
     * @param file     确认搜索的域
     * @param keywords 关键字
     * @param num      搜素深度
     * @return List
     * @throws IOException    IOException
     * @throws ParseException ParseException
     */
    public static List<String> searchData(String file, String keywords, int num) throws IOException, ParseException {
        Directory dir;
        dir = FSDirectory.open(Paths.get(INDEX_PATH));
        IndexReader reader = DirectoryReader.open(dir);
        IndexSearcher searcher = new IndexSearcher(reader);
        Analyzer analyzer = new StandardAnalyzer();
        QueryParser parser = new QueryParser(file, analyzer);
        parser.setDefaultOperator(QueryParser.AND_OPERATOR);
        Query query = parser.parse(keywords);
        TopDocs hits = searcher.search(query, num);
        List<String> list = new ArrayList<>();
        for (ScoreDoc scoreDoc : hits.scoreDocs) {
            Document doc = searcher.doc(scoreDoc.doc);
            list.add(doc.get("article_id"));
        }
        System.out.println("有效的索引文档:" + reader.numDocs());
        System.out.println("删掉的索引文档:" + reader.numDeletedDocs());
        return list;
    }

    public static void main(String[] args) {
        try {
            List<String> list = searchData("article_content", "nothing", 100);
            System.out.println(list.size());
        } catch (IOException | ParseException e) {
            e.printStackTrace();
        }
    }
}

当然,你需要这样使用

/**
     * 客户端关键字搜索
     *
     * @param keywords 关键字
     * @param modelMap ModelMap
     * @return 视图
     * @throws IOException    IOException
     * @throws ParseException ParseException
     */
    @RequestMapping(value = "/searchArticleToRead", method = RequestMethod.POST)
    public String searchArticleToRead(String keywords, ModelMap modelMap) throws IOException, ParseException {
        List<String> list = DataBaseSearcherUtil.searchData("article_content", keywords, 10);
        // 如果在文章内容没搜索到,则转到搜索标题,标题没搜索到,就搜索文章属性
        if (list.size() == 0) {
            list = DataBaseSearcherUtil.searchData("article_title", keywords, 10);
            if (list.size() == 0) {
                list = DataBaseSearcherUtil.searchData("category_name", keywords, 10);
            }
        }
        List<TArticleVO> articleVOS = new ArrayList<>();
        if (list.size() > 0) {
            for (String articleId : list) {
                //将查询的ID索引,进行数据库查询,返回文章list
                articleVOS.add(articleByVisitorService.getArticleById(Long.parseLong(articleId)));
            }
        }
        modelMap.addAttribute("articleVOS", articleVOS);
        // 调用数据库的侧边栏查询
        asideContent(modelMap);
        return "page/index";
    }


原创 Feb 8, 2018 9:35:55 PM 71 0

Java模拟浏览器发送请求

话不多说,看代码

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * 伪装浏览器
 *
 * @author neal
 */
public class MaskBrowser {
    public static void main(String[] args) throws IOException {
        HttpURLConnection conn = null;
        try {
            URL readUrl = new URL("需要登录的URL");
            conn = (HttpURLConnection) readUrl.openConnection();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //连接不能为空
        assert conn != null;
        //设置Post方法
        conn.setRequestMethod("POST");
        //不适用缓存
        conn.setUseCaches(false);
        //发送POST请求需要设置一下两行
        conn.setDoOutput(true);
        conn.setDoInput(true);
        //读取超时时间
        conn.setReadTimeout(8000);
        //设置连接时间
        conn.setReadTimeout(8000);
        //设置不要302自动跳转
        conn.setInstanceFollowRedirects(false);
        //设置请求头
        conn.setRequestProperty("User-Agent"
                , "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36");
        conn.setRequestProperty("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
        conn.setRequestProperty("Accept-Encoding", "gzip, deflate");
        conn.setRequestProperty("Accept-Language", "zh-CN,zh;q=0.9");
        conn.setRequestProperty("Cache-Control", "max-age=0");
        conn.setRequestProperty("Connection", "keep-alive");
        conn.setRequestProperty("Cookie", "Hm_lvt_d131e80dbe4e2a6df483fc811164f418=1517996742,1518090993; JSESSIONID=021244182EEC605D1A5F2C6B031EBC51");
        conn.setRequestProperty("Host", "请自行输入");
        conn.setRequestProperty("Referer", "请自行输入");
        conn.setRequestProperty("Upgrade-Insecure-Requests", "1");
        //设置Post参数
        String pars = "username=用户&password=你的密码";
        PrintWriter out = new PrintWriter(conn.getOutputStream());
        out.print(pars);
        out.flush();

        int n = conn.getResponseCode();
        if (n == 200) {
            InputStream is = conn.getInputStream();
            BufferedReader in = new BufferedReader(new InputStreamReader(is, "UTF-8"));
            StringBuilder buffer = new StringBuilder();
            String line;
            while ((line = in.readLine()) != null) {
                buffer.append(line).append("\r\n");
            }
            String result = buffer.toString();
            System.out.println(result);
        }
    }
}

只是可以简单模拟一下登录,拿到登录后的内容,无法绕过验证码......有待提高

原创 Feb 8, 2018 9:27:07 PM 57 0

从数据库到JavaBean,配置使用

请看官大老爷看代码

package com.neal.main.domain;

import java.io.*;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

/**
 * 从数据库到JavaBean
 *
 * @author Neal
 */
public class TableConfiguration {
    /**
     * 配置文件位置
     */
    private String propertyName;
    /**
     * 实体类生成所在包的路径
     */
    private String packageOutPath;
    /**
     * 作者名
     */
    private String authorName;
    /**
     * 表名
     */
    private String tableName;
    /**
     * 数据库名
     */
    private String databaseName;
    /**
     * 拿到对应数据库中所有实体类(实体类需要与其他表名做区分)
     */
    private List<String> tableNames;
    /**
     * 列名(字段)集合
     */
    private List<String> columnNames;
    /**
     * 列名类型集合
     */
    private List<String> columnTypeNames;
    /**
     * 是否需要导入java.util.*
     */
    private boolean fUtil = false;
    /**
     * 是否需要导入java.sql.*
     */
    private boolean fSql = false;

    /**
     * 构造,初始化
     */
    private TableConfiguration(String propertyName) {
        this.propertyName = propertyName;
        // 使用Properties类读取reverse.properties配置文件
        Properties properties = new Properties();
        try (InputStream inputStream = getClass().getResourceAsStream(propertyName)) {
            properties.load(inputStream);
        } catch (IOException e) {
            System.out.println("没找到这个配置文件 " + e);
        }
        this.databaseName = properties.getProperty("database");
        this.tableName = properties.getProperty("table");
        this.packageOutPath = properties.getProperty("package");
        this.authorName = properties.getProperty("author");
    }

    /**
     * 创建多个实体类
     */
    private void genEntity(List<String> tableNames, Connection connection) {
        //递归生成文件
        for (String tableName : tableNames) {
            this.genEntity(tableName, connection);
        }
    }

    /**
     * 创建单个实体类
     */
    private void genEntity(String tableName, Connection connection) {
        fUtil = false;
        fSql = false;
        String sql = "SELECT * FROM " + tableName;
        try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
            ResultSetMetaData setMetaData = preparedStatement.getMetaData();
            // 统计字段(列)
            int size = setMetaData.getColumnCount();
            columnNames = new ArrayList<>();
            columnTypeNames = new ArrayList<>();

            for (int i = 0; i < size; i++) {
                columnNames.add(setMetaData.getColumnName(i + 1));
                columnTypeNames.add(setMetaData.getColumnTypeName(i + 1));
                if ("DATETIME".equalsIgnoreCase(columnTypeNames.get(i))) {
                    fUtil = true;
                }
                if ("IMAGE".equalsIgnoreCase(columnTypeNames.get(i))
                        || "TEXT".equalsIgnoreCase(columnTypeNames.get(i))
                        || "TIMESTAMP".equalsIgnoreCase(columnTypeNames.get(i))) {
                    fSql = true;
                }
            }
            System.out.println(columnNames);
            System.out.println(columnTypeNames);
        } catch (SQLException e) {
            System.out.println("未拿到字段集" + e);
        }
        // 将代码写入内存中去
        String content = parse(tableName);

        // 写入文件
        try {
            File directory = new File("");
            String outputPath = directory.getAbsolutePath() + "/src/"
                    + this.packageOutPath.replace(".", "/")
                    + "/";
            System.out.println("路径为:" + outputPath);
            //路径检查,不存在则创建
            File path = new File(outputPath);
            if (!path.exists()) {
                if (path.mkdir()) {
                    System.out.println("路径已被创建");
                }
            }
            System.out.println(path.exists());
            outputPath += initSml(initCap(tableName)) + ".java";
            File file = new File(outputPath);
            if (!file.exists()) {
                if (file.createNewFile()) {
                    System.out.println("文件已被创建");
                }
            }
            //写入到磁盘
            FileWriter fw = new FileWriter(file);
            PrintWriter pw = new PrintWriter(fw);
            // 将内存中的数据写入磁盘
            pw.println(content);
            pw.flush();
            pw.close();
            fw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void getAllEntityTable(Connection connection) {
        ResultSet rs;
        try {
            DatabaseMetaData dmd = connection.getMetaData();
            /*
             * TABLE_CAT String ==> 表类别(可为null)
             * TABLE_MODE String ==> 表模式(可为null)
             * TABLE_NAME String ==> 表名称
             * TABLE_TYPE String ==> 表类型
             * */
            rs = dmd.getTables(null, null, "%", null);
            while (rs.next()) {
                tableNames.add(rs.getString("TABLE_NAME"));
            }
            rs.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    /**
     * 写入注释
     *
     * @param tableName 表名
     * @return 注释
     */
    private String parse(String tableName) {
        StringBuffer sb = new StringBuffer();
        sb.append("package ").append(this.packageOutPath).append(";\r\n");
        sb.append("\r\n");
        if (fUtil) {
            sb.append("import java.util.*;\r\n");
        }
        if (fSql) {
            sb.append("import java.sql.*;\r\n");
        }
        sb.append("\r\n");
        //注释部分
        sb.append("/**\r\n");
        sb.append(" * ").append(tableName).append("实体类\r\n");
        sb.append(" *\r");
        sb.append(" * @author ").append(this.authorName).append(" ")
                .append(new Timestamp(System.currentTimeMillis())).append("\r\n");
        sb.append(" */");

        //实体部分
        sb.append("\npublic class ").append(initSml(initCap(tableName))).append(" {\r\n");
        // 实体类属性
        processAllAttrs(sb);
        // get set方法
        processAllMethod(sb);
        sb.append("}\n");
        return sb.toString();
    }

    /**
     * 写入实体类属性
     *
     * @param sb StringBuffer
     */
    private void processAllAttrs(StringBuffer sb) {
        for (int i = 0; i < columnNames.size(); i++) {
            sb.append("\tprivate ").append(sqlTypeToJavaType(columnTypeNames.get(i)))
                    .append(" ").append(initSml(columnNames.get(i))).append(";\r\n");
        }
    }

    /**
     * 写入GET,SET方法
     *
     * @param sb StringBuffer
     */
    private void processAllMethod(StringBuffer sb) {
        for (int i = 0; i < columnNames.size(); i++) {
            sb.append("\r\tpublic void set").append(initSml(initCap(columnNames.get(i) + "(")))
                    .append(sqlTypeToJavaType(columnTypeNames.get(i)))
                    .append(" ").append(initSml(columnNames.get(i))).append(") {\r\n");
            sb.append("\t\tthis.").append(initSml(columnNames.get(i)))
                    .append(" = ").append(initSml(columnNames.get(i)))
                    .append(";\r\n");
            sb.append("\t}\n");
            sb.append("\n");
            sb.append("\tpublic ").append(sqlTypeToJavaType(columnTypeNames.get(i)))
                    .append(" get").append(initSml(initCap(initCap(columnNames.get(i)))))
                    .append("() {\r\n");
            sb.append("\t\treturn ").append(initSml(columnNames.get(i))).append(";\r\n");
            sb.append("\t}\r\n");
        }
    }

    /**
     * 将输入字符串的首字母改成大写
     *
     * @param str 字符串
     * @return 开头大写的字符串
     */
    private String initCap(String str) {
        char[] ch = str.toCharArray();
        final char startChar = 'a';
        final char endChar = 'z';
        if (ch[0] >= startChar && ch[0] <= endChar) {
            ch[0] -= 32;
        }
        return new String(ch);
    }

    /**
     * 将字符串‘_’删除后,后一位转成大写
     *
     * @param str 字符串
     * @return String
     */
    private String initSml(String str) {
        char[] ch = str.toCharArray();
        List<Character> list = new ArrayList<>();
        for (int i = 0, j = 0; i < ch.length; i++, j++) {
            if (ch[i] == '_') {
                if (i < ch.length - 1) {
                    if (ch[i + 1] >= 'A' && ch[i + 1] <= 'Z') {
                        list.add(ch[i + 1]);
                    } else {
                        list.add((char) (ch[i + 1] - 32));
                    }
                    i++;
                } else {
                    break;
                }
            } else {
                list.add(ch[i]);
            }
        }
        char[] c = new char[list.size()];
        for (int i = 0; i < list.size(); i++) {
            c[i] = list.get(i);
        }
        return new String(c);
    }

    /**
     * 数据库类型映射Java类型
     *
     * @param sqlType 字符串转类型
     * @return String
     */
    private String sqlTypeToJavaType(String sqlType) {
        final String bit = "bit";
        final String tinyint = "tinyint";
        final String smallint = "smallint";
        final String newInt = "int";
        final String bigint = "bigint";
        final String newFloat = "float";
        final String numeric = "numeric";
        final String decimal = "decimal";
        final String real = "real";
        final String money = "money";
        final String varchar = "varchar";
        final String newChar = "char";
        final String nvarchar = "nvarchar";
        final String nchar = "nchar";
        final String text = "text";
        final String datetime = "datetime";
        final String image = "image";
        final String timestamp = "Timestamp";
        if (bit.equalsIgnoreCase(sqlType)) {
            return "boolean";
        } else if (tinyint.equalsIgnoreCase(sqlType)) {
            return "byte";
        } else if (smallint.equalsIgnoreCase(sqlType)) {
            return "short";
        } else if (newInt.equalsIgnoreCase(sqlType)
                || bigint.equalsIgnoreCase(sqlType)) {
            return "long";
        } else if (newFloat.equalsIgnoreCase(sqlType)) {
            return "float";
        } else if (decimal.equalsIgnoreCase(sqlType)
                || numeric.equalsIgnoreCase(sqlType)
                || real.equalsIgnoreCase(sqlType)
                || money.equalsIgnoreCase(sqlType)) {
            return "double";
        } else if (varchar.equalsIgnoreCase(sqlType)
                || newChar.equalsIgnoreCase(sqlType)
                || nvarchar.equalsIgnoreCase(sqlType)
                || nchar.equalsIgnoreCase(sqlType)
                || text.equalsIgnoreCase(sqlType)) {
            return "String";
        } else if (datetime.equalsIgnoreCase(sqlType)) {
            return "Date";
        } else if (image.equalsIgnoreCase(sqlType)) {
            return "Blob";
        } else if (timestamp.equalsIgnoreCase(sqlType)) {
            return "Timestamp";
        }
        return null;
    }

    /**
     * 调用此方法启动
     */
    private void start() {
        Properties properties = new Properties();
        InputStream inputStream = getClass().getResourceAsStream(propertyName);
        try {
            properties.load(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
        String driver = properties.getProperty("driver");
        String user = properties.getProperty("user");
        String url = properties.getProperty("url");
        String pass = properties.getProperty("password");
        Connection conn = null;
        try {
            Class.forName(driver);
            conn = DriverManager.getConnection(url, user, pass);
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
        if (databaseName != null && !"".equals(databaseName)
                && tableName != null && !"".equals(tableName)) {
            System.out.println("databaseName 和 tableName 不能同时存在");
        } else {
            // 如果配置文件中有数据库名字,则可以拿到其他其中所有的实体类
            if (databaseName != null && !"".equals(databaseName)) {
                // 获取所有实体表名字
                tableNames = new ArrayList<>();
                if (conn != null) {
                    getAllEntityTable(conn);
                }
                System.out.println(tableNames);
                // 为每个实体表生成实体类
                genEntity(tableNames, conn);
            } else {
                genEntity(tableName, conn);
            }
        }
        try {
            if (conn != null) {
                conn.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    /**
     * 出口
     */
    public static void main(String[] args) {
        new TableConfiguration("../resource/reverse.properties").start();
    }
}

当然,你可能需要说明书

#reversetable
将数据库中的表,逆向生成Java实体类(JavaBean)

填充配置文件,名字随意,具体配置如下

`驱动`
driver=com.mysql.jdbc.Driver

`URL地址`
url=jdbc:mysql://localhost:3306/xxx?useUnicode=true&characterEncoding=UTF-8

`数据库用户名`
user=root

`数据库密码`
password=xx

`具体逆向表(目前只能单一导入)`
table=t_article

`用于标识是否将该数据库下的所有表全部逆向生成实体类,
非具体数据库名,具体数据库名在URL需要填写`
database=xxx

`需要存入到的包`
package=com.neal.main.entity

`作者注释信息`
author=Neal

然后再new一个TableConfiguration的带配置文件路径的有参对象,调用start()方法启动

目前支持的字段类型有
"bit"
"tinyint"
"smallint"
"int"
"bigint"
"float"
"numeric"
"decimal"
"real"
"money"
"varchar"
"char"
"nvarchar"
"nchar"
"text"
"datetime"
"image"
"Timestamp"
可自行修改源码进行添加,修改sqlTypeToJavaType()方法,即可

配置如下,当然别忘了导入数据库连接的jar包



原创 Feb 8, 2018 8:19:03 PM 86 3

Ubuntu配置JDK

更新系统

执行一下命令以使用最新的修补程序和更新来更新系统

sudo apt-get update && sudo apt-get upgrade -y
下载配置最新jdk

先必须安装Python软件属性才能安装最新的Java 8.运行一下命令安装此软件

sudo apt-get install python-software-properties

记得按Y继续安装。安装完成后,执行一下命令,将webupd8team java ppa存储库添加到系统中

sudo add-apt-repository ppa:webupd8team/java

请求时,需要按Enter键继续。现在可以使用命令安装最新版本的Java 8了。

首先还是第一步,更新一下软件包列表

sudo apt-get update

然后再使用以下命令安装最新版本的Oracle Java 8

sudo apt-get install oracle-java8-installer

在下载的同时,需要同意许可证,请注意确认。

检查Jdk是否已经安装完成

请输入一下命令进行检查

java -version 
javac -version
java
javac

现在你已经成功安装好了JDK8了。

哦 对了,如果你要配置Tomcat的话,这种方式安装Jdk的位置在 /usr/lib/jvm/java-8-oracle/ 目录下。

原创 Feb 1, 2018 1:20:17 PM 165 1

Java面试常考题

问题:​​A线程输出10次,B线程输出100次,再A线程输出10次, 再B线程线程输入100次,如此循环50次,请写出程序.
public class TraditionalThreadTest {
    private static class SugThread {
        /**
         * 信号
         */
        private boolean isFree = false;

        private synchronized void sub(int i) {
            while (isFree) {
                try {
                    // 主等待 让出锁
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            for (int j = 1; j <= 10; j++) {
                System.out.println("sub thread " + j + " is " + i);
            }
            isFree = true;
            // 子 释放锁
            this.notify();
        }

        private synchronized void main(int i) {
            while (!isFree) {
                try {
                    // 子等待 让出锁
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            for (int j = 1; j <= 100; j++) {
                System.out.println("main thread " + j + " is " + i);
            }
            isFree = false;
            // 主 释放锁
            this.notify();
        }
    }

    public static void main(String[] args) {
        SugThread sugThread = new SugThread();
        new Thread(() -> {
            for (int i = 1; i <= 50; i++) {
                sugThread.sub(i);
            }
        }).start();
        new Thread(() -> {
            for (int i = 1; i <= 50; i++) {
                sugThread.main(i);
            }
        }).start();
    }
}


原创 Jan 30, 2018 9:54:50 PM 91 1

Java定时器的使用Demo

import java.util.Timer;
import java.util.TimerTask;

/**
 * 定时器的使用
 *
 * @author Neal
 */
public class TimerTaskTest {
    public static void main(String[] args) {
        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("boom!!!!");
            }
            // delay:起始时间,period:间隔时间
        }, 2000, 2000);
    }
}


原创 Jan 30, 2018 9:32:56 PM 70 1

动态代理的实现

功能接口

import java.lang.reflect.Method;

/**
 * 功能
 *
 * @author Neal
 */
public interface Advice {
    /**
     * 前切点
     */
    void beforeMethod();

    /**
     * 后切点
     *
     * @param method Method
     */
    void afterMethod(Method method);
}

代理demo

import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collection;

/**
 * 动态代理测试
 *
 * @author Neal
 */
public class ProxyTest {
    public static void main(String[] args) {
        ArrayList target = new ArrayList();
        Collection<String> proxy1 = (Collection<String>) getProxy(target, new MyAdvice());
        proxy1.add("jack");
        proxy1.add("neal");
        proxy1.add("rose");
        System.out.println(proxy1.size());
        System.out.println(proxy1.toString());
    }

    /**
     * 动态代理
     *
     * @param target 目标对象
     * @param advice 切面功能
     * @return Object
     */
    private static Object getProxy(final Object target, final Advice advice) {
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), (proxy, method, args) -> {
            advice.beforeMethod();
            proxy = method.invoke(target, args);
            advice.afterMethod(method);
            return proxy;
        });
    }
}


原创 Jan 30, 2018 9:26:15 PM 78 1

展望2018

2018来的很匆忙

  • 继续努力学习,拿到毕业证
  • 争取完成自己定的小目标
  • 认真找份好工作

祝2018,你我都有好运!

原创 Jan 19, 2018 8:11:37 PM 90 0

我的头像

黑天白夜

你懂的越多,懂你的就越少!

  • 来访数:4,422
  • 总文章:28
  • 原创数:27
  • 点赞数:8