提交了很多代码
This commit is contained in:
@@ -5,6 +5,7 @@ import java.util.Scanner;
|
||||
/**
|
||||
* @Title: PatternMatchingTest
|
||||
* @Description: 模式匹配算法
|
||||
* 来源:http://www.cnblogs.com/jiaohanhan/p/6654874.html
|
||||
* @Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2018年9月14日
|
||||
|
||||
213
src/main/java/com/pancm/arithmetic/SortTest.java
Normal file
213
src/main/java/com/pancm/arithmetic/SortTest.java
Normal file
@@ -0,0 +1,213 @@
|
||||
package com.pancm.arithmetic;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @author ZERO
|
||||
* @Data 2017-5-31 下午5:30:29
|
||||
* @Description 数组排序算法 主要是冒泡、二分和快速排序
|
||||
*/
|
||||
public class SortTest {
|
||||
|
||||
/**
|
||||
* @param args
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
|
||||
int[] t={1,44,55,22,34,88,3};
|
||||
for(int i=0,j=t.length;i<j;i++){
|
||||
System.out.println("排序之前:"+t[i]);
|
||||
}
|
||||
// long a=System.currentTimeMillis();
|
||||
// int[] k=ps(t);
|
||||
// for(int i=0,j=k.length;i<j;i++){
|
||||
// System.out.println("插入排序之后:"+k[i]);
|
||||
// }
|
||||
//
|
||||
int[] s=crps(t);
|
||||
for(int i=0,j=s.length;i<j;i++){
|
||||
System.out.println("插入排序倒叙之后:"+s[i]);
|
||||
}
|
||||
|
||||
|
||||
// System.out.println("\r<br>执行耗时 : "+(System.currentTimeMillis()-a)+"毫秒 ");
|
||||
// int[] p=sort(t);
|
||||
// for(int i=0,j=p.length;i<j;i++){
|
||||
// System.out.println("二分法排序之后:"+p[i]);
|
||||
// }
|
||||
//
|
||||
// int[] l=mp(t);
|
||||
// for(int i=0,j=l.length;i<j;i++){
|
||||
// System.out.println("冒泡排序之后:"+l[i]);
|
||||
// }
|
||||
//
|
||||
int[] mpdx=mpdx(t);
|
||||
for(int i=0,j=mpdx.length;i<j;i++){
|
||||
System.out.println("冒泡排序倒叙之后:"+mpdx[i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < t.length; i++) {
|
||||
System.out.print(t[i]+" ");
|
||||
}
|
||||
//快速排序
|
||||
quick(t);
|
||||
System.out.println();
|
||||
System.out.println("快速排序之后:");
|
||||
for (int i = 0; i < t.length; i++) {
|
||||
System.out.print(t[i]+" ");
|
||||
}
|
||||
|
||||
Arrays.sort(t);
|
||||
// for(int i:t){
|
||||
// System.out.println("快速排序之升序:"+i);
|
||||
// }
|
||||
// for(int j=t.length-1;0<=j;j--){
|
||||
// System.out.println("快速排序之降序:"+t[j]);
|
||||
// }
|
||||
// System.out.println("\r<br>执行耗时 : "+(System.currentTimeMillis()-a)+"毫秒 ");
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入排序 升序
|
||||
* 插入排序是循环数组,然后将前一位的数字和后一位的进行比较,将数值大的向后移一位
|
||||
* @param a
|
||||
* @return
|
||||
*/
|
||||
public static int[] ps(int[] a){
|
||||
for(int i=1,j=a.length;i<j;i++){
|
||||
int t=a[i];
|
||||
int k;
|
||||
for(k=i-1;k>=0;k--){
|
||||
if(a[k]>t){
|
||||
a[k+1]=a[k];
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
a[k+1]=t;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入排序 降序
|
||||
* 插入排序是循环数组,然后将前一位的数字和后一位的进行比较,将数值大的向后移一位
|
||||
* @param a
|
||||
* @return
|
||||
*/
|
||||
public static int[] crps(int[] a){
|
||||
for(int i=1,j=a.length;i<j;i++){
|
||||
int t=a[i];
|
||||
int k;
|
||||
for(k=i-1;k>=0;k--){
|
||||
if(a[k]<t){
|
||||
a[k+1]=a[k];
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
a[k+1]=t;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 冒泡排序 升序
|
||||
* 冒泡排序 是双重循环数组,前一位和后一位进行比较,若前一位大于后一位,就交换位置
|
||||
*/
|
||||
public static int[] mp(int[] m){
|
||||
for(int i=0;i<m.length-1;i++){
|
||||
for(int j=i+1;j<m.length;j++){
|
||||
if(m[i]>m[j]){
|
||||
int tmp=m[i];
|
||||
m[i]=m[j];
|
||||
m[j]=tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* 冒泡排序 倒序
|
||||
* 冒泡排序 是双重循环数组,前一位和后一位进行比较,若前一位大于后一位,就交换位置
|
||||
*/
|
||||
public static int[] mpdx(int[] a){
|
||||
for(int i=0;i<a.length-1;i++){
|
||||
for(int j=i+1;j<a.length;j++){
|
||||
if(a[i]<a[j]){
|
||||
int tmp=a[i];
|
||||
a[i]=a[j];
|
||||
a[j]=tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
/**
|
||||
* 二分法排序 升序
|
||||
* @param a
|
||||
* @return
|
||||
*/
|
||||
public static int[] sort(int[] a) {
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
int temp = a[i];
|
||||
int left = 0;
|
||||
int right = i-1;
|
||||
int mid = 0;
|
||||
while(left<=right){
|
||||
mid = (left+right)/2;
|
||||
if(temp<a[mid]){
|
||||
right = mid-1;
|
||||
}else{
|
||||
left = mid+1;
|
||||
}
|
||||
}
|
||||
for (int j = i-1; j >= left; j--) {
|
||||
a[j+1] = a[j];
|
||||
}
|
||||
if(left != i){
|
||||
a[left] = temp;
|
||||
}
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
/**
|
||||
* 快速排序
|
||||
* @param a
|
||||
*/
|
||||
private static void quick(int[] a) {
|
||||
if(a.length>0){
|
||||
quickSort(a,0,a.length-1);
|
||||
}
|
||||
}
|
||||
|
||||
private static void quickSort(int[] a, int low, int high) {
|
||||
if(low<high){ //如果不加这个判断递归会无法退出导致堆栈溢出异常
|
||||
int middle = getMiddle(a,low,high);
|
||||
quickSort(a, 0, middle-1);
|
||||
quickSort(a, middle+1, high);
|
||||
}
|
||||
}
|
||||
|
||||
private static int getMiddle(int[] a, int low, int high) {
|
||||
int temp = a[low];//基准元素
|
||||
while(low<high){
|
||||
//找到比基准元素小的元素位置
|
||||
while(low<high && a[high]>=temp){
|
||||
high--;
|
||||
}
|
||||
a[low] = a[high];
|
||||
while(low<high && a[low]<=temp){
|
||||
low++;
|
||||
}
|
||||
a[high] = a[low];
|
||||
}
|
||||
a[low] = temp;
|
||||
return low;
|
||||
}
|
||||
|
||||
}
|
||||
56
src/main/java/com/pancm/basics/ExtendTest.java
Normal file
56
src/main/java/com/pancm/basics/ExtendTest.java
Normal file
@@ -0,0 +1,56 @@
|
||||
package com.pancm.basics;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @Title: ExtendTest
|
||||
* @Description:
|
||||
* 继承测试
|
||||
* @Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2018年3月27日
|
||||
*/
|
||||
public class ExtendTest {
|
||||
|
||||
public static void main(String[] args) {
|
||||
Cat1 cat=new Cat1();
|
||||
Dog1 dog=new Dog1();
|
||||
cat.eat();
|
||||
cat.sleep("cat");
|
||||
cat.climbTree();
|
||||
dog.eat("dog");
|
||||
dog.sleep("dog");
|
||||
}
|
||||
}
|
||||
|
||||
class Animal1{
|
||||
public void eat(String name){
|
||||
System.out.println(name+"正在吃东西...");
|
||||
}
|
||||
public void sleep(String name){
|
||||
System.out.println(name+"正在睡觉...");
|
||||
}
|
||||
}
|
||||
|
||||
class Cat1 extends Animal1{
|
||||
private String name="Cat";
|
||||
public void eat(){
|
||||
super.eat(name);
|
||||
System.out.println(name+"吃完了");
|
||||
}
|
||||
public void sleep(){
|
||||
this.sleep(name);
|
||||
}
|
||||
|
||||
public void sleep(String name){
|
||||
System.out.println(name+"刚刚睡觉!");
|
||||
}
|
||||
|
||||
public void climbTree(){
|
||||
System.out.println(name+"正在爬树!");
|
||||
}
|
||||
}
|
||||
|
||||
class Dog1 extends Animal1{
|
||||
|
||||
}
|
||||
@@ -1,10 +1,14 @@
|
||||
package com.pancm.basics;
|
||||
|
||||
/**
|
||||
* @author ZERO
|
||||
* @Data 2017-6-2 上午11:46:45
|
||||
* @Description 继承测试 经典题
|
||||
*
|
||||
* @Title: ExtendsTest2
|
||||
* @Description: 继承测试 经典题
|
||||
* @Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年6月2日
|
||||
*/
|
||||
public class ExtendsTest {
|
||||
public class ExtendsTest2 {
|
||||
public static void main(String[] args) {
|
||||
A a1 = new A();
|
||||
A a2 = new B();
|
||||
43
src/main/java/com/pancm/basics/FinalTest.java
Normal file
43
src/main/java/com/pancm/basics/FinalTest.java
Normal file
@@ -0,0 +1,43 @@
|
||||
package com.pancm.basics;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: FinalTest
|
||||
* Description:
|
||||
* final测试
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2018年3月21日
|
||||
*/
|
||||
public class FinalTest{
|
||||
//定义一个final修饰的变量
|
||||
public static final String name="xuwujing";
|
||||
|
||||
public static void main(String[] args) {
|
||||
//这句会报错 因为该变量已经被final修饰了
|
||||
// name="张三";
|
||||
}
|
||||
//类加上final之后,该类是无法被继承的
|
||||
final class Test2{
|
||||
}
|
||||
//这句会报错,因为Test2是被final修饰的类
|
||||
// class Test3 extends Test2{
|
||||
// }
|
||||
|
||||
class Test4{
|
||||
//定义一个被final修饰的方法
|
||||
final Date getTime(){
|
||||
return new Date();
|
||||
}
|
||||
}
|
||||
|
||||
class Test5 extends Test4{
|
||||
//这句会报错,因为final方法是不能被子类修改的。
|
||||
// Date getTime(){
|
||||
// return new Date();
|
||||
// }
|
||||
}
|
||||
}
|
||||
42
src/main/java/com/pancm/basics/PackagingTest.java
Normal file
42
src/main/java/com/pancm/basics/PackagingTest.java
Normal file
@@ -0,0 +1,42 @@
|
||||
package com.pancm.basics;
|
||||
|
||||
/**
|
||||
*
|
||||
* @Title: PackagingTest
|
||||
* @Description:
|
||||
* 封装
|
||||
* @Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2018年3月27日
|
||||
*/
|
||||
public class PackagingTest {
|
||||
|
||||
public static void main(String[] args) {
|
||||
User9 user=new User9();
|
||||
//这里会报错,因为id和name是私有的,用于保护该数据
|
||||
// user.id=10;
|
||||
// user.name="张三";
|
||||
user.setId(1);
|
||||
user.setName("张三");
|
||||
System.out.println(user.getId());
|
||||
System.out.println(user.getName());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class User9{
|
||||
private int id;
|
||||
private String name;
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
43
src/main/java/com/pancm/basics/PolymorphicTest.java
Normal file
43
src/main/java/com/pancm/basics/PolymorphicTest.java
Normal file
@@ -0,0 +1,43 @@
|
||||
package com.pancm.basics;
|
||||
|
||||
/**
|
||||
*
|
||||
* @Title: PolymorphicTest
|
||||
* @Description: 多态测试
|
||||
* @Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2018年3月27日
|
||||
*/
|
||||
public class PolymorphicTest {
|
||||
|
||||
public static void main(String[] args) {
|
||||
Animal2 animal = new Cat2();
|
||||
animal.eat();
|
||||
}
|
||||
}
|
||||
|
||||
class Animal2 {
|
||||
private String name = "Animal";
|
||||
|
||||
public void eat() {
|
||||
System.out.println(name + "正在吃东西...");
|
||||
sleep();
|
||||
}
|
||||
|
||||
public void sleep() {
|
||||
System.out.println(name + "正在睡觉...");
|
||||
}
|
||||
}
|
||||
|
||||
class Cat2 extends Animal2 {
|
||||
private String name = "Cat";
|
||||
|
||||
public void eat(String name) {
|
||||
System.out.println(name + "吃完了");
|
||||
sleep();
|
||||
}
|
||||
|
||||
public void sleep() {
|
||||
System.out.println(name + "正在睡觉");
|
||||
}
|
||||
}
|
||||
79
src/main/java/com/pancm/basics/ReflectTest.java
Normal file
79
src/main/java/com/pancm/basics/ReflectTest.java
Normal file
@@ -0,0 +1,79 @@
|
||||
package com.pancm.basics;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: ReflectTest
|
||||
* Description:
|
||||
* 反射测试
|
||||
*
|
||||
* 反射技术可以对一个类进行解剖。
|
||||
优点:大大的增强了程序的扩展性。
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2018年2月9日
|
||||
*/
|
||||
public class ReflectTest {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
Class clazz = User.class;//获得User的类名,返回reflect.User
|
||||
Object obj = create(clazz);//创建User的一个对象
|
||||
System.out.println(obj);//输出对象,会调用对象的toString方法
|
||||
System.out.println("---------");
|
||||
invoke1(obj, "getMessage");//调用User对象的getMessage方法
|
||||
}
|
||||
/*
|
||||
**根据类名,new一个对象,并返回*/
|
||||
static Object create(Class clazz) throws Exception {
|
||||
//如果clazz含有无参数的构造方法,可以如下方式实例化
|
||||
//clazz.newInstance();
|
||||
//根据类名和参数(类型、个数),找到相应的构造方法-下面创建构造方法参数为String的构造方法
|
||||
Constructor con=clazz.getConstructor(String.class);
|
||||
//实例化对象
|
||||
Object obj=con.newInstance("哈哈");
|
||||
//返回对象
|
||||
return obj;
|
||||
}
|
||||
/*
|
||||
**根据对象,方法名(字符串),来调用方法*/
|
||||
static void invoke1(Object obj, String methodName)throws Exception{
|
||||
//getDeclaredMethods可以获取类本身(不包括父类)所有方法的名字(包括私有方法)**一般不用这种方法,私有的属性一般不能修改
|
||||
Method[] ms = obj.getClass().getDeclaredMethods();
|
||||
//getMethods可以获取类本身,以及父类的方法的名字,但不包括私有的方法
|
||||
ms = obj.getClass().getMethods();
|
||||
for (Method m : ms) {
|
||||
//如果方法名字匹配,则反射调用方法
|
||||
if (methodName.equals(m.getName()))
|
||||
m.invoke(obj, null);
|
||||
}
|
||||
/*
|
||||
**防止方法重载,可用下面的方式(可以指明参数)--与上面的for循环(无法防止方法重载)一个效果
|
||||
**Method m = obj.getClass().getMethod(methodName, null);
|
||||
**m.invoke(obj, null);
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
**根据类名获取类的属性(一般不直接操作属性)*/
|
||||
static void field(Class clazz) throws Exception {
|
||||
Field[] fs = clazz.getDeclaredFields();
|
||||
//fs = clazz.getFields();
|
||||
for (Field f : fs)
|
||||
System.out.println(f.getName());
|
||||
}
|
||||
/*
|
||||
**根据类名获取类的注解*/
|
||||
static void annon(Class clazz) throws Exception {
|
||||
Annotation[] as = clazz.getAnnotations();
|
||||
for (Annotation a : as)
|
||||
System.out.println(((Member) a).getName());
|
||||
}
|
||||
|
||||
}
|
||||
87
src/main/java/com/pancm/basics/ReflectTest2.java
Normal file
87
src/main/java/com/pancm/basics/ReflectTest2.java
Normal file
@@ -0,0 +1,87 @@
|
||||
package com.pancm.basics;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: ReflectTest2
|
||||
* Description:
|
||||
* 反射测试
|
||||
* 反射的基本步骤:
|
||||
1、获得class对象,就是获取到指定的名称的字节码文件对象。
|
||||
2、实例化对象,获得类的属性、方法或构造函数。
|
||||
3、访问属性、调用方法、调用构造函数创建对象。
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2018年2月28日
|
||||
*/
|
||||
public class ReflectTest2 {
|
||||
|
||||
public static void main(String[] args) throws ReflectiveOperationException {
|
||||
method_1();
|
||||
method_2();
|
||||
method_3();
|
||||
method_4();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取该类中的所有方法
|
||||
*/
|
||||
private static void method_1() throws ReflectiveOperationException {
|
||||
//指定类和路径
|
||||
Class clazz=Class.forName("com.pancm.test.reflectTest.User");
|
||||
// Class clazz=User.class;
|
||||
//获取的是该类中的公有方法和父类中的公有方法。
|
||||
Method[] methods=clazz.getMethods();
|
||||
//获取本类中的方法,包含私有方法。
|
||||
methods=clazz.getDeclaredMethods();
|
||||
for(Method me:methods){
|
||||
System.out.println("方法:"+me);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定方法
|
||||
*/
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private static void method_2() throws ReflectiveOperationException {
|
||||
//指定类和路径
|
||||
Class clazz=Class.forName("com.pancm.test.reflectTest.User");
|
||||
//获取的指定名称的方法
|
||||
//如果带有入参,则指定入参类型
|
||||
Method method=clazz.getMethod("getMessage2",int.class);
|
||||
//初始化
|
||||
Object obj=clazz.newInstance();
|
||||
//执行该方法
|
||||
method.invoke(obj, 11);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取私有的方法
|
||||
*/
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private static void method_3() throws ReflectiveOperationException {
|
||||
//指定类和路径
|
||||
Class clazz=Class.forName("com.pancm.test.reflectTest.User");
|
||||
//获取私有的方法,必须要使用getDeclaredMethod
|
||||
Method method=clazz.getDeclaredMethod("getMessage3", null);
|
||||
//私有方法不能直接访问,因为权限不够。非要访问,可以通过暴力的方式。
|
||||
method.setAccessible(true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取静态方法
|
||||
*/
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private static void method_4() throws ReflectiveOperationException {
|
||||
//指定类和路径
|
||||
Class clazz=Class.forName("com.pancm.test.reflectTest.User");
|
||||
//获取私有的方法,必须要使用getDeclaredMethod
|
||||
Method method=clazz.getMethod("getMessage4",String.class);
|
||||
System.out.println();
|
||||
method.invoke(null, "测试");
|
||||
}
|
||||
|
||||
}
|
||||
80
src/main/java/com/pancm/basics/ServletTest.java
Normal file
80
src/main/java/com/pancm/basics/ServletTest.java
Normal file
@@ -0,0 +1,80 @@
|
||||
package com.pancm.basics;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: ServletTest
|
||||
* Description:
|
||||
* 部署在tomcat之后,在web.xml添加:
|
||||
* <servlet>
|
||||
<servlet-name>testServlet</servlet-name>
|
||||
<servlet-class>com.pancm.test.servletTest.testServlet</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>testServlet</servlet-name>
|
||||
<url-pattern>/test.do</url-pattern>
|
||||
</servlet-mapping>
|
||||
然后启动tomcat,在浏览器输入 ip:端口/项目名/设置的地址
|
||||
就可以访问了
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2018年3月20日
|
||||
*/
|
||||
public class ServletTest extends HttpServlet {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 返回结果
|
||||
*/
|
||||
private String result = null;
|
||||
|
||||
private long count=1;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
doPost(req, resp);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
System.out.println("============");
|
||||
System.out.println(req.getParameter("param"));
|
||||
PrintWriter printWriter=resp.getWriter();
|
||||
result = "这是第"+count+"次响应!";
|
||||
try {
|
||||
resp.setCharacterEncoding("utf-8");
|
||||
count++;
|
||||
printWriter.print(result);
|
||||
} catch (Exception e) {
|
||||
result="第"+count+"次请求错误!";
|
||||
printWriter.print(result);
|
||||
}finally{
|
||||
req=null;
|
||||
printWriter=null;
|
||||
resp=null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
super.destroy();
|
||||
}
|
||||
}
|
||||
89
src/main/java/com/pancm/basics/StringTest.java
Normal file
89
src/main/java/com/pancm/basics/StringTest.java
Normal file
@@ -0,0 +1,89 @@
|
||||
package com.pancm.basics;
|
||||
|
||||
/**
|
||||
* Title: test1
|
||||
* Description: string相关问题
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017-7-21
|
||||
*/
|
||||
public class StringTest {
|
||||
public static void main(String[] args) {
|
||||
|
||||
String hello="hello";
|
||||
//有15种构造方法,有两种是过时的,其中包含char[],byte[],int[],String,StringBuffer,StringBuilder。
|
||||
String newHello=new String("hello");
|
||||
char []cHello ={'h','e','l','l','o'};
|
||||
String str=new String(cHello);
|
||||
System.out.println(hello+","+newHello+","+str);
|
||||
test1();
|
||||
test3();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private static void test1(){
|
||||
String str="Hello World";
|
||||
String str1="";
|
||||
StringBuffer sbr=new StringBuffer(str);
|
||||
StringBuilder sbd=new StringBuilder(str);
|
||||
long start=System.currentTimeMillis();
|
||||
for(int i=0;i<10000;i++){
|
||||
str1+=str;
|
||||
}
|
||||
System.out.println("String累加用时:"+(System.currentTimeMillis()-start)+"ms");
|
||||
long start2=System.currentTimeMillis();
|
||||
for(int i=0;i<10000;i++){
|
||||
sbr.append(str);
|
||||
}
|
||||
System.out.println("StringBuffer累加用时:"+(System.currentTimeMillis()-start2)+"ms");
|
||||
long start3=System.currentTimeMillis();
|
||||
for(int i=0;i<10000;i++){
|
||||
sbd.append(str);
|
||||
}
|
||||
System.out.println("StringBuilder累加用时:"+(System.currentTimeMillis()-start3)+"ms");
|
||||
}
|
||||
|
||||
|
||||
private static void test3() {
|
||||
|
||||
String s1 = "test";
|
||||
String s2 = new String("test");
|
||||
String s3 = "te";
|
||||
String s4 = "st";
|
||||
String s5 = "te" + "st";
|
||||
String s6 = s3 + s4;
|
||||
String s7 = new String(s1);
|
||||
// 引用地址不同 equals相同
|
||||
System.out.println(s1 == s2); //false
|
||||
// s5 在编译之前就可以确认s5=Programming 因此相等
|
||||
System.out.println(s1 == s5); //true
|
||||
//字符串常量池的原则 这时 s6 的值是在运行时得到的,它会重新构造字符串对象 所以为false
|
||||
System.out.println(s1 == s6); //false
|
||||
System.out.println(s7==s1); //false
|
||||
System.out.println(s7.equals(s1)); //true
|
||||
|
||||
|
||||
String ab="ab";
|
||||
String c="c";
|
||||
String ab_c=ab+c;
|
||||
String ab_c1="ab"+"c";
|
||||
String abc="abc";
|
||||
/**
|
||||
* 优先级问题
|
||||
*/
|
||||
System.out.println(ab_c == abc + " : " + ab_c.equals(abc));//false
|
||||
/**
|
||||
* 字符串常量池的原则 这时 ab_c 的值是在运行时得到的,它会重新构造字符串对象 所以为false
|
||||
*/
|
||||
System.out.println((ab_c == abc) + " : " + ab_c.equals(abc));//false : true
|
||||
/**
|
||||
* 这条语言在编译时,可以确定 ab_c1 = "abc",因此它与 abc = "abc" 指向同一对象 所以为true
|
||||
*/
|
||||
System.out.println((ab_c1 == abc) + " : " + ab_c1.equals(abc));//true : true
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
62
src/main/java/com/pancm/basics/User.java
Normal file
62
src/main/java/com/pancm/basics/User.java
Normal file
@@ -0,0 +1,62 @@
|
||||
package com.pancm.basics;
|
||||
|
||||
/**
|
||||
*
|
||||
* @Title: User
|
||||
* @Description:
|
||||
* 反射测试实体类
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2018年2月9日
|
||||
*/
|
||||
public class User {
|
||||
private String name;
|
||||
|
||||
//构造方法1(默认构造方法)***********************
|
||||
public User(){
|
||||
|
||||
}
|
||||
//构造方法2
|
||||
public User(String name){
|
||||
this.name=name;
|
||||
}
|
||||
//******自定义方法*************
|
||||
public void getMessage(){
|
||||
System.out.print("反射测试");
|
||||
}
|
||||
|
||||
//******自定义方法2*************
|
||||
public String getMessage2(int num){
|
||||
String str=num+"反射测试!";
|
||||
System.out.print(str);
|
||||
return str;
|
||||
}
|
||||
|
||||
//******自定义方法3*************
|
||||
private String getMessage3(){
|
||||
String str="这是一个私有的方法!";
|
||||
System.out.print(str);
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
//******自定义方法4*************
|
||||
public static String getMessage4(String s){
|
||||
String str=s+"这是一个静态的方法!";
|
||||
System.out.print(str);
|
||||
return str;
|
||||
}
|
||||
|
||||
//******重写toString方法,在测试的时候会用到*****
|
||||
@Override
|
||||
public String toString() {
|
||||
return "name:"+this.name;
|
||||
}
|
||||
//**************************
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
396
src/main/java/com/pancm/bigdata/hbase/HBaseUtil.java
Normal file
396
src/main/java/com/pancm/bigdata/hbase/HBaseUtil.java
Normal file
@@ -0,0 +1,396 @@
|
||||
package com.pancm.bigdata.hbase;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.hadoop.conf.Configuration;
|
||||
import org.apache.hadoop.hbase.Cell;
|
||||
import org.apache.hadoop.hbase.CellUtil;
|
||||
import org.apache.hadoop.hbase.HBaseConfiguration;
|
||||
import org.apache.hadoop.hbase.HColumnDescriptor;
|
||||
import org.apache.hadoop.hbase.HTableDescriptor;
|
||||
import org.apache.hadoop.hbase.TableName;
|
||||
import org.apache.hadoop.hbase.client.Admin;
|
||||
import org.apache.hadoop.hbase.client.Connection;
|
||||
import org.apache.hadoop.hbase.client.ConnectionFactory;
|
||||
import org.apache.hadoop.hbase.client.Delete;
|
||||
import org.apache.hadoop.hbase.client.Get;
|
||||
import org.apache.hadoop.hbase.client.Put;
|
||||
import org.apache.hadoop.hbase.client.Result;
|
||||
import org.apache.hadoop.hbase.client.ResultScanner;
|
||||
import org.apache.hadoop.hbase.client.Scan;
|
||||
import org.apache.hadoop.hbase.client.Table;
|
||||
import org.apache.hadoop.hbase.util.Bytes;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: HBaseUtil
|
||||
* Description: HBase工具类
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年12月6日
|
||||
*/
|
||||
public class HBaseUtil {
|
||||
/** hadoop 连接 */
|
||||
private static Configuration conf = null;
|
||||
/** hbase 连接 */
|
||||
private static Connection con = null;
|
||||
/** 会话 */
|
||||
private static Admin admin = null;
|
||||
|
||||
private static String ip ="master";
|
||||
private static String port ="2181";
|
||||
private static String port1 ="9001";
|
||||
|
||||
// 初始化连接
|
||||
static {
|
||||
// 获得配制文件对象
|
||||
conf = HBaseConfiguration.create();
|
||||
// 设置配置参数
|
||||
conf.set("hbase.zookeeper.quorum", ip);
|
||||
conf.set("hbase.zookeeper.property.clientPort", port);
|
||||
//如果hbase是集群,这个必须加上
|
||||
//这个ip和端口是在hadoop/mapred-site.xml配置文件配置的
|
||||
conf.set("hbase.master", ip+":"+port1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取连接
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public synchronized static Connection getConnection() {
|
||||
try {
|
||||
if (null == con || con.isClosed()) {
|
||||
// 获得连接对象
|
||||
con = ConnectionFactory.createConnection(conf);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
System.out.println("获取连接失败!");
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return con;
|
||||
}
|
||||
|
||||
/**
|
||||
* 连接关闭
|
||||
*/
|
||||
public static void close() {
|
||||
try {
|
||||
if (admin != null) {
|
||||
admin.close();
|
||||
}
|
||||
if (con != null) {
|
||||
con.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
System.out.println("连接关闭失败!");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建表
|
||||
*
|
||||
* @param tableName
|
||||
* 表名
|
||||
* @param columnFamily
|
||||
* 列族
|
||||
*/
|
||||
public static void creatTable(String tableName, String[] columnFamily) {
|
||||
if(null==tableName||tableName.length()==0){
|
||||
return;
|
||||
}
|
||||
if(null==columnFamily||columnFamily.length==0){
|
||||
return;
|
||||
}
|
||||
// 创建表名对象
|
||||
TableName tn = TableName.valueOf(tableName);
|
||||
// a.判断数据库是否存在
|
||||
try {
|
||||
// 获取会话
|
||||
admin = getConnection().getAdmin();
|
||||
if (admin.tableExists(tn)) {
|
||||
System.out.println(tableName + " 表存在,删除表....");
|
||||
// 先使表设置为不可编辑
|
||||
admin.disableTable(tn);
|
||||
// 删除表
|
||||
admin.deleteTable(tn);
|
||||
System.out.println("表删除成功.....");
|
||||
}
|
||||
// 创建表结构对象
|
||||
HTableDescriptor htd = new HTableDescriptor(tn);
|
||||
for (String str : columnFamily) {
|
||||
// 创建列族结构对象
|
||||
HColumnDescriptor hcd = new HColumnDescriptor(str);
|
||||
htd.addFamily(hcd);
|
||||
}
|
||||
// 创建表
|
||||
admin.createTable(htd);
|
||||
System.out.println(tableName + " 表创建成功!");
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据单条插入或更新
|
||||
*
|
||||
* @param tableName
|
||||
* 表名
|
||||
* @param rowKey
|
||||
* 行健 (主键)
|
||||
* @param family
|
||||
* 列族
|
||||
* @param qualifier
|
||||
* 列
|
||||
* @param value
|
||||
* 存入的值
|
||||
* @return
|
||||
*/
|
||||
public static void insert(String tableName, String rowKey, String family,
|
||||
String qualifier, String value) {
|
||||
Table t = null;
|
||||
try {
|
||||
t = getConnection().getTable(TableName.valueOf(tableName));
|
||||
Put put = new Put(Bytes.toBytes(rowKey));
|
||||
put.addColumn(Bytes.toBytes(family), Bytes.toBytes(qualifier),
|
||||
Bytes.toBytes(value));
|
||||
t.put(put);
|
||||
System.out.println(tableName + " 更新成功!");
|
||||
} catch (IOException e) {
|
||||
System.out.println(tableName + " 更新失败!");
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据批量插入或更新
|
||||
*
|
||||
* @param tableName
|
||||
* 表名
|
||||
* @param list
|
||||
* hbase的数据
|
||||
* @return
|
||||
*/
|
||||
public static void insertBatch(String tableName, List<?> list) {
|
||||
if (null == tableName ||tableName.length()==0) {
|
||||
return;
|
||||
}
|
||||
if( null == list || list.size() == 0){
|
||||
return;
|
||||
}
|
||||
Table t = null;
|
||||
Put put = null;
|
||||
JSONObject json = null;
|
||||
List<Put> puts = new ArrayList<Put>();
|
||||
try {
|
||||
t = getConnection().getTable(TableName.valueOf(tableName));
|
||||
for (int i = 0, j = list.size(); i < j; i++) {
|
||||
json = (JSONObject) list.get(i);
|
||||
put = new Put(Bytes.toBytes(json.getString("rowKey")));
|
||||
put.addColumn(Bytes.toBytes(json.getString("family")),
|
||||
Bytes.toBytes(json.getString("qualifier")),
|
||||
Bytes.toBytes(json.getString("value")));
|
||||
puts.add(put);
|
||||
}
|
||||
t.put(puts);
|
||||
System.out.println(tableName + " 更新成功!");
|
||||
} catch (IOException e) {
|
||||
System.out.println(tableName + " 更新失败!");
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据删除
|
||||
* @param tableName 表名
|
||||
* @param rowKey 行健
|
||||
* @return
|
||||
*/
|
||||
public static void delete(String tableName, String rowKey) {
|
||||
delete(tableName,rowKey,"","");
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据删除
|
||||
* @param tableName 表名
|
||||
* @param rowKey 行健
|
||||
* @param family 列族
|
||||
* @return
|
||||
*/
|
||||
public static void delete(String tableName, String rowKey, String family) {
|
||||
delete(tableName,rowKey,family,"");
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据删除
|
||||
* @param tableName 表名
|
||||
* @param rowKey 行健
|
||||
* @param family 列族
|
||||
* @param qualifier 列
|
||||
* @return
|
||||
*/
|
||||
public static void delete(String tableName, String rowKey, String family,
|
||||
String qualifier) {
|
||||
if (null == tableName ||tableName.length()==0) {
|
||||
return;
|
||||
}
|
||||
if( null == rowKey || rowKey.length() == 0){
|
||||
return;
|
||||
}
|
||||
Table t = null;
|
||||
try {
|
||||
t = getConnection().getTable(TableName.valueOf(tableName));
|
||||
Delete del = new Delete(Bytes.toBytes(rowKey));
|
||||
// 如果列族不为空
|
||||
if (null != family && family.length() > 0) {
|
||||
// 如果列不为空
|
||||
if (null != qualifier && qualifier.length() > 0) {
|
||||
del.addColumn(Bytes.toBytes(family),
|
||||
Bytes.toBytes(qualifier));
|
||||
} else {
|
||||
del.addFamily(Bytes.toBytes(family));
|
||||
}
|
||||
}
|
||||
t.delete(del);
|
||||
} catch (IOException e) {
|
||||
System.out.println("删除失败!");
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询该表中的所有数据
|
||||
*
|
||||
* @param tableName
|
||||
* 表名
|
||||
*/
|
||||
public static void select(String tableName) {
|
||||
if(null==tableName||tableName.length()==0){
|
||||
return;
|
||||
}
|
||||
Table t = null;
|
||||
List<Map<String,Object>> list=new ArrayList<Map<String,Object>>();
|
||||
try {
|
||||
t = getConnection().getTable(TableName.valueOf(tableName));
|
||||
// 读取操作
|
||||
Scan scan = new Scan();
|
||||
// 得到扫描的结果集
|
||||
ResultScanner rs = t.getScanner(scan);
|
||||
if (null == rs ) {
|
||||
return;
|
||||
}
|
||||
for (Result result : rs) {
|
||||
// 得到单元格集合
|
||||
List<Cell> cs = result.listCells();
|
||||
if (null == cs || cs.size() == 0) {
|
||||
continue;
|
||||
}
|
||||
for (Cell cell : cs) {
|
||||
Map<String,Object> map=new HashMap<String, Object>();
|
||||
map.put("rowKey", Bytes.toString(CellUtil.cloneRow(cell)));// 取行健
|
||||
map.put("timestamp", cell.getTimestamp());// 取到时间戳
|
||||
map.put("family", Bytes.toString(CellUtil.cloneFamily(cell)));// 取到列族
|
||||
map.put("qualifier", Bytes.toString(CellUtil.cloneQualifier(cell)));// 取到列
|
||||
map.put("value", Bytes.toString(CellUtil.cloneValue(cell)));// 取到值
|
||||
list.add(map);
|
||||
}
|
||||
}
|
||||
System.out.println("查询的数据:"+list);
|
||||
} catch (IOException e) {
|
||||
System.out.println("查询失败!");
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据表名和行健查询
|
||||
* @param tableName
|
||||
* @param rowKey
|
||||
*/
|
||||
public static void select(String tableName, String rowKey) {
|
||||
select(tableName,rowKey,"","");
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据表名、行健和列族查询
|
||||
* @param tableName
|
||||
* @param rowKey
|
||||
* @param family
|
||||
*/
|
||||
public static void select(String tableName, String rowKey, String family) {
|
||||
select(tableName,rowKey,family,"");
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据条件明细查询
|
||||
*
|
||||
* @param tableName
|
||||
* 表名
|
||||
* @param rowKey
|
||||
* 行健 (主键)
|
||||
* @param family
|
||||
* 列族
|
||||
* @param qualifier
|
||||
* 列
|
||||
*/
|
||||
public static void select(String tableName, String rowKey, String family,
|
||||
String qualifier) {
|
||||
Table t = null;
|
||||
List<Map<String,Object>> list=new ArrayList<Map<String,Object>>();
|
||||
try {
|
||||
t = getConnection().getTable(TableName.valueOf(tableName));
|
||||
// 通过HBase中的 get来进行查询
|
||||
Get get = new Get(Bytes.toBytes(rowKey));
|
||||
// 如果列族不为空
|
||||
if (null != family && family.length() > 0) {
|
||||
// 如果列不为空
|
||||
if (null != qualifier && qualifier.length() > 0) {
|
||||
get.addColumn(Bytes.toBytes(family),
|
||||
Bytes.toBytes(qualifier));
|
||||
} else {
|
||||
get.addFamily(Bytes.toBytes(family));
|
||||
}
|
||||
}
|
||||
Result r = t.get(get);
|
||||
List<Cell> cs = r.listCells();
|
||||
if (null == cs || cs.size() == 0) {
|
||||
return;
|
||||
}
|
||||
for (Cell cell : cs) {
|
||||
Map<String,Object> map=new HashMap<String, Object>();
|
||||
map.put("rowKey", Bytes.toString(CellUtil.cloneRow(cell)));// 取行健
|
||||
map.put("timestamp", cell.getTimestamp());// 取到时间戳
|
||||
map.put("family", Bytes.toString(CellUtil.cloneFamily(cell)));// 取到列族
|
||||
map.put("qualifier", Bytes.toString(CellUtil.cloneQualifier(cell)));// 取到列
|
||||
map.put("value", Bytes.toString(CellUtil.cloneValue(cell)));// 取到值
|
||||
list.add(map);
|
||||
}
|
||||
System.out.println("查询的数据:"+list);
|
||||
} catch (IOException e) {
|
||||
System.out.println("查询失败!");
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
86
src/main/java/com/pancm/bigdata/hbase/HbaseTest.java
Normal file
86
src/main/java/com/pancm/bigdata/hbase/HbaseTest.java
Normal file
@@ -0,0 +1,86 @@
|
||||
package com.pancm.bigdata.hbase;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
/**
|
||||
*
|
||||
* Title: hbaseTest
|
||||
* Description: HBase 相关测试
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年11月23日
|
||||
*/
|
||||
public class HbaseTest {
|
||||
|
||||
public static void main(String[] args) {
|
||||
test();
|
||||
}
|
||||
|
||||
/**
|
||||
* 一些测试
|
||||
*/
|
||||
private static void test() {
|
||||
String tableName1="t_student",tableName2="t_student_info";
|
||||
String []columnFamily1={"st1","st2"};
|
||||
String []columnFamily2={"stf1","stf2"};
|
||||
HBaseUtil.creatTable(tableName1, columnFamily1);
|
||||
HBaseUtil.creatTable(tableName2, columnFamily2);
|
||||
|
||||
HBaseUtil.insert(tableName1, "1001", columnFamily1[0], "name", "zhangsan");
|
||||
HBaseUtil.insert(tableName1, "1002", columnFamily1[0], "name", "lisi");
|
||||
HBaseUtil.insert(tableName1, "1001", columnFamily1[1], "age", "18");
|
||||
HBaseUtil.insert(tableName1, "1002", columnFamily1[1], "age", "20");
|
||||
|
||||
HBaseUtil.insert(tableName2, "1001", columnFamily2[0], "phone", "123456");
|
||||
HBaseUtil.insert(tableName2, "1002", columnFamily2[0], "phone", "234567");
|
||||
HBaseUtil.insert(tableName2, "1001", columnFamily2[1], "mail", "123@163.com");
|
||||
HBaseUtil.insert(tableName2, "1002", columnFamily2[1], "mail", "234@163.com");
|
||||
|
||||
HBaseUtil.select(tableName1); //查询该表所有数据
|
||||
HBaseUtil.select(tableName1, "1001"); //根据表名和行健查询
|
||||
HBaseUtil.select(tableName2, "1002",columnFamily2[0]); //根据表名、行健和列族查询
|
||||
HBaseUtil.select(tableName2, "1002",columnFamily2[1],"mail"); //根据表名、行健、列族、和列查询
|
||||
|
||||
HBaseUtil.select(tableName1, "1002"); //根据表名和行健查询
|
||||
HBaseUtil.delete(tableName1, "1002", columnFamily1[0]);//删除数据
|
||||
HBaseUtil.select(tableName1, "1002"); //根据表名和行健查询
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 批量测试方法
|
||||
* @param tableName 表名
|
||||
* @param family 列族
|
||||
* @param qualifier 列
|
||||
* @param value 值
|
||||
* @param k 次数
|
||||
*/
|
||||
public static void insterTest(String tableName,String family,String qualifier,String value, int k){
|
||||
List<JSONObject> list =new ArrayList<>();
|
||||
for(int i=1;i<=k;i++){
|
||||
JSONObject json =new JSONObject();
|
||||
json.put("rowKey", i); //行健
|
||||
json.put("family", family); //列族
|
||||
json.put("qualifier", qualifier); //列
|
||||
if("t_student".equals(tableName)){ //如果是t_student 姓名则加上编号
|
||||
json.put("value", value+i); //值
|
||||
}else if("".equals(value)){ //如果为空,则是年龄
|
||||
json.put("value", i); //值
|
||||
}else{ //否则就是性别
|
||||
json.put("value", value); //值
|
||||
}
|
||||
|
||||
list.add(json);
|
||||
}
|
||||
HBaseUtil.insertBatch(tableName,list);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
8
src/main/java/com/pancm/bigdata/hbase/package-info.java
Normal file
8
src/main/java/com/pancm/bigdata/hbase/package-info.java
Normal file
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* @Title: package-info
|
||||
* @Description: hbase相关的代码
|
||||
* @Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2018年9月21日
|
||||
*/
|
||||
package com.pancm.bigdata.hbase;
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.pancm.bigdata.storm.example;
|
||||
|
||||
import org.apache.storm.Config;
|
||||
import org.apache.storm.LocalCluster;
|
||||
import org.apache.storm.StormSubmitter;
|
||||
import org.apache.storm.generated.AlreadyAliveException;
|
||||
import org.apache.storm.generated.AuthorizationException;
|
||||
import org.apache.storm.generated.InvalidTopologyException;
|
||||
import org.apache.storm.generated.StormTopology;
|
||||
import org.apache.storm.topology.TopologyBuilder;
|
||||
import org.apache.storm.tuple.Fields;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: WordCountApp
|
||||
* Description: 测试storm本地模式 统计words单次个数
|
||||
* 源代码地址:http://www.tianshouzhi.com/api/tutorials/storm/54
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年12月28日
|
||||
*/
|
||||
public class WordCountApp {
|
||||
public static void main(String[] args) throws InterruptedException, AlreadyAliveException, InvalidTopologyException {
|
||||
//定义拓扑
|
||||
TopologyBuilder builder = new TopologyBuilder();
|
||||
builder.setSpout("word-reader" , new WordReader());
|
||||
builder.setBolt("word-normalizer" , new WordNormalizer()).shuffleGrouping("word-reader" );
|
||||
builder.setBolt("word-counter" , new WordCounter()).fieldsGrouping("word-normalizer" , new Fields("word"));
|
||||
StormTopology topology = builder.createTopology();
|
||||
//配置
|
||||
|
||||
Config conf = new Config();
|
||||
String fileName ="words.txt" ;
|
||||
conf.put("fileName" , fileName );
|
||||
conf.setDebug(false);
|
||||
|
||||
//运行拓扑
|
||||
System.out.println("开始...");
|
||||
if(args !=null&&args.length>0){ //有参数时,表示向集群提交作业,并把第一个参数当做topology名称
|
||||
System.out.println("远程模式");
|
||||
try {
|
||||
StormSubmitter.submitTopology(args[0], conf, topology);
|
||||
} catch (AuthorizationException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else{//没有参数时,本地提交
|
||||
//启动本地模式
|
||||
System.out.println("本地模式");
|
||||
LocalCluster cluster = new LocalCluster();
|
||||
cluster.submitTopology("Getting-Started-Topologie" , conf , topology );
|
||||
Thread.sleep(5000);
|
||||
//关闭本地集群
|
||||
cluster.shutdown();
|
||||
}
|
||||
System.out.println("结束");
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package com.pancm.bigdata.storm.example;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.storm.task.OutputCollector;
|
||||
import org.apache.storm.task.TopologyContext;
|
||||
import org.apache.storm.topology.IRichBolt;
|
||||
import org.apache.storm.topology.OutputFieldsDeclarer;
|
||||
import org.apache.storm.tuple.Tuple;
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: WordCounter
|
||||
* Description: 该类主要用于统计
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年12月28日
|
||||
*/
|
||||
public class WordCounter implements IRichBolt {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
Integer id;
|
||||
String name;
|
||||
Map<String, Integer> counters;
|
||||
private OutputCollector collector;
|
||||
|
||||
/**
|
||||
* 当Bolt销毁时,我们会显示单词数量
|
||||
*/
|
||||
@Override
|
||||
public void cleanup() {
|
||||
System.out.println("开始显示单词数量...");
|
||||
for (Map.Entry<String, Integer> entry : counters.entrySet()) {
|
||||
System.out.println(entry.getKey() + ": " + entry.getValue());
|
||||
}
|
||||
System.out.println("WordCounter.cleanup()");
|
||||
}
|
||||
|
||||
/**
|
||||
* 为每个单词计数
|
||||
*/
|
||||
@Override
|
||||
public void execute(Tuple input) {
|
||||
System.out.println("WordCounter.execute()");
|
||||
String str = input.getString(0);
|
||||
/**
|
||||
* 如果单词尚不存在于map,我们就创建一个,如果已在,我们就为它加1
|
||||
*/
|
||||
if (!counters.containsKey(str)) {
|
||||
counters.put(str, 1);
|
||||
} else {
|
||||
Integer c = counters.get(str) + 1;
|
||||
counters.put(str, c);
|
||||
}
|
||||
// 对元组作为应答
|
||||
collector.ack(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
@Override
|
||||
public void prepare(Map stormConf, TopologyContext context,
|
||||
OutputCollector collector) {
|
||||
this.counters = new HashMap<String, Integer>();
|
||||
this.collector = collector;
|
||||
this.name = context.getThisComponentId();
|
||||
this.id = context.getThisTaskId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void declareOutputFields(OutputFieldsDeclarer declarer) {
|
||||
System.out.println("WordCounter.declareOutputFields()");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getComponentConfiguration() {
|
||||
System.out.println("WordCounter.getComponentConfiguration()");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package com.pancm.bigdata.storm.example;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.storm.task.OutputCollector;
|
||||
import org.apache.storm.task.TopologyContext;
|
||||
import org.apache.storm.topology.IRichBolt;
|
||||
import org.apache.storm.topology.OutputFieldsDeclarer;
|
||||
import org.apache.storm.tuple.Fields;
|
||||
import org.apache.storm.tuple.Tuple;
|
||||
import org.apache.storm.tuple.Values;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: WordNormalizer
|
||||
* Description:该类主要用于格式化数据
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年12月28日
|
||||
*/
|
||||
public class WordNormalizer implements IRichBolt {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 3644849073824009317L;
|
||||
private OutputCollector collector;
|
||||
private static int count=1;
|
||||
|
||||
/**
|
||||
* *bolt*从单词文件接收到文本行,并标准化它。 文本行会全部转化成小写,并切分它,从中得到所有单词。
|
||||
*/
|
||||
public void execute(Tuple input) {
|
||||
System.out.println("WordNormalizer.execute()执行次数:"+count);
|
||||
String sentence = input.getString(0);
|
||||
String[] words = sentence.split(" ");
|
||||
for (String word : words) {
|
||||
word = word.trim();
|
||||
if (!word.isEmpty()) {
|
||||
word = word.toLowerCase();
|
||||
/* //发布这个单词 */
|
||||
collector.emit(input, new Values(word));
|
||||
}
|
||||
}
|
||||
// 对元组做出应答
|
||||
collector.ack(input);
|
||||
count++;
|
||||
}
|
||||
|
||||
public void prepare(Map stormConf, TopologyContext context,
|
||||
OutputCollector collector) {
|
||||
System.out.println("WordNormalizer.prepare()");
|
||||
this.collector = collector;
|
||||
}
|
||||
|
||||
/**
|
||||
* 这个*bolt*只会发布“word”域
|
||||
*/
|
||||
public void declareOutputFields(OutputFieldsDeclarer declarer) {
|
||||
System.out.println("WordNormalizer.declareOutputFields()");
|
||||
declarer.declare(new Fields("word"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getComponentConfiguration() {
|
||||
System.out.println("WordNormalizer.getComponentConfiguration()");
|
||||
return null;
|
||||
}
|
||||
|
||||
public void cleanup() {
|
||||
System.out.println("WordNormalizer.cleanup()");
|
||||
}
|
||||
}
|
||||
129
src/main/java/com/pancm/bigdata/storm/example/WordReader.java
Normal file
129
src/main/java/com/pancm/bigdata/storm/example/WordReader.java
Normal file
@@ -0,0 +1,129 @@
|
||||
package com.pancm.bigdata.storm.example;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileReader;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.storm.spout.SpoutOutputCollector;
|
||||
import org.apache.storm.task.TopologyContext;
|
||||
import org.apache.storm.topology.IRichSpout;
|
||||
import org.apache.storm.topology.OutputFieldsDeclarer;
|
||||
import org.apache.storm.tuple.Fields;
|
||||
import org.apache.storm.tuple.Values;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: WordReader
|
||||
* Description: 该类主要用于从外部数据源words.txt中获取数据
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年12月28日
|
||||
*/
|
||||
public class WordReader implements IRichSpout {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 6146631397258548505L;
|
||||
private SpoutOutputCollector collector;
|
||||
private FileReader fileReader;
|
||||
BufferedReader reader;
|
||||
private boolean completed = false;
|
||||
|
||||
/**
|
||||
* 这个方法做的惟一一件事情就是分发文件中的文本行
|
||||
*/
|
||||
public void nextTuple() {
|
||||
/**
|
||||
* 这个方法会不断的被调用,直到整个文件都读完了,我们将等待并返回。
|
||||
*/
|
||||
if (completed) {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
// 什么也不做
|
||||
}
|
||||
return;
|
||||
}
|
||||
String str;
|
||||
|
||||
try {
|
||||
int i = 0;
|
||||
// 读所有文本行
|
||||
while ((str = reader.readLine()) != null) {
|
||||
System.out.println("WordReader.nextTuple(),emits time:" + i++);
|
||||
/**
|
||||
* 按行发布一个新值
|
||||
*/
|
||||
this.collector.emit(new Values(str), str);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Error reading tuple", e);
|
||||
} finally {
|
||||
completed = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* 当Spout被创建之后,这个方法会被掉用
|
||||
*/
|
||||
public void open(Map conf, TopologyContext context,
|
||||
SpoutOutputCollector collector) {
|
||||
|
||||
System.out.println("WordReader.open(Map conf, TopologyContext context, SpoutOutputCollector collector)");
|
||||
String fileName = conf.get("fileName").toString();
|
||||
InputStream inputStream = WordReader.class.getClassLoader()
|
||||
.getResourceAsStream(fileName);
|
||||
reader = new BufferedReader(new InputStreamReader(inputStream));
|
||||
this.collector = collector;
|
||||
}
|
||||
|
||||
/**
|
||||
* 声明数据格式,即输出的一个Tuple中,包含几个字段
|
||||
*/
|
||||
public void declareOutputFields(OutputFieldsDeclarer declarer) {
|
||||
System.out
|
||||
.println("WordReader.declareOutputFields(OutputFieldsDeclarer declarer)");
|
||||
declarer.declare(new Fields("line"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void activate() {
|
||||
System.out.println("WordReader.activate()");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deactivate() {
|
||||
System.out.println("WordReader.deactivate()");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getComponentConfiguration() {
|
||||
System.out.println("WordReader.getComponentConfiguration()");
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 当一个Tuple处理成功时,会调用这个方法
|
||||
*/
|
||||
public void ack(Object msgId) {
|
||||
System.out.println("WordReader.ack(Object msgId):" + msgId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当Topology停止时,会调用这个方法
|
||||
*/
|
||||
public void close() {
|
||||
System.out.println("WordReader.close()");
|
||||
}
|
||||
|
||||
/**
|
||||
* 当一个Tuple处理失败时,会调用这个方法
|
||||
*/
|
||||
public void fail(Object msgId) {
|
||||
System.out.println("WordReader.fail(Object msgId):" + msgId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* Title: package-info
|
||||
* Description:
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年12月28日
|
||||
*/
|
||||
package com.pancm.bigdata.storm.example;
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.pancm.bigdata.storm.example1;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.storm.task.OutputCollector;
|
||||
import org.apache.storm.task.TopologyContext;
|
||||
import org.apache.storm.topology.OutputFieldsDeclarer;
|
||||
import org.apache.storm.topology.base.BaseRichBolt;
|
||||
import org.apache.storm.tuple.Tuple;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 生成一份报告
|
||||
* @author soul
|
||||
*
|
||||
*/
|
||||
public class ReportBolt extends BaseRichBolt {
|
||||
|
||||
private HashMap<String, Long> counts = null;//保存单词和对应的计数
|
||||
|
||||
public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
this.counts = new HashMap<String, Long>();
|
||||
}
|
||||
|
||||
public void execute(Tuple input) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
String word = input.getStringByField("word");
|
||||
Long count = input.getLongByField("count");
|
||||
this.counts.put(word, count);
|
||||
|
||||
//实时输出
|
||||
System.out.println("结果:"+this.counts);
|
||||
}
|
||||
|
||||
public void declareOutputFields(OutputFieldsDeclarer declarer) {
|
||||
// TODO Auto-generated method stub
|
||||
//这里是末端bolt,不需要发射数据流,这里无需定义
|
||||
}
|
||||
|
||||
/**
|
||||
* cleanup是IBolt接口中定义
|
||||
* Storm在终止一个bolt之前会调用这个方法
|
||||
* 本例我们利用cleanup()方法在topology关闭时输出最终的计数结果
|
||||
* 通常情况下,cleanup()方法用来释放bolt占用的资源,如打开的文件句柄或数据库连接
|
||||
* 但是当Storm拓扑在一个集群上运行,IBolt.cleanup()方法不能保证执行(这里是开发模式,生产环境不要这样做)。
|
||||
*/
|
||||
public void cleanup(){
|
||||
System.out.println("---------- FINAL COUNTS -----------");
|
||||
|
||||
ArrayList<String> keys = new ArrayList<String>();
|
||||
keys.addAll(this.counts.keySet());
|
||||
Collections.sort(keys);
|
||||
for(String key : keys){
|
||||
System.out.println(key + " : " + this.counts.get(key));
|
||||
}
|
||||
System.out.println("----------------------------");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.pancm.bigdata.storm.example1;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.storm.spout.SpoutOutputCollector;
|
||||
import org.apache.storm.task.TopologyContext;
|
||||
import org.apache.storm.topology.OutputFieldsDeclarer;
|
||||
import org.apache.storm.topology.base.BaseRichSpout;
|
||||
import org.apache.storm.tuple.Fields;
|
||||
import org.apache.storm.tuple.Values;
|
||||
import org.apache.storm.utils.Utils;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 向后端发射tuple数据流
|
||||
* @author soul
|
||||
*
|
||||
*/
|
||||
public class SentenceSpout extends BaseRichSpout {
|
||||
|
||||
//BaseRichSpout是ISpout接口和IComponent接口的简单实现,接口对用不到的方法提供了默认的实现
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
private SpoutOutputCollector collector;
|
||||
private String[] sentences = {
|
||||
"my name is soul",
|
||||
"im a boy",
|
||||
"i have a dog",
|
||||
"my dog has fleas",
|
||||
"my girl friend is beautiful"
|
||||
};
|
||||
|
||||
private int index=0;
|
||||
|
||||
/**
|
||||
* open()方法中是ISpout接口中定义,在Spout组件初始化时被调用。
|
||||
* open()接受三个参数:一个包含Storm配置的Map,一个TopologyContext对象,提供了topology中组件的信息,SpoutOutputCollector对象提供发射tuple的方法。
|
||||
* 在这个例子中,我们不需要执行初始化,只是简单的存储在一个SpoutOutputCollector实例变量。
|
||||
*/
|
||||
public void open(Map conf, TopologyContext context, SpoutOutputCollector collector) {
|
||||
// TODO Auto-generated method stub
|
||||
this.collector = collector;
|
||||
}
|
||||
|
||||
/**
|
||||
* nextTuple()方法是任何Spout实现的核心。
|
||||
* Storm调用这个方法,向输出的collector发出tuple。
|
||||
* 在这里,我们只是发出当前索引的句子,并增加该索引准备发射下一个句子。
|
||||
*/
|
||||
public void nextTuple() {
|
||||
//collector.emit(new Values("hello world this is a test"));
|
||||
|
||||
// TODO Auto-generated method stub
|
||||
this.collector.emit(new Values(sentences[index]));
|
||||
index++;
|
||||
if (index>=sentences.length) {
|
||||
index=0;
|
||||
}
|
||||
Utils.sleep(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* declareOutputFields是在IComponent接口中定义的,所有Storm的组件(spout和bolt)都必须实现这个接口
|
||||
* 用于告诉Storm流组件将会发出那些数据流,每个流的tuple将包含的字段
|
||||
*/
|
||||
public void declareOutputFields(OutputFieldsDeclarer declarer) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
declarer.declare(new Fields("sentence"));//告诉组件发出数据流包含sentence字段
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package com.pancm.bigdata.storm.example1;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.storm.task.OutputCollector;
|
||||
import org.apache.storm.task.TopologyContext;
|
||||
import org.apache.storm.topology.OutputFieldsDeclarer;
|
||||
import org.apache.storm.topology.base.BaseRichBolt;
|
||||
import org.apache.storm.tuple.Fields;
|
||||
import org.apache.storm.tuple.Tuple;
|
||||
import org.apache.storm.tuple.Values;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 订阅sentence spout发射的tuple流,实现分割单词
|
||||
* @author soul
|
||||
*
|
||||
*/
|
||||
public class SplitSentenceBolt extends BaseRichBolt {
|
||||
//BaseRichBolt是IComponent和IBolt接口的实现
|
||||
//继承这个类,就不用去实现本例不关心的方法
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
private OutputCollector collector;
|
||||
|
||||
/**
|
||||
* prepare()方法类似于ISpout 的open()方法。
|
||||
* 这个方法在blot初始化时调用,可以用来准备bolt用到的资源,比如数据库连接。
|
||||
* 本例子和SentenceSpout类一样,SplitSentenceBolt类不需要太多额外的初始化,
|
||||
* 所以prepare()方法只保存OutputCollector对象的引用。
|
||||
*/
|
||||
public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) {
|
||||
// TODO Auto-generated method stub
|
||||
this.collector=collector;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* SplitSentenceBolt核心功能是在类IBolt定义execute()方法,这个方法是IBolt接口中定义。
|
||||
* 每次Bolt从流接收一个订阅的tuple,都会调用这个方法。
|
||||
* 本例中,收到的元组中查找“sentence”的值,
|
||||
* 并将该值拆分成单个的词,然后按单词发出新的tuple。
|
||||
*/
|
||||
public void execute(Tuple input) {
|
||||
// TODO Auto-generated method stub
|
||||
String sentence = input.getStringByField("sentence");
|
||||
String[] words = sentence.split(" ");
|
||||
for (String word : words) {
|
||||
this.collector.emit(new Values(word));//向下一个bolt发射数据
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* plitSentenceBolt类定义一个元组流,每个包含一个字段(“word”)。
|
||||
*/
|
||||
public void declareOutputFields(OutputFieldsDeclarer declarer) {
|
||||
// TODO Auto-generated method stub
|
||||
declarer.declare(new Fields("word"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package com.pancm.bigdata.storm.example1;
|
||||
|
||||
|
||||
|
||||
import org.apache.storm.Config;
|
||||
import org.apache.storm.LocalCluster;
|
||||
import org.apache.storm.topology.TopologyBuilder;
|
||||
import org.apache.storm.tuple.Fields;
|
||||
import org.apache.storm.utils.Utils;
|
||||
|
||||
import com.pancm.bigdata.storm.example1.ReportBolt;
|
||||
import com.pancm.bigdata.storm.example1.SentenceSpout;
|
||||
import com.pancm.bigdata.storm.example1.SplitSentenceBolt;
|
||||
import com.pancm.bigdata.storm.example1.WordCountBolt;
|
||||
|
||||
/**
|
||||
* 实现单词计数topology
|
||||
*
|
||||
*/
|
||||
public class WordCountApp
|
||||
{
|
||||
private static final String SENTENCE_SPOUT_ID = "sentence-spout";
|
||||
private static final String SPLIT_BOLT_ID = "split-bolt";
|
||||
private static final String COUNT_BOLT_ID = "count-bolt";
|
||||
private static final String REPORT_BOLT_ID = "report-bolt";
|
||||
private static final String TOPOLOGY_NAME = "word-count-topology";
|
||||
|
||||
public static void main( String[] args ) //throws Exception
|
||||
{
|
||||
//System.out.println( "Hello World!" );
|
||||
//实例化spout和bolt
|
||||
|
||||
SentenceSpout spout = new SentenceSpout();
|
||||
SplitSentenceBolt splitBolt = new SplitSentenceBolt();
|
||||
WordCountBolt countBolt = new WordCountBolt();
|
||||
ReportBolt reportBolt = new ReportBolt();
|
||||
|
||||
TopologyBuilder builder = new TopologyBuilder();//创建了一个TopologyBuilder实例
|
||||
|
||||
//TopologyBuilder提供流式风格的API来定义topology组件之间的数据流
|
||||
|
||||
//builder.setSpout(SENTENCE_SPOUT_ID, spout);//注册一个sentence spout
|
||||
|
||||
//设置两个Executeor(线程),默认一个
|
||||
builder.setSpout(SENTENCE_SPOUT_ID, spout,2);
|
||||
|
||||
// SentenceSpout --> SplitSentenceBolt
|
||||
|
||||
//注册一个bolt并订阅sentence发射出的数据流,shuffleGrouping方法告诉Storm要将SentenceSpout发射的tuple随机均匀的分发给SplitSentenceBolt的实例
|
||||
//builder.setBolt(SPLIT_BOLT_ID, splitBolt).shuffleGrouping(SENTENCE_SPOUT_ID);
|
||||
|
||||
//SplitSentenceBolt单词分割器设置4个Task,2个Executeor(线程)
|
||||
builder.setBolt(SPLIT_BOLT_ID, splitBolt,2).setNumTasks(4).shuffleGrouping(SENTENCE_SPOUT_ID);
|
||||
|
||||
// SplitSentenceBolt --> WordCountBolt
|
||||
|
||||
//fieldsGrouping将含有特定数据的tuple路由到特殊的bolt实例中
|
||||
//这里fieldsGrouping()方法保证所有“word”字段相同的tuuple会被路由到同一个WordCountBolt实例中
|
||||
//builder.setBolt(COUNT_BOLT_ID, countBolt).fieldsGrouping( SPLIT_BOLT_ID, new Fields("word"));
|
||||
|
||||
//WordCountBolt单词计数器设置4个Executeor(线程)
|
||||
builder.setBolt(COUNT_BOLT_ID, countBolt,4).fieldsGrouping( SPLIT_BOLT_ID, new Fields("word"));
|
||||
|
||||
// WordCountBolt --> ReportBolt
|
||||
|
||||
//globalGrouping是把WordCountBolt发射的所有tuple路由到唯一的ReportBolt
|
||||
builder.setBolt(REPORT_BOLT_ID, reportBolt).globalGrouping(COUNT_BOLT_ID);
|
||||
|
||||
|
||||
Config config = new Config();//Config类是一个HashMap<String,Object>的子类,用来配置topology运行时的行为
|
||||
//设置worker数量
|
||||
//config.setNumWorkers(2);
|
||||
//本地提交
|
||||
LocalCluster cluster = new LocalCluster();
|
||||
|
||||
cluster.submitTopology(TOPOLOGY_NAME, config, builder.createTopology());
|
||||
|
||||
Utils.sleep(10000);
|
||||
cluster.killTopology(TOPOLOGY_NAME);
|
||||
cluster.shutdown();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package com.pancm.bigdata.storm.example1;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.storm.task.OutputCollector;
|
||||
import org.apache.storm.task.TopologyContext;
|
||||
import org.apache.storm.topology.OutputFieldsDeclarer;
|
||||
import org.apache.storm.topology.base.BaseRichBolt;
|
||||
import org.apache.storm.tuple.Fields;
|
||||
import org.apache.storm.tuple.Tuple;
|
||||
import org.apache.storm.tuple.Values;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 订阅 split sentence bolt的输出流,实现单词计数,并发送当前计数给下一个bolt
|
||||
* @author soul
|
||||
*
|
||||
*/
|
||||
public class WordCountBolt extends BaseRichBolt {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
private OutputCollector collector;
|
||||
//存储单词和对应的计数
|
||||
private HashMap<String, Long> counts = null;//注:不可序列化对象需在prepare中实例化
|
||||
|
||||
/**
|
||||
* 大部分实例变量通常是在prepare()中进行实例化,这个设计模式是由topology的部署方式决定的
|
||||
* 因为在部署拓扑时,组件spout和bolt是在网络上发送的序列化的实例变量。
|
||||
* 如果spout或bolt有任何non-serializable实例变量在序列化之前被实例化(例如,在构造函数中创建)
|
||||
* 会抛出NotSerializableException并且拓扑将无法发布。
|
||||
* 本例中因为HashMap 是可序列化的,所以可以安全地在构造函数中实例化。
|
||||
* 但是,通常情况下最好是在构造函数中对基本数据类型和可序列化的对象进行复制和实例化
|
||||
* 而在prepare()方法中对不可序列化的对象进行实例化。
|
||||
*/
|
||||
public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) {
|
||||
// TODO Auto-generated method stub
|
||||
this.collector = collector;
|
||||
this.counts = new HashMap<String, Long>();
|
||||
}
|
||||
|
||||
/**
|
||||
* 在execute()方法中,我们查找的收到的单词的计数(如果不存在,初始化为0)
|
||||
* 然后增加计数并存储,发出一个新的词和当前计数组成的二元组。
|
||||
* 发射计数作为流允许拓扑的其他bolt订阅和执行额外的处理。
|
||||
*/
|
||||
public void execute(Tuple input) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
String word = input.getStringByField("word");
|
||||
Long count = this.counts.get(word);
|
||||
if (count == null) {
|
||||
count = 0L;//如果不存在,初始化为0
|
||||
}
|
||||
count++;//增加计数
|
||||
this.counts.put(word, count);//存储计数
|
||||
this.collector.emit(new Values(word,count));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public void declareOutputFields(OutputFieldsDeclarer declarer) {
|
||||
// TODO Auto-generated method stub
|
||||
//声明一个输出流,其中tuple包括了单词和对应的计数,向后发射
|
||||
//其他bolt可以订阅这个数据流进一步处理
|
||||
declarer.declare(new Fields("word","count"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* Title: package-info
|
||||
* Description:
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年12月29日
|
||||
*/
|
||||
package com.pancm.bigdata.storm.example1;
|
||||
60
src/main/java/com/pancm/bigdata/storm/one/WordCountApp.java
Normal file
60
src/main/java/com/pancm/bigdata/storm/one/WordCountApp.java
Normal file
@@ -0,0 +1,60 @@
|
||||
package com.pancm.bigdata.storm.one;
|
||||
|
||||
import org.apache.storm.Config;
|
||||
import org.apache.storm.LocalCluster;
|
||||
import org.apache.storm.StormSubmitter;
|
||||
import org.apache.storm.generated.AlreadyAliveException;
|
||||
import org.apache.storm.generated.AuthorizationException;
|
||||
import org.apache.storm.generated.InvalidTopologyException;
|
||||
import org.apache.storm.generated.StormTopology;
|
||||
import org.apache.storm.topology.TopologyBuilder;
|
||||
import org.apache.storm.tuple.Fields;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: WordCountApp
|
||||
* Description: 测试storm本地模式 统计words单次个数
|
||||
* 源代码地址:http://www.tianshouzhi.com/api/tutorials/storm/54
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年12月28日
|
||||
*/
|
||||
public class WordCountApp {
|
||||
public static void main(String[] args) throws InterruptedException, AlreadyAliveException, InvalidTopologyException {
|
||||
//定义拓扑
|
||||
TopologyBuilder builder = new TopologyBuilder();
|
||||
builder.setSpout("word-reader" , new WordReader());
|
||||
builder.setBolt("word-normalizer" , new WordNormalizer()).shuffleGrouping("word-reader" );
|
||||
builder.setBolt("word-counter" , new WordCounter()).fieldsGrouping("word-normalizer" , new Fields("word"));
|
||||
StormTopology topology = builder.createTopology();
|
||||
//配置
|
||||
|
||||
Config conf = new Config();
|
||||
String fileName ="words.txt" ;
|
||||
conf.put("fileName" , fileName );
|
||||
conf.setDebug(false);
|
||||
|
||||
//运行拓扑
|
||||
System.out.println("开始...");
|
||||
if(args !=null&&args.length>0){ //有参数时,表示向集群提交作业,并把第一个参数当做topology名称
|
||||
System.out.println("远程模式");
|
||||
try {
|
||||
StormSubmitter.submitTopology(args[0], conf, topology);
|
||||
} catch (AuthorizationException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else{//没有参数时,本地提交
|
||||
//启动本地模式
|
||||
System.out.println("本地模式");
|
||||
LocalCluster cluster = new LocalCluster();
|
||||
cluster.submitTopology("Getting-Started-Topologie" , conf , topology );
|
||||
Thread.sleep(5000);
|
||||
//关闭本地集群
|
||||
cluster.shutdown();
|
||||
}
|
||||
System.out.println("结束");
|
||||
|
||||
}
|
||||
}
|
||||
84
src/main/java/com/pancm/bigdata/storm/one/WordCounter.java
Normal file
84
src/main/java/com/pancm/bigdata/storm/one/WordCounter.java
Normal file
@@ -0,0 +1,84 @@
|
||||
package com.pancm.bigdata.storm.one;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.storm.task.OutputCollector;
|
||||
import org.apache.storm.task.TopologyContext;
|
||||
import org.apache.storm.topology.IRichBolt;
|
||||
import org.apache.storm.topology.OutputFieldsDeclarer;
|
||||
import org.apache.storm.tuple.Tuple;
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: WordCounter
|
||||
* Description: 该类主要用于统计
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年12月28日
|
||||
*/
|
||||
public class WordCounter implements IRichBolt {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
Integer id;
|
||||
String name;
|
||||
Map<String, Integer> counters;
|
||||
private OutputCollector collector;
|
||||
|
||||
/**
|
||||
* 当Bolt销毁时,我们会显示单词数量
|
||||
*/
|
||||
@Override
|
||||
public void cleanup() {
|
||||
System.out.println("开始显示单词数量...");
|
||||
for (Map.Entry<String, Integer> entry : counters.entrySet()) {
|
||||
System.out.println(entry.getKey() + ": " + entry.getValue());
|
||||
}
|
||||
System.out.println("WordCounter.cleanup()");
|
||||
}
|
||||
|
||||
/**
|
||||
* 为每个单词计数
|
||||
*/
|
||||
@Override
|
||||
public void execute(Tuple input) {
|
||||
System.out.println("WordCounter.execute()");
|
||||
String str = input.getString(0);
|
||||
/**
|
||||
* 如果单词尚不存在于map,我们就创建一个,如果已在,我们就为它加1
|
||||
*/
|
||||
if (!counters.containsKey(str)) {
|
||||
counters.put(str, 1);
|
||||
} else {
|
||||
Integer c = counters.get(str) + 1;
|
||||
counters.put(str, c);
|
||||
}
|
||||
// 对元组作为应答
|
||||
collector.ack(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
@Override
|
||||
public void prepare(Map stormConf, TopologyContext context,
|
||||
OutputCollector collector) {
|
||||
this.counters = new HashMap<String, Integer>();
|
||||
this.collector = collector;
|
||||
this.name = context.getThisComponentId();
|
||||
this.id = context.getThisTaskId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void declareOutputFields(OutputFieldsDeclarer declarer) {
|
||||
System.out.println("WordCounter.declareOutputFields()");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getComponentConfiguration() {
|
||||
System.out.println("WordCounter.getComponentConfiguration()");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package com.pancm.bigdata.storm.one;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.storm.task.OutputCollector;
|
||||
import org.apache.storm.task.TopologyContext;
|
||||
import org.apache.storm.topology.IRichBolt;
|
||||
import org.apache.storm.topology.OutputFieldsDeclarer;
|
||||
import org.apache.storm.tuple.Fields;
|
||||
import org.apache.storm.tuple.Tuple;
|
||||
import org.apache.storm.tuple.Values;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: WordNormalizer
|
||||
* Description:该类主要用于格式化数据
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年12月28日
|
||||
*/
|
||||
public class WordNormalizer implements IRichBolt {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 3644849073824009317L;
|
||||
private OutputCollector collector;
|
||||
|
||||
/**
|
||||
* *bolt*从单词文件接收到文本行,并标准化它。 文本行会全部转化成小写,并切分它,从中得到所有单词。
|
||||
*/
|
||||
public void execute(Tuple input) {
|
||||
System.out.println("WordNormalizer.execute()");
|
||||
String sentence = input.getString(0);
|
||||
String[] words = sentence.split(" ");
|
||||
for (String word : words) {
|
||||
word = word.trim();
|
||||
if (!word.isEmpty()) {
|
||||
word = word.toLowerCase();
|
||||
/* //发布这个单词 */
|
||||
collector.emit(input, new Values(word));
|
||||
}
|
||||
}
|
||||
// 对元组做出应答
|
||||
collector.ack(input);
|
||||
}
|
||||
|
||||
public void prepare(Map stormConf, TopologyContext context,
|
||||
OutputCollector collector) {
|
||||
System.out.println("WordNormalizer.prepare()");
|
||||
this.collector = collector;
|
||||
}
|
||||
|
||||
/**
|
||||
* 这个*bolt*只会发布“word”域
|
||||
*/
|
||||
public void declareOutputFields(OutputFieldsDeclarer declarer) {
|
||||
System.out.println("WordNormalizer.declareOutputFields()");
|
||||
declarer.declare(new Fields("word"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getComponentConfiguration() {
|
||||
System.out.println("WordNormalizer.getComponentConfiguration()");
|
||||
return null;
|
||||
}
|
||||
|
||||
public void cleanup() {
|
||||
System.out.println("WordNormalizer.cleanup()");
|
||||
}
|
||||
}
|
||||
130
src/main/java/com/pancm/bigdata/storm/one/WordReader.java
Normal file
130
src/main/java/com/pancm/bigdata/storm/one/WordReader.java
Normal file
@@ -0,0 +1,130 @@
|
||||
package com.pancm.bigdata.storm.one;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileReader;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.storm.spout.SpoutOutputCollector;
|
||||
import org.apache.storm.task.TopologyContext;
|
||||
import org.apache.storm.topology.IRichSpout;
|
||||
import org.apache.storm.topology.OutputFieldsDeclarer;
|
||||
import org.apache.storm.tuple.Fields;
|
||||
import org.apache.storm.tuple.Values;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: WordReader
|
||||
* Description: 该类主要用于从外部数据源words.txt中获取数据
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年12月28日
|
||||
*/
|
||||
public class WordReader implements IRichSpout {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 6146631397258548505L;
|
||||
private SpoutOutputCollector collector;
|
||||
private FileReader fileReader;
|
||||
BufferedReader reader;
|
||||
private boolean completed = false;
|
||||
|
||||
/**
|
||||
* 这个方法做的惟一一件事情就是分发文件中的文本行
|
||||
*/
|
||||
public void nextTuple() {
|
||||
/**
|
||||
* 这个方法会不断的被调用,直到整个文件都读完了,我们将等待并返回。
|
||||
*/
|
||||
if (completed) {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
// 什么也不做
|
||||
}
|
||||
return;
|
||||
}
|
||||
String str;
|
||||
|
||||
try {
|
||||
int i = 0;
|
||||
// 读所有文本行
|
||||
while ((str = reader.readLine()) != null) {
|
||||
System.out.println("WordReader.nextTuple(),emits time:" + i++);
|
||||
/**
|
||||
* 按行发布一个新值
|
||||
*/
|
||||
this.collector.emit(new Values(str), str);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Error reading tuple", e);
|
||||
} finally {
|
||||
completed = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* 当Spout被创建之后,这个方法会被掉用
|
||||
*/
|
||||
public void open(Map conf, TopologyContext context,
|
||||
SpoutOutputCollector collector) {
|
||||
|
||||
System.out
|
||||
.println("WordReader.open(Map conf, TopologyContext context, SpoutOutputCollector collector)");
|
||||
String fileName = conf.get("fileName").toString();
|
||||
InputStream inputStream = WordReader.class.getClassLoader()
|
||||
.getResourceAsStream(fileName);
|
||||
reader = new BufferedReader(new InputStreamReader(inputStream));
|
||||
this.collector = collector;
|
||||
}
|
||||
|
||||
/**
|
||||
* 声明数据格式,即输出的一个Tuple中,包含几个字段
|
||||
*/
|
||||
public void declareOutputFields(OutputFieldsDeclarer declarer) {
|
||||
System.out
|
||||
.println("WordReader.declareOutputFields(OutputFieldsDeclarer declarer)");
|
||||
declarer.declare(new Fields("line"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void activate() {
|
||||
System.out.println("WordReader.activate()");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deactivate() {
|
||||
System.out.println("WordReader.deactivate()");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getComponentConfiguration() {
|
||||
System.out.println("WordReader.getComponentConfiguration()");
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 当一个Tuple处理成功时,会调用这个方法
|
||||
*/
|
||||
public void ack(Object msgId) {
|
||||
System.out.println("WordReader.ack(Object msgId):" + msgId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当Topology停止时,会调用这个方法
|
||||
*/
|
||||
public void close() {
|
||||
System.out.println("WordReader.close()");
|
||||
}
|
||||
|
||||
/**
|
||||
* 当一个Tuple处理失败时,会调用这个方法
|
||||
*/
|
||||
public void fail(Object msgId) {
|
||||
System.out.println("WordReader.fail(Object msgId):" + msgId);
|
||||
}
|
||||
}
|
||||
11
src/main/java/com/pancm/bigdata/storm/one/package-info.java
Normal file
11
src/main/java/com/pancm/bigdata/storm/one/package-info.java
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* Title: package-info
|
||||
* Description:
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年12月28日
|
||||
*/
|
||||
package com.pancm.bigdata.storm.one;
|
||||
11
src/main/java/com/pancm/bigdata/storm/package-info.java
Normal file
11
src/main/java/com/pancm/bigdata/storm/package-info.java
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* Title: package-info
|
||||
* Description: strom相关代码
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2018年1月11日
|
||||
*/
|
||||
package com.pancm.bigdata.storm;
|
||||
50
src/main/java/com/pancm/bigdata/storm/test/App.java
Normal file
50
src/main/java/com/pancm/bigdata/storm/test/App.java
Normal file
@@ -0,0 +1,50 @@
|
||||
package com.pancm.bigdata.storm.test;
|
||||
|
||||
import org.apache.storm.Config;
|
||||
import org.apache.storm.LocalCluster;
|
||||
import org.apache.storm.StormSubmitter;
|
||||
import org.apache.storm.topology.TopologyBuilder;
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: App
|
||||
* Description:
|
||||
* storm测试
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2018年3月6日
|
||||
*/
|
||||
public class App {
|
||||
|
||||
private static final String str1="test1";
|
||||
private static final String str2="test2";
|
||||
|
||||
public static void main(String[] args) {
|
||||
// TODO Auto-generated method stub
|
||||
//定义一个拓扑
|
||||
TopologyBuilder builder=new TopologyBuilder();
|
||||
builder.setSpout(str1, new TestSpout());
|
||||
builder.setBolt(str2, new TestBolt()).shuffleGrouping(str1);
|
||||
Config conf = new Config();
|
||||
conf.put("test", "test");
|
||||
try{
|
||||
//运行拓扑
|
||||
if(args !=null&&args.length>0){ //有参数时,表示向集群提交作业,并把第一个参数当做topology名称
|
||||
System.out.println("远程模式");
|
||||
StormSubmitter.submitTopology(args[0], conf, builder.createTopology());
|
||||
} else{//没有参数时,本地提交
|
||||
//启动本地模式
|
||||
System.out.println("本地模式");
|
||||
LocalCluster cluster = new LocalCluster();
|
||||
cluster.submitTopology("111" ,conf, builder.createTopology() );
|
||||
// Thread.sleep(2000);
|
||||
// //关闭本地集群
|
||||
// cluster.shutdown();
|
||||
}
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
80
src/main/java/com/pancm/bigdata/storm/test/TestBolt.java
Normal file
80
src/main/java/com/pancm/bigdata/storm/test/TestBolt.java
Normal file
@@ -0,0 +1,80 @@
|
||||
package com.pancm.bigdata.storm.test;
|
||||
|
||||
import java.util.Map;
|
||||
import org.apache.storm.task.OutputCollector;
|
||||
import org.apache.storm.task.TopologyContext;
|
||||
import org.apache.storm.topology.OutputFieldsDeclarer;
|
||||
import org.apache.storm.topology.base.BaseRichBolt;
|
||||
import org.apache.storm.tuple.Tuple;
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: TestBolt
|
||||
* Description:
|
||||
* 用于处理消息
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2018年3月6日
|
||||
*/
|
||||
public class TestBolt extends BaseRichBolt{
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 4743224635827696343L;
|
||||
|
||||
private OutputCollector collector;
|
||||
private long count=1;
|
||||
/**
|
||||
* 在Bolt启动前执行,提供Bolt启动环境配置的入口
|
||||
* 一般对于不可序列化的对象进行实例化。
|
||||
* 注:如果是可以序列化的对象,那么最好是使用构造函数。
|
||||
*/
|
||||
@Override
|
||||
public void prepare(Map map, TopologyContext arg1, OutputCollector collector) {
|
||||
System.out.println("prepare:"+map.get("test"));
|
||||
this.collector=collector;
|
||||
}
|
||||
|
||||
/**
|
||||
* execute()方法是Bolt实现的核心。
|
||||
* 也就是执行方法,每次Bolt从流接收一个订阅的tuple,都会调用这个方法。
|
||||
*/
|
||||
@Override
|
||||
public void execute(Tuple tuple) {
|
||||
/**
|
||||
* 接受消息可以使用这两种方式进行接收。
|
||||
* 个人推荐第二种。
|
||||
*/
|
||||
// String msg=tuple.getString(0);
|
||||
String msg=tuple.getStringByField("test");
|
||||
//这里我们就不做消息的处理,只打印
|
||||
System.out.println("Bolt第"+count+"接受的消息:"+msg);
|
||||
count++;
|
||||
/**
|
||||
*
|
||||
* 没次调用处理一个输入的tuple,所有的tuple都必须在一定时间内应答。
|
||||
* 可以是ack或者fail。否则,spout就会重发tuple。
|
||||
* 如果继承的是IRichBolt,则需要手动ack。
|
||||
* 这里就不用了,BaseRichBolt会自动帮我们应答。
|
||||
*/
|
||||
// collector.ack(tuple);
|
||||
}
|
||||
|
||||
/**
|
||||
* 声明数据格式
|
||||
*/
|
||||
@Override
|
||||
public void declareOutputFields(OutputFieldsDeclarer arg0) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* cleanup是IBolt接口中定义,用于释放bolt占用的资源。
|
||||
* Storm在终止一个bolt之前会调用这个方法。
|
||||
*/
|
||||
@Override
|
||||
public void cleanup() {
|
||||
System.out.println("资源释放");
|
||||
}
|
||||
}
|
||||
92
src/main/java/com/pancm/bigdata/storm/test/TestSpout.java
Normal file
92
src/main/java/com/pancm/bigdata/storm/test/TestSpout.java
Normal file
@@ -0,0 +1,92 @@
|
||||
package com.pancm.bigdata.storm.test;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.storm.spout.SpoutOutputCollector;
|
||||
import org.apache.storm.task.TopologyContext;
|
||||
import org.apache.storm.topology.OutputFieldsDeclarer;
|
||||
import org.apache.storm.topology.base.BaseRichSpout;
|
||||
import org.apache.storm.tuple.Fields;
|
||||
import org.apache.storm.tuple.Values;
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: TestSpout
|
||||
* Description:
|
||||
* Spout 发射器
|
||||
* 用于向Bolt发送消息
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2018年3月6日
|
||||
*/
|
||||
public class TestSpout extends BaseRichSpout{
|
||||
|
||||
private static final long serialVersionUID = 225243592780939490L;
|
||||
|
||||
private SpoutOutputCollector collector;
|
||||
private String message="这是个测试消息!";
|
||||
private static final String field="test";
|
||||
private long count=1;
|
||||
|
||||
|
||||
/**
|
||||
* open()方法中是在ISpout接口中定义,在Spout组件初始化时被调用。
|
||||
* 有三个参数:
|
||||
* 1.Storm配置的Map;
|
||||
* 2.topology中组件的信息;
|
||||
* 3.发射tuple的方法;
|
||||
*/
|
||||
@Override
|
||||
public void open(Map map, TopologyContext arg1, SpoutOutputCollector collector) {
|
||||
System.out.println("open:"+map.get("test"));
|
||||
this.collector = collector;
|
||||
}
|
||||
|
||||
/**
|
||||
* nextTuple()方法是Spout实现的核心。
|
||||
* 也就是主要执行方法,用于输出信息,通过collector.emit方法发射。
|
||||
*/
|
||||
@Override
|
||||
public void nextTuple() {
|
||||
if(count<=2){
|
||||
System.out.println("第"+count+"次开始发送数据...");
|
||||
this.collector.emit(new Values(message));
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* declareOutputFields是在IComponent接口中定义,用于声明数据格式。
|
||||
* 即输出的一个Tuple中,包含几个字段。
|
||||
*/
|
||||
@Override
|
||||
public void declareOutputFields(OutputFieldsDeclarer declarer) {
|
||||
System.out.println("定义格式...");
|
||||
declarer.declare(new Fields(field));
|
||||
}
|
||||
|
||||
/**
|
||||
* 当一个Tuple处理成功时,会调用这个方法
|
||||
*/
|
||||
@Override
|
||||
public void ack(Object obj) {
|
||||
System.out.println("ack:"+obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当Topology停止时,会调用这个方法
|
||||
*/
|
||||
@Override
|
||||
public void close() {
|
||||
System.out.println("关闭...");
|
||||
}
|
||||
|
||||
/**
|
||||
* 当一个Tuple处理失败时,会调用这个方法
|
||||
*/
|
||||
@Override
|
||||
public void fail(Object obj) {
|
||||
System.out.println("失败:"+obj);
|
||||
}
|
||||
}
|
||||
11
src/main/java/com/pancm/bigdata/storm/test/package-info.java
Normal file
11
src/main/java/com/pancm/bigdata/storm/test/package-info.java
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* Title: package-info
|
||||
* Description:
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2018年3月15日
|
||||
*/
|
||||
package com.pancm.bigdata.storm.test;
|
||||
55
src/main/java/com/pancm/bigdata/storm/test2/App.java
Normal file
55
src/main/java/com/pancm/bigdata/storm/test2/App.java
Normal file
@@ -0,0 +1,55 @@
|
||||
package com.pancm.bigdata.storm.test2;
|
||||
|
||||
import org.apache.storm.Config;
|
||||
import org.apache.storm.LocalCluster;
|
||||
import org.apache.storm.StormSubmitter;
|
||||
import org.apache.storm.topology.TopologyBuilder;
|
||||
import org.apache.storm.tuple.Fields;
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: App
|
||||
* Description:
|
||||
* storm测试
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2018年3月6日
|
||||
*/
|
||||
public class App {
|
||||
|
||||
private static final String test_spout="test_spout";
|
||||
private static final String test_bolt="test_bolt";
|
||||
private static final String test2_bolt="test2_bolt";
|
||||
|
||||
public static void main(String[] args) {
|
||||
//定义一个拓扑
|
||||
TopologyBuilder builder=new TopologyBuilder();
|
||||
//设置两个Executeor(线程),默认一个
|
||||
builder.setSpout(test_spout, new TestSpout(),2);
|
||||
//shuffleGrouping:表示是随机分组
|
||||
//设置两个Executeor(线程),和两个task
|
||||
builder.setBolt(test_bolt, new TestBolt(),2).setNumTasks(2).shuffleGrouping(test_spout);
|
||||
//fieldsGrouping:表示是按字段分组
|
||||
//设置两个Executeor(线程),和两个task
|
||||
builder.setBolt(test2_bolt, new Test2Bolt(),2).setNumTasks(2).fieldsGrouping(test_bolt, new Fields("count"));
|
||||
Config conf = new Config();
|
||||
conf.put("test", "test");
|
||||
try{
|
||||
//运行拓扑
|
||||
if(args !=null&&args.length>0){ //有参数时,表示向集群提交作业,并把第一个参数当做topology名称
|
||||
System.out.println("运行远程模式");
|
||||
StormSubmitter.submitTopology(args[0], conf, builder.createTopology());
|
||||
} else{//没有参数时,本地提交
|
||||
//启动本地模式
|
||||
System.out.println("运行本地模式");
|
||||
LocalCluster cluster = new LocalCluster();
|
||||
cluster.submitTopology("Word-counts" ,conf, builder.createTopology() );
|
||||
Thread.sleep(20000);
|
||||
// //关闭本地集群
|
||||
cluster.shutdown();
|
||||
}
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
89
src/main/java/com/pancm/bigdata/storm/test2/Test2Bolt.java
Normal file
89
src/main/java/com/pancm/bigdata/storm/test2/Test2Bolt.java
Normal file
@@ -0,0 +1,89 @@
|
||||
package com.pancm.bigdata.storm.test2;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.storm.task.OutputCollector;
|
||||
import org.apache.storm.task.TopologyContext;
|
||||
import org.apache.storm.topology.OutputFieldsDeclarer;
|
||||
import org.apache.storm.topology.base.BaseRichBolt;
|
||||
import org.apache.storm.tuple.Tuple;
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: Test2Bolt
|
||||
* Description:
|
||||
* 统计单词出现的次数
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2018年3月16日
|
||||
*/
|
||||
public class Test2Bolt extends BaseRichBolt{
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 4743224635827696343L;
|
||||
|
||||
|
||||
/**
|
||||
* 保存单词和对应的计数
|
||||
*/
|
||||
private HashMap<String, Integer> counts = null;
|
||||
|
||||
private long count=1;
|
||||
/**
|
||||
* 在Bolt启动前执行,提供Bolt启动环境配置的入口
|
||||
* 一般对于不可序列化的对象进行实例化。
|
||||
* 注:如果是可以序列化的对象,那么最好是使用构造函数。
|
||||
*/
|
||||
@Override
|
||||
public void prepare(Map map, TopologyContext arg1, OutputCollector collector) {
|
||||
System.out.println("prepare:"+map.get("test"));
|
||||
this.counts=new HashMap<String, Integer>();
|
||||
}
|
||||
|
||||
/**
|
||||
* execute()方法是Bolt实现的核心。
|
||||
* 也就是执行方法,每次Bolt从流接收一个订阅的tuple,都会调用这个方法。
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public void execute(Tuple tuple) {
|
||||
String msg=tuple.getStringByField("count");
|
||||
System.out.println("第"+count+"次统计单词出现的次数");
|
||||
/**
|
||||
* 如果不包含该单词,说明在该map是第一次出现
|
||||
* 否则进行加1
|
||||
*/
|
||||
if (!counts.containsKey(msg)) {
|
||||
counts.put(msg, 1);
|
||||
} else {
|
||||
counts.put(msg, counts.get(msg)+1);
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* cleanup是IBolt接口中定义,用于释放bolt占用的资源。
|
||||
* Storm在终止一个bolt之前会调用这个方法。
|
||||
*/
|
||||
@Override
|
||||
public void cleanup() {
|
||||
System.out.println("===========开始显示单词数量============");
|
||||
for (Map.Entry<String, Integer> entry : counts.entrySet()) {
|
||||
System.out.println(entry.getKey() + ": " + entry.getValue());
|
||||
}
|
||||
System.out.println("===========结束============");
|
||||
System.out.println("Test2Bolt的资源释放");
|
||||
}
|
||||
|
||||
/**
|
||||
* 声明数据格式
|
||||
*/
|
||||
@Override
|
||||
public void declareOutputFields(OutputFieldsDeclarer arg0) {
|
||||
|
||||
}
|
||||
}
|
||||
74
src/main/java/com/pancm/bigdata/storm/test2/TestBolt.java
Normal file
74
src/main/java/com/pancm/bigdata/storm/test2/TestBolt.java
Normal file
@@ -0,0 +1,74 @@
|
||||
package com.pancm.bigdata.storm.test2;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.storm.task.OutputCollector;
|
||||
import org.apache.storm.task.TopologyContext;
|
||||
import org.apache.storm.topology.OutputFieldsDeclarer;
|
||||
import org.apache.storm.topology.base.BaseRichBolt;
|
||||
import org.apache.storm.tuple.Fields;
|
||||
import org.apache.storm.tuple.Tuple;
|
||||
import org.apache.storm.tuple.Values;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: TestBolt
|
||||
* Description:
|
||||
* 对单词进行分割
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2018年3月16日
|
||||
*/
|
||||
public class TestBolt extends BaseRichBolt{
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 4743224635827696343L;
|
||||
|
||||
private OutputCollector collector;
|
||||
|
||||
/**
|
||||
* 在Bolt启动前执行,提供Bolt启动环境配置的入口
|
||||
* 一般对于不可序列化的对象进行实例化。
|
||||
* 注:如果是可以序列化的对象,那么最好是使用构造函数。
|
||||
*/
|
||||
@Override
|
||||
public void prepare(Map map, TopologyContext arg1, OutputCollector collector) {
|
||||
System.out.println("prepare:"+map.get("test"));
|
||||
this.collector=collector;
|
||||
}
|
||||
|
||||
/**
|
||||
* execute()方法是Bolt实现的核心。
|
||||
* 也就是执行方法,每次Bolt从流接收一个订阅的tuple,都会调用这个方法。
|
||||
*/
|
||||
@Override
|
||||
public void execute(Tuple tuple) {
|
||||
String msg=tuple.getStringByField("word");
|
||||
System.out.println("开始分割单词:"+msg);
|
||||
String[] words = msg.toLowerCase().split(" ");
|
||||
for (String word : words) {
|
||||
this.collector.emit(new Values(word));//向下一个bolt发射数据
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 声明数据格式
|
||||
*/
|
||||
@Override
|
||||
public void declareOutputFields(OutputFieldsDeclarer declarer) {
|
||||
declarer.declare(new Fields("count"));
|
||||
}
|
||||
|
||||
/**
|
||||
* cleanup是IBolt接口中定义,用于释放bolt占用的资源。
|
||||
* Storm在终止一个bolt之前会调用这个方法。
|
||||
*/
|
||||
@Override
|
||||
public void cleanup() {
|
||||
System.out.println("TestBolt的资源释放");
|
||||
}
|
||||
}
|
||||
96
src/main/java/com/pancm/bigdata/storm/test2/TestSpout.java
Normal file
96
src/main/java/com/pancm/bigdata/storm/test2/TestSpout.java
Normal file
@@ -0,0 +1,96 @@
|
||||
package com.pancm.bigdata.storm.test2;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.storm.spout.SpoutOutputCollector;
|
||||
import org.apache.storm.task.TopologyContext;
|
||||
import org.apache.storm.topology.OutputFieldsDeclarer;
|
||||
import org.apache.storm.topology.base.BaseRichSpout;
|
||||
import org.apache.storm.tuple.Fields;
|
||||
import org.apache.storm.tuple.Values;
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: TestSpout
|
||||
* Description:
|
||||
* 发送信息
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2018年3月6日
|
||||
*/
|
||||
public class TestSpout extends BaseRichSpout{
|
||||
|
||||
private static final long serialVersionUID = 225243592780939490L;
|
||||
|
||||
private SpoutOutputCollector collector;
|
||||
private static final String field="word";
|
||||
private int count=1;
|
||||
private String[] message = {
|
||||
"My nickname is xuwujing",
|
||||
"My blog address is http://www.panchengming.com/",
|
||||
"My interest is playing games"
|
||||
};
|
||||
|
||||
/**
|
||||
* open()方法中是在ISpout接口中定义,在Spout组件初始化时被调用。
|
||||
* 有三个参数:
|
||||
* 1.Storm配置的Map;
|
||||
* 2.topology中组件的信息;
|
||||
* 3.发射tuple的方法;
|
||||
*/
|
||||
@Override
|
||||
public void open(Map map, TopologyContext arg1, SpoutOutputCollector collector) {
|
||||
System.out.println("open:"+map.get("test"));
|
||||
this.collector = collector;
|
||||
}
|
||||
|
||||
/**
|
||||
* nextTuple()方法是Spout实现的核心。
|
||||
* 也就是主要执行方法,用于输出信息,通过collector.emit方法发射。
|
||||
*/
|
||||
@Override
|
||||
public void nextTuple() {
|
||||
|
||||
if(count<=message.length){
|
||||
System.out.println("第"+count +"次开始发送数据...");
|
||||
this.collector.emit(new Values(message[count-1]));
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* declareOutputFields是在IComponent接口中定义,用于声明数据格式。
|
||||
* 即输出的一个Tuple中,包含几个字段。
|
||||
*/
|
||||
@Override
|
||||
public void declareOutputFields(OutputFieldsDeclarer declarer) {
|
||||
System.out.println("定义格式...");
|
||||
declarer.declare(new Fields(field));
|
||||
}
|
||||
|
||||
/**
|
||||
* 当一个Tuple处理成功时,会调用这个方法
|
||||
*/
|
||||
@Override
|
||||
public void ack(Object obj) {
|
||||
System.out.println("ack:"+obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当Topology停止时,会调用这个方法
|
||||
*/
|
||||
@Override
|
||||
public void close() {
|
||||
System.out.println("关闭...");
|
||||
}
|
||||
|
||||
/**
|
||||
* 当一个Tuple处理失败时,会调用这个方法
|
||||
*/
|
||||
@Override
|
||||
public void fail(Object obj) {
|
||||
System.out.println("失败:"+obj);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* Title: package-info
|
||||
* Description:
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2018年3月15日
|
||||
*/
|
||||
package com.pancm.bigdata.storm.test2;
|
||||
84
src/main/java/com/pancm/bigdata/zookeeper/ZookeeperTest.java
Normal file
84
src/main/java/com/pancm/bigdata/zookeeper/ZookeeperTest.java
Normal file
@@ -0,0 +1,84 @@
|
||||
package com.pancm.bigdata.zookeeper;
|
||||
|
||||
import org.apache.zookeeper.CreateMode;
|
||||
import org.apache.zookeeper.WatchedEvent;
|
||||
import org.apache.zookeeper.Watcher;
|
||||
import org.apache.zookeeper.ZooDefs.Ids;
|
||||
import org.apache.zookeeper.ZooKeeper;
|
||||
|
||||
/**
|
||||
*
|
||||
* @Title: ZookeeperTest
|
||||
* @Description:
|
||||
* zookeeper测试
|
||||
* @Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2018年4月28日
|
||||
*/
|
||||
public class ZookeeperTest {
|
||||
private static String url="master:2181";
|
||||
private static ZooKeeper zk;
|
||||
private static int CONNECTION_TIMEOUT=30000;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
// 创建一个与服务器的连接
|
||||
zk = new ZooKeeper(url ,
|
||||
CONNECTION_TIMEOUT, new Watcher() {
|
||||
// 监控所有被触发的事件
|
||||
public void process(WatchedEvent event) {
|
||||
System.out.println(event.getPath()+"已经触发了" + event.getType() + "事件!");
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* 创建一个给定的目录节点 path, 并给它设置数据,
|
||||
* CreateMode 标识有四种形式的目录节点,分别是
|
||||
* PERSISTENT:持久化目录节点,这个目录节点存储的数据不会丢失;
|
||||
* PERSISTENT_SEQUENTIAL:顺序自动编号的目录节点,这种目录节点会根据当前已近存在的节点数自动加 1,
|
||||
* 然后返回给客户端已经成功创建的目录节点名;
|
||||
* EPHEMERAL:临时目录节点,一旦创建这个节点的客户端与服务器端口也就是 session 超时,这种节点会被自动删除;
|
||||
* EPHEMERAL_SEQUENTIAL:临时自动编号节点
|
||||
*/
|
||||
|
||||
// 创建一个父级目录节点
|
||||
if(zk.exists("/test", true)==null){
|
||||
//参数说明:目录,参数,参数权限,节点类型
|
||||
zk.create("/test", "data1".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
|
||||
}
|
||||
if(zk.exists("/test/test1", true)==null){
|
||||
// 创建一个子目录节点
|
||||
zk.create("/test/test1", "data2".getBytes(), Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);
|
||||
}
|
||||
|
||||
System.out.println("="+new String(zk.getData("/test",false,null)));
|
||||
// 取出子目录节点列表
|
||||
System.out.println("=="+zk.getChildren("/test",true));
|
||||
|
||||
if(zk.exists("/test/test1", true)!=null){
|
||||
// 修改子目录节点数据
|
||||
zk.setData("/test/test1","testOne".getBytes(),-1);
|
||||
}
|
||||
System.out.println("目录节点状态:["+zk.exists("/test",true)+"]");
|
||||
if(zk.exists("/test/test1", true)!=null){
|
||||
// 创建另外一个子目录节点
|
||||
zk.create("/test/test2", "test2".getBytes(), Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);
|
||||
}
|
||||
System.out.println("==="+new String(zk.getData("/test/test2",true,null)));
|
||||
|
||||
/*
|
||||
* 删除 path 对应的目录节点,version 为 -1 可以匹配任何版本,也就删除了这个目录节点所有数据
|
||||
*/
|
||||
// 删除子目录节点
|
||||
zk.delete("/test/test2",-1);
|
||||
zk.delete("/test/test1",-1);
|
||||
|
||||
// 删除父目录节点
|
||||
zk.delete("/test",-1);
|
||||
// 关闭连接
|
||||
zk.close();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* @Title: package-info
|
||||
* @Description: zookeeper相关代码
|
||||
* @Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2018年4月28日
|
||||
*/
|
||||
package com.pancm.bigdata.zookeeper;
|
||||
132
src/main/java/com/pancm/commons/apache/CommonsTest.java
Normal file
132
src/main/java/com/pancm/commons/apache/CommonsTest.java
Normal file
@@ -0,0 +1,132 @@
|
||||
package com.pancm.commons.apache;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.collections.Bag;
|
||||
import org.apache.commons.collections.BidiMap;
|
||||
import org.apache.commons.collections.Factory;
|
||||
import org.apache.commons.collections.HashBag;
|
||||
import org.apache.commons.collections.bidimap.TreeBidiMap;
|
||||
import org.apache.commons.collections.list.LazyList;
|
||||
import org.apache.commons.lang.RandomStringUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang.WordUtils;
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: langTest
|
||||
* Description: Apache commons工具包测试
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年10月30日
|
||||
*/
|
||||
public class CommonsTest {
|
||||
|
||||
public static void main(String[] args) {
|
||||
stringTest();
|
||||
otherTest();
|
||||
}
|
||||
|
||||
/**
|
||||
* StringUtils 相关测试
|
||||
*/
|
||||
private static void stringTest(){
|
||||
/*
|
||||
* 空指针判断
|
||||
*/
|
||||
String str="";
|
||||
String str2=null;
|
||||
String str3=" ";
|
||||
System.out.println(":"+StringUtils.isEmpty(str)); //:true
|
||||
System.out.println("null:"+StringUtils.isEmpty(str2)); //null:true
|
||||
System.out.println(" :"+StringUtils.isEmpty(str3)); // :false
|
||||
|
||||
/*
|
||||
* 判断是否为数字
|
||||
*/
|
||||
String str4="123";
|
||||
String str5="12 3";
|
||||
String str6="123QD#";
|
||||
System.out.println("str4:"+StringUtils.isNumeric(str4));//str4:true
|
||||
System.out.println("str5:"+StringUtils.isNumeric(str5));//str5:false
|
||||
System.out.println("str6:"+StringUtils.isNumeric(str6));//str6:false
|
||||
|
||||
/*
|
||||
* 统计子字符串出现的次数
|
||||
*/
|
||||
String str7="abcdefgfedccfg";
|
||||
String str8="ac";
|
||||
String str9="c";
|
||||
System.out.println("count:"+StringUtils.countMatches(str7, str8));//count:0
|
||||
System.out.println("count:"+StringUtils.countMatches(str7, str9));//count:3
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 其他的测试
|
||||
*/
|
||||
private static void otherTest(){
|
||||
System.out.println("十位数字随机数:"+RandomStringUtils.randomNumeric(10)); //0534110685
|
||||
System.out.println("十位字母随机数:"+RandomStringUtils.randomAlphabetic(10)); //jLWiHdQhHg
|
||||
System.out.println("十位ASCII随机数:"+RandomStringUtils.randomAscii(10)); //8&[bxy%h_-
|
||||
String str="hello world,why are you so happy";
|
||||
System.out.println("首字符大写:"+WordUtils.capitalize(str)); //:Hello World,why Are You So Happy
|
||||
}
|
||||
|
||||
/**
|
||||
* Bag 测试
|
||||
* 主要测试重复元素的统计
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
private static void bagTest(){
|
||||
//定义4种球
|
||||
Bag box=new HashBag(Arrays.asList("red","blue","black","green"));
|
||||
System.out.println("box.getCount():"+box.getCount("red"));//box.getCount():1
|
||||
box.add("red", 5);//红色的球增加五个
|
||||
System.out.println("box.size():"+box.size()); //box.size():9
|
||||
System.out.println("box.getCount():"+box.getCount("red"));//box.getCount():6
|
||||
}
|
||||
|
||||
/**
|
||||
* Lazy测试
|
||||
* 需要该元素的时候,才会生成
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static void lazyTest(){
|
||||
List<String> lazy=LazyList.decorate(new ArrayList<>(), new Factory() {
|
||||
@Override
|
||||
public Object create() {
|
||||
return "Hello";
|
||||
}
|
||||
});
|
||||
//访问了第三个元素,此时0和1位null
|
||||
//get几就增加了几加一 , 输出依旧是 Hello
|
||||
String str=lazy.get(2);
|
||||
System.out.println("str:"+str);//str:Hello
|
||||
//加入的第四个元素
|
||||
lazy.add("world");
|
||||
//元素总个为4个
|
||||
System.out.println("lazy.size():"+lazy.size());//lazy.size():4
|
||||
}
|
||||
|
||||
/**
|
||||
* 双向Map
|
||||
* 唯一的key和map,可以通过键或值来操作
|
||||
* 比如删除、查询等
|
||||
*/
|
||||
private static void bidimapTest(){
|
||||
BidiMap map=new TreeBidiMap();
|
||||
map.put(1, "a");
|
||||
map.put(2, "b");
|
||||
map.put(3, "c");
|
||||
System.out.println("map:"+map); //map:{1=a, 2=b, 3=c}
|
||||
System.out.println("map.get():"+map.get(2)); //map.get():b
|
||||
System.out.println("map.getKey():"+map.getKey("a")); //map.getKey():1
|
||||
System.out.println("map.removeValue():"+map.removeValue("c")); //map.removeValue():3
|
||||
System.out.println("map:"+map); //map:{1=a, 2=b}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
154
src/main/java/com/pancm/commons/google/GuavaTest.java
Normal file
154
src/main/java/com/pancm/commons/google/GuavaTest.java
Normal file
@@ -0,0 +1,154 @@
|
||||
package com.pancm.commons.google;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.HashBasedTable;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.Table;
|
||||
import com.google.common.primitives.Ints;
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: guavaTest
|
||||
* Description:谷歌 guava 工具包测试
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年10月30日
|
||||
*/
|
||||
public class GuavaTest {
|
||||
|
||||
public static void main(String[] args) {
|
||||
noChangeList();
|
||||
one2MoreMap();
|
||||
more2One();
|
||||
filtedMap();
|
||||
joiner();
|
||||
splitter();
|
||||
integer();
|
||||
}
|
||||
|
||||
/**
|
||||
* 不可变集合测试
|
||||
*/
|
||||
private static void noChangeList(){
|
||||
ImmutableList<String> list=ImmutableList.of("A","B","C");
|
||||
ImmutableMap<Integer,String> map=ImmutableMap.of(1,"壹",2,"贰",3,"叁");
|
||||
System.out.println("ImmutableList:"+list); //ImmutableList:[A, B, C]
|
||||
System.out.println("ImmutableMap:"+map); //ImmutableMap:{1=壹, 2=贰, 3=叁}
|
||||
|
||||
//下面运行直接报错,因为这是不可变集合
|
||||
// list.add("D");
|
||||
// map.put(4, "肆");
|
||||
}
|
||||
|
||||
/**
|
||||
* map中多个键的测试
|
||||
* 例如:一个人多个电话
|
||||
*/
|
||||
private static void one2MoreMap(){
|
||||
Multimap<String,String> map= ArrayListMultimap.create();
|
||||
map.put("路人甲", "123");
|
||||
map.put("路人甲", "234");
|
||||
map.put("路人乙", "567");
|
||||
map.put("路人乙", "890");
|
||||
System.out.println("Multimap:"+map); //Multimap:{路人乙=[567, 890], 路人甲=[123, 234]}
|
||||
System.out.println("get:"+map.get("路人乙")); //get:[567, 890]
|
||||
}
|
||||
|
||||
/**
|
||||
* 多个键值对一个值
|
||||
* 例如:坐标
|
||||
*/
|
||||
private static void more2One(){
|
||||
Table<Double, Double, String> table=HashBasedTable.create();
|
||||
table.put(22.54, 114.01, "深圳");
|
||||
table.put(39.96, 116.40, "北京");
|
||||
System.out.println("Table:"+table); //Table:{22.54={114.01=深圳}, 39.96={116.4=北京}}
|
||||
System.out.println("Table.get:"+table.get(22.54, 114.01));//Table.get:深圳
|
||||
}
|
||||
|
||||
/**
|
||||
* Map的过滤
|
||||
* 例如:查找该集合中大于20岁的人
|
||||
*/
|
||||
private static void filtedMap(){
|
||||
Map<String,Integer> map=new HashMap<String,Integer>();
|
||||
map.put("张三", 19);
|
||||
map.put("李四", 20);
|
||||
map.put("王五", 21);
|
||||
Map<String,Integer> filtedmap =Maps.filterValues(map,
|
||||
new Predicate<Integer>(){
|
||||
@Override
|
||||
public boolean apply(Integer age) {
|
||||
return age>20;
|
||||
}
|
||||
});
|
||||
System.out.println("Map:"+map); //Map:{张三=19, 李四=20, 王五=21}
|
||||
System.out.println("filtedmap:"+filtedmap);//filtedmap:{王五=21}
|
||||
}
|
||||
|
||||
/**
|
||||
* Joiner连接测试
|
||||
* 不局限于连接String,如果是null,会直接跳过
|
||||
*
|
||||
*/
|
||||
private static void joiner(){
|
||||
//设置连接符
|
||||
//如:设置为 "和",拼接 “你”,“我” 就变成了“你和我”
|
||||
Joiner joiner=Joiner.on(",");
|
||||
String str=joiner.skipNulls().join("你好","java");
|
||||
Map<String,String> map=new HashMap<String,String>();
|
||||
map.put("张三", "你好");
|
||||
map.put("李四", "嗨");
|
||||
//设置键值的连接符以及键与值之间的连接符
|
||||
String str1=Joiner.on(",").withKeyValueSeparator(":").join(map);
|
||||
System.out.println("Joiner: "+str); //Joiner: 你好,java
|
||||
System.out.println("Joiner: "+str1); //Joiner: 张三:你好,李四:嗨
|
||||
}
|
||||
|
||||
/**
|
||||
* Splitter拆分测试
|
||||
*/
|
||||
private static void splitter(){
|
||||
String str="你好,java";
|
||||
//按字符分割
|
||||
for(String s:Splitter.on(",").split(str)){
|
||||
System.out.println("s:"+s);
|
||||
}
|
||||
//按固定长度分割
|
||||
for(String d:Splitter.fixedLength(2).split(str)){
|
||||
System.out.println("d:"+d);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 基本类型测试
|
||||
*/
|
||||
private static void integer(){
|
||||
int []ints={1,4,3,2};
|
||||
//找到里面的最大值
|
||||
System.out.println("max:"+Ints.max(ints)); //max:4
|
||||
|
||||
List<Integer> list=new ArrayList<Integer>();
|
||||
list.add(1);
|
||||
list.add(3);
|
||||
list.add(6);
|
||||
//包装类型集合转变为基本类型集合
|
||||
int []arr=Ints.toArray(list);
|
||||
for(int i=0,j=arr.length;i<j;i++){
|
||||
System.out.println("arr:"+arr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
101
src/main/java/com/pancm/commons/others/JodaTest.java
Normal file
101
src/main/java/com/pancm/commons/others/JodaTest.java
Normal file
@@ -0,0 +1,101 @@
|
||||
package com.pancm.commons.others;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.joda.time.Hours;
|
||||
import org.joda.time.MutableDateTime;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: JodaTest
|
||||
* Description: Joda 时间工具包测试
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年11月1日
|
||||
*/
|
||||
public class JodaTest {
|
||||
|
||||
public static void main(String[] args) {
|
||||
jodaTest();
|
||||
}
|
||||
|
||||
/**
|
||||
* 日期方法
|
||||
*/
|
||||
private static void jodaTest(){
|
||||
//当前时间戳
|
||||
DateTime datetime =new DateTime();
|
||||
//当前的英文星期几
|
||||
System.out.println("Week:"+datetime.dayOfWeek().getAsText(Locale.ENGLISH)); //Week:Wednesday
|
||||
//本地的日期格式
|
||||
System.out.println("LocalDate:"+datetime.toLocalDate()); //LocalDate:2017-11-02
|
||||
//本地的当前时间 包含毫秒
|
||||
System.out.println("LocalDateTime:"+datetime.toLocalDateTime()); //LocalDateTime:2017-11-02T08:40:04.529
|
||||
//格式化日期
|
||||
System.out.println("时间:"+datetime.toString(DateTimeFormat.forPattern("yyyy年M月d日")));//时间:2017年11月2日
|
||||
|
||||
//加上100小时之后是星期几(中文)
|
||||
System.out.println("dayOfWeek:"+datetime.plusHours(100).dayOfWeek().getAsText(Locale.CHINA));//dayOfWeek:星期一
|
||||
//加100天的日期
|
||||
System.out.println("toLocalDate():"+datetime.plusDays(100).toLocalDate()); //toLocalDate():2018-02-10
|
||||
//十年前的今天是星期几(默认中文)
|
||||
System.out.println("minusYears():"+datetime.minusYears(10).dayOfWeek().getAsText()); //minusYears():星期五
|
||||
|
||||
//离双11还有多少小时
|
||||
System.out.println("离双11的时间:"+Hours.hoursBetween(datetime,new DateTime("2017-11-11")).getHours()); //离双11的时间:207
|
||||
|
||||
//伦敦的时间:2017-11-02T01:24:15.139Z
|
||||
System.out.println("伦敦的时间:"+datetime.withZone(DateTimeZone.forID("Europe/London")));//伦敦的时间:2017-11-02T01:24:15.139Z
|
||||
|
||||
//标准时间
|
||||
System.out.println("标准时间:"+datetime.withZone(DateTimeZone.UTC));
|
||||
|
||||
//当前可变的时间
|
||||
MutableDateTime mdt=new MutableDateTime();
|
||||
//10年后的时间
|
||||
DateTime dt=datetime.plusYears(10);
|
||||
|
||||
System.out.println("十年之后:"+dt); //2027-11-02T09:06:36.883+08:00
|
||||
|
||||
while(mdt.isBefore(dt)){
|
||||
//循环一次加一天
|
||||
mdt.addDays(1);
|
||||
//是13号,并且是星期五
|
||||
if(mdt.getDayOfMonth()==13&&mdt.getDayOfWeek()==5){
|
||||
//打印出十年内所有的黑色星期五
|
||||
System.out.println("黑色星期五:"+mdt);
|
||||
/*
|
||||
* 星期五:2018-04-13T09:13:40.551+08:00
|
||||
星期五:2018-07-13T09:13:40.551+08:00
|
||||
星期五:2019-09-13T09:13:40.551+08:00
|
||||
星期五:2019-12-13T09:13:40.551+08:00
|
||||
星期五:2020-03-13T09:13:40.551+08:00
|
||||
星期五:2020-11-13T09:13:40.551+08:00
|
||||
星期五:2021-08-13T09:13:40.551+08:00
|
||||
星期五:2022-05-13T09:13:40.551+08:00
|
||||
星期五:2023-01-13T09:13:40.551+08:00
|
||||
星期五:2023-10-13T09:13:40.551+08:00
|
||||
星期五:2024-09-13T09:13:40.551+08:00
|
||||
星期五:2024-12-13T09:13:40.551+08:00
|
||||
星期五:2025-06-13T09:13:40.551+08:00
|
||||
星期五:2026-02-13T09:13:40.551+08:00
|
||||
星期五:2026-03-13T09:13:40.551+08:00
|
||||
星期五:2026-11-13T09:13:40.551+08:00
|
||||
星期五:2027-08-13T09:13:40.551+08:00
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
//转换成jdk的Date格式
|
||||
Date jdkDate=datetime.toDate();
|
||||
System.out.println("jdkDate:"+jdkDate); //jdkDate:Thu Nov 02 09:51:13 CST 2017
|
||||
//jdk的Date转换成Joda的Date
|
||||
datetime=new DateTime(jdkDate);
|
||||
System.out.println("JodaDate:"+datetime);//JodaDate:2017-11-02T09:51:13.691+08:00
|
||||
}
|
||||
|
||||
}
|
||||
8
src/main/java/com/pancm/commons/others/package-info.java
Normal file
8
src/main/java/com/pancm/commons/others/package-info.java
Normal file
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* @Title: package-info
|
||||
* @Description: 其它的工具包测试
|
||||
* @Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2018年9月21日
|
||||
*/
|
||||
package com.pancm.commons.others;
|
||||
69
src/main/java/com/pancm/nio/mina/ClientTestServer.java
Normal file
69
src/main/java/com/pancm/nio/mina/ClientTestServer.java
Normal file
@@ -0,0 +1,69 @@
|
||||
package com.pancm.nio.mina;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.apache.mina.core.future.ConnectFuture;
|
||||
import org.apache.mina.core.service.IoConnector;
|
||||
import org.apache.mina.core.session.IoSession;
|
||||
import org.apache.mina.filter.codec.ProtocolCodecFilter;
|
||||
import org.apache.mina.filter.codec.serialization.ObjectSerializationCodecFactory;
|
||||
import org.apache.mina.transport.socket.nio.NioSocketConnector;
|
||||
|
||||
import com.pancm.nio.mina.demo.MinaClientHandler;
|
||||
|
||||
|
||||
/**
|
||||
* @author ZERO
|
||||
* @Data 2017-5-12 上午10:25:57
|
||||
* @Description
|
||||
*/
|
||||
public class ClientTestServer {
|
||||
|
||||
public IoConnector creatClient(){
|
||||
IoConnector connector=new NioSocketConnector();
|
||||
connector.setConnectTimeoutMillis(30000);
|
||||
connector.getFilterChain().addLast("codec",
|
||||
new ProtocolCodecFilter(new ObjectSerializationCodecFactory()));
|
||||
connector.setHandler(new MinaClientHandler());
|
||||
return connector;
|
||||
}
|
||||
public IoSession getIOSession(IoConnector connector){
|
||||
ConnectFuture future = connector.connect(new InetSocketAddress("192.168.2.55", 1255));
|
||||
// 等待是否连接成功,相当于是转异步执行为同步执行。
|
||||
future.awaitUninterruptibly();
|
||||
// 连接成功后获取会话对象。 如果没有上面的等待, 由于connect()方法是异步的, session可能会无法获取。
|
||||
IoSession session = null;
|
||||
try{
|
||||
session = future.getSession();
|
||||
}catch(Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
return session;
|
||||
}
|
||||
public void sendMsg(IoSession session,String msg){
|
||||
|
||||
HashMap<String,String> sy=new HashMap<String, String>();
|
||||
sy.put("channel", "android");
|
||||
sy.put("deviceId", "12-ab");
|
||||
sy.put("device", "1456");
|
||||
sy.put("appVersion", "Version 1.5.1");
|
||||
sy.put("account", "This is test message");
|
||||
|
||||
sy.put("ss","client_bind");
|
||||
// logger.info("SentBody:"+sy);
|
||||
// session.setAttribute("account","hello world");
|
||||
session.write(sy);// 发送消息
|
||||
}
|
||||
public static void main(String[] args) {
|
||||
for(int i=0;i<4000;i++){
|
||||
ClientTestServer client = new ClientTestServer();
|
||||
IoConnector connector = client.creatClient();
|
||||
IoSession session = client.getIOSession(connector);
|
||||
client.sendMsg(session,Arrays.toString(new byte[1000])+":"+System.currentTimeMillis());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
107
src/main/java/com/pancm/nio/mina/demo/MinaClient.java
Normal file
107
src/main/java/com/pancm/nio/mina/demo/MinaClient.java
Normal file
@@ -0,0 +1,107 @@
|
||||
package com.pancm.nio.mina.demo;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.mina.core.future.ConnectFuture;
|
||||
import org.apache.mina.core.service.IoConnector;
|
||||
import org.apache.mina.core.session.IoSession;
|
||||
import org.apache.mina.filter.codec.ProtocolCodecFilter;
|
||||
import org.apache.mina.filter.codec.serialization.ObjectSerializationCodecFactory;
|
||||
import org.apache.mina.transport.socket.nio.NioSocketConnector;
|
||||
|
||||
|
||||
/**
|
||||
* @author ZERO
|
||||
* @version 2017-3-27 下午5:59:54
|
||||
* mina 客户端
|
||||
*/
|
||||
public class MinaClient {
|
||||
private static Logger logger = Logger.getLogger(MinaClient.class);
|
||||
private static String HOST = "127.0.0.1";
|
||||
private static int PORT = 1255;
|
||||
private static IoConnector connector=new NioSocketConnector();
|
||||
private static IoSession session;
|
||||
public static IoConnector getConnector() {
|
||||
return connector;
|
||||
}
|
||||
|
||||
public static void setConnector(IoConnector connector) {
|
||||
MinaClient.connector = connector;
|
||||
}
|
||||
|
||||
/*
|
||||
* 测试服务端与客户端程序!
|
||||
a. 启动服务端,然后再启动客户端
|
||||
b. 服务端接收消息并处理成功;
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public static void main(String[] args) {
|
||||
// 设置链接超时时间
|
||||
connector.setConnectTimeout(30000);
|
||||
// 添加过滤器 可序列话的对象
|
||||
connector.getFilterChain().addLast(
|
||||
"codec",
|
||||
new ProtocolCodecFilter(new ObjectSerializationCodecFactory()));
|
||||
// 添加业务逻辑处理器类
|
||||
connector.setHandler(new MinaClientHandler());
|
||||
ConnectFuture future = connector.connect(new InetSocketAddress(
|
||||
HOST, PORT));// 创建连接
|
||||
future.awaitUninterruptibly();// 等待连接创建完成
|
||||
session = future.getSession();// 获得session
|
||||
|
||||
bindstart();
|
||||
pushstart();
|
||||
}
|
||||
|
||||
public static void bindstart(){
|
||||
logger.info("客户端绑定服务端");
|
||||
// 创建一个非阻塞的客户端程序
|
||||
|
||||
try {
|
||||
|
||||
HashMap<String,String> sy=new HashMap<String, String>();
|
||||
sy.put("channel", "xiaoai");
|
||||
sy.put("deviceId", "12-ab");
|
||||
sy.put("device", "1456");
|
||||
sy.put("appVersion", "Version 1.5.1");
|
||||
sy.put("account", "0030000100009702");
|
||||
|
||||
sy.put("client_bind","client_bind");
|
||||
logger.info("SentBody:"+sy);
|
||||
// session.setAttribute("account","hello world");
|
||||
session.write(sy);// 发送消息
|
||||
logger.info("终端与服务端建立连接成功...发送的消息为:"+sy);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
logger.error("客户端链接异常...", e);
|
||||
}
|
||||
// session.getCloseFuture().awaitUninterruptibly();// 等待连接断开
|
||||
// connector.dispose();
|
||||
}
|
||||
|
||||
public static void pushstart(){
|
||||
logger.info("客户端请求服务端推送");
|
||||
// 创建一个非阻塞的客户端程序
|
||||
// IoConnector connector = new NioSocketConnector();
|
||||
// 设置链接超时时间
|
||||
try {
|
||||
HashMap<String,String> sy=new HashMap<String, String>();
|
||||
sy.put("closeTV", "closeTV");
|
||||
sy.put("account", "0030000100009702"); //账号
|
||||
|
||||
sy.put("put","client_online");
|
||||
logger.info("SentBody:"+sy.toString());
|
||||
// session.setAttribute("account","hello world");
|
||||
session.write(sy);// 发送消息
|
||||
logger.info("客户端与服务端建立连接成功...发送的消息为:"+sy);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
logger.error("客户端链接异常...", e);
|
||||
}
|
||||
// session.getCloseFuture().awaitUninterruptibly();// 等待连接断开
|
||||
// connector.dispose();
|
||||
}
|
||||
|
||||
}
|
||||
33
src/main/java/com/pancm/nio/mina/demo/MinaClientHandler.java
Normal file
33
src/main/java/com/pancm/nio/mina/demo/MinaClientHandler.java
Normal file
@@ -0,0 +1,33 @@
|
||||
package com.pancm.nio.mina.demo;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.mina.core.service.IoHandlerAdapter;
|
||||
import org.apache.mina.core.session.IoSession;
|
||||
|
||||
|
||||
/**
|
||||
* @author ZERO
|
||||
* @version 2017-3-27 ??6:01:31
|
||||
* 客户端handle
|
||||
*/
|
||||
public class MinaClientHandler extends IoHandlerAdapter {
|
||||
private static Logger logger = Logger.getLogger(MinaClientHandler.class);
|
||||
|
||||
@Override
|
||||
public void messageReceived(IoSession session, Object message)
|
||||
throws Exception {
|
||||
String msg = message.toString();
|
||||
logger.info("客户端接收的数据:" + msg);
|
||||
// if(msg.equals(XiaoaiConstant.CMD_HEARTBEAT_REQUEST)){
|
||||
logger.warn("成功收到心跳包");
|
||||
// session.write(XiaoaiConstant.CMD_HEARTBEAT_RESPONSE);
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(IoSession session, Throwable cause)
|
||||
throws Exception {
|
||||
logger.error("发生错误...", cause);
|
||||
}
|
||||
}
|
||||
58
src/main/java/com/pancm/nio/mina/demo/MinaServer.java
Normal file
58
src/main/java/com/pancm/nio/mina/demo/MinaServer.java
Normal file
@@ -0,0 +1,58 @@
|
||||
package com.pancm.nio.mina.demo;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.mina.core.service.IoAcceptor;
|
||||
import org.apache.mina.core.session.IdleStatus;
|
||||
import org.apache.mina.filter.codec.ProtocolCodecFilter;
|
||||
import org.apache.mina.filter.codec.serialization.ObjectSerializationCodecFactory;
|
||||
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
|
||||
|
||||
|
||||
/**
|
||||
* @author ZERO:
|
||||
* @version 2017-3-27 下午3:20:11
|
||||
* 创建服务端
|
||||
*/
|
||||
public class MinaServer {
|
||||
//记录日志
|
||||
public static Logger logger=Logger.getLogger(MinaServer.class);
|
||||
private static int PORT=3333;
|
||||
|
||||
/* 启动此类 提示服务端运行成功后
|
||||
* Windows 命令 输入 telnet 127.0.0.1 3305
|
||||
* 然后输入消息 message
|
||||
* 消息为bye的时候关闭连接
|
||||
* */
|
||||
public static void main(String[] args) {
|
||||
IoAcceptor ia=null;
|
||||
try{
|
||||
//创建一个非堵塞的server端Socket
|
||||
ia=new NioSocketAcceptor();
|
||||
//创建 协议编码解码过滤器ProtocolCodecFilter
|
||||
// ProtocolCodecFilter pf=new ProtocolCodecFilter(new TextLineCodecFactory(Charset
|
||||
// .forName("UTF-8"),
|
||||
// LineDelimiter.WINDOWS.getValue(),
|
||||
// LineDelimiter.WINDOWS.getValue()));
|
||||
//设置端口
|
||||
InetSocketAddress pt=new InetSocketAddress(PORT);
|
||||
// 设置过滤器(使用Mina提供的文本换行符编解码器)
|
||||
ia.getFilterChain().addLast("codec", new ProtocolCodecFilter(new ObjectSerializationCodecFactory()));
|
||||
//设置读取数据的缓存区大小
|
||||
ia.getSessionConfig().setReadBufferSize(2048);
|
||||
//读写通道10秒内无操作进入空闲状态
|
||||
ia.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);
|
||||
//绑定逻辑处理器
|
||||
ia.setHandler(new MinaServerHandler());
|
||||
//绑定端口
|
||||
ia.bind(pt);
|
||||
logger.info("服务端启动成功...端口号为:"+PORT);
|
||||
|
||||
}catch(Exception e){
|
||||
logger.error("服务器的异常..."+e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
67
src/main/java/com/pancm/nio/mina/demo/MinaServerHandler.java
Normal file
67
src/main/java/com/pancm/nio/mina/demo/MinaServerHandler.java
Normal file
@@ -0,0 +1,67 @@
|
||||
package com.pancm.nio.mina.demo;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Date;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.mina.core.service.IoHandlerAdapter;
|
||||
import org.apache.mina.core.session.IdleStatus;
|
||||
import org.apache.mina.core.session.IoSession;
|
||||
|
||||
|
||||
/**
|
||||
* @author ZERO:
|
||||
* @version 2017-3-27 下午3:59:33
|
||||
* 业务逻辑实现
|
||||
*/
|
||||
public class MinaServerHandler extends IoHandlerAdapter {
|
||||
public static Logger logger=Logger.getLogger(MinaServerHandler.class);
|
||||
|
||||
@Override
|
||||
public void sessionCreated(IoSession iosession) throws Exception{
|
||||
InetSocketAddress sa=(InetSocketAddress)iosession.getRemoteAddress();
|
||||
String address=sa.getAddress().getHostAddress(); //访问的ip
|
||||
logger.info("服务端与客户端创建连接..."+"访问的IP:"+address);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void sessionOpened(IoSession iosession) throws Exception{
|
||||
logger.info("服务端与客户端连接打开...");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void messageReceived(IoSession session,Object message) throws Exception{
|
||||
String msg=message.toString();
|
||||
logger.info("服务端收到的数据为:"+msg);
|
||||
if("bye".equals(msg)){ //服务端断开的条件
|
||||
session.close();
|
||||
}
|
||||
Date date=new Date();
|
||||
session.write(date); //返回给服务端数据
|
||||
}
|
||||
|
||||
@Override
|
||||
public void messageSent(IoSession session, Object message) throws Exception {
|
||||
// session.close(); //发送成功后主动断开与客户端的连接
|
||||
logger.info("服务端发送信息成功...");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sessionClosed(IoSession session) throws Exception {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sessionIdle(IoSession session, IdleStatus status)
|
||||
throws Exception {
|
||||
logger.info("服务端进入空闲状态...");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(IoSession session, Throwable cause)
|
||||
throws Exception {
|
||||
logger.error("服务端发送异常...", cause);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
54
src/main/java/com/pancm/nio/mina/demo1/MinaClient.java
Normal file
54
src/main/java/com/pancm/nio/mina/demo1/MinaClient.java
Normal file
@@ -0,0 +1,54 @@
|
||||
package com.pancm.nio.mina.demo1;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.mina.core.future.ConnectFuture;
|
||||
import org.apache.mina.core.service.IoConnector;
|
||||
import org.apache.mina.core.session.IoSession;
|
||||
import org.apache.mina.filter.codec.ProtocolCodecFilter;
|
||||
import org.apache.mina.transport.socket.nio.NioSocketConnector;
|
||||
|
||||
/**
|
||||
* @author ZERO
|
||||
* @version 2017-3-27 下午5:59:54
|
||||
* mina 客户端
|
||||
*/
|
||||
public class MinaClient {
|
||||
private static Logger logger = Logger.getLogger(MinaClient.class);
|
||||
private static String HOST = "127.0.0.1";
|
||||
private static int PORT = 3305;
|
||||
|
||||
/*
|
||||
* 测试服务端与客户端程序!
|
||||
a. 启动服务端,然后再启动客户端(客户端发送的消息是"why are you so diao ")
|
||||
b. 服务端接收消息并处理成功;
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
// 创建一个非阻塞的客户端程序
|
||||
IoConnector connector = new NioSocketConnector();
|
||||
// 设置链接超时时间
|
||||
connector.setConnectTimeout(30000);
|
||||
ProtocolCodecFilter pf=new ProtocolCodecFilter((new MyTextLineCodecFactory(Charset .forName("utf-8"), "\r\n")));
|
||||
// 添加过滤器
|
||||
connector.getFilterChain().addLast("codec", pf);
|
||||
// 添加业务逻辑处理器类
|
||||
connector.setHandler(new MinaClientHandler());
|
||||
IoSession session = null;
|
||||
try {
|
||||
ConnectFuture future = connector.connect(new InetSocketAddress(
|
||||
HOST, PORT));// 创建连接
|
||||
future.awaitUninterruptibly();// 等待连接创建完成
|
||||
session = future.getSession();// 获得session
|
||||
String msg="hello \r\n";
|
||||
session.write(msg);// 发送消息
|
||||
logger.info("客户端与服务端建立连接成功...发送的消息为:"+msg);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
logger.error("客户端链接异常...", e);
|
||||
}
|
||||
session.getCloseFuture().awaitUninterruptibly();// 等待连接断开
|
||||
connector.dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.pancm.nio.mina.demo1;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.mina.core.service.IoHandlerAdapter;
|
||||
import org.apache.mina.core.session.IoSession;
|
||||
|
||||
/**
|
||||
* @author ZERO
|
||||
* @version 2017-3-27 下午6:01:31
|
||||
* 业务逻辑过滤器代码
|
||||
*/
|
||||
public class MinaClientHandler extends IoHandlerAdapter {
|
||||
private static Logger logger = Logger.getLogger(MinaClientHandler.class);
|
||||
|
||||
@Override
|
||||
public void messageReceived(IoSession session, Object message)
|
||||
throws Exception {
|
||||
String msg = message.toString();
|
||||
logger.info("客户端接收到的信息为:" + msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(IoSession session, Throwable cause)
|
||||
throws Exception {
|
||||
logger.error("客户端发生异常...", cause);
|
||||
}
|
||||
}
|
||||
64
src/main/java/com/pancm/nio/mina/demo1/MinaServer.java
Normal file
64
src/main/java/com/pancm/nio/mina/demo1/MinaServer.java
Normal file
@@ -0,0 +1,64 @@
|
||||
package com.pancm.nio.mina.demo1;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.mina.core.service.IoAcceptor;
|
||||
import org.apache.mina.core.session.IdleStatus;
|
||||
import org.apache.mina.filter.codec.ProtocolCodecFilter;
|
||||
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @author ZERO:
|
||||
* @version 2017-3-28 上午10:20:11
|
||||
* 创建服务端
|
||||
*/
|
||||
public class MinaServer {
|
||||
//记录日志
|
||||
public static Logger logger=Logger.getLogger(MinaServer.class);
|
||||
private static int PORT=3305;
|
||||
|
||||
/* 启动此类 提示服务端运行成功后
|
||||
* Windows 命令 输入 telnet 127.0.0.1 3305
|
||||
* 然后输入消息 message
|
||||
* 消息为bye的时候关闭连接
|
||||
* */
|
||||
public static void main(String[] args) {
|
||||
new MinaServer().start();
|
||||
}
|
||||
|
||||
public void start() {
|
||||
IoAcceptor ia=null;
|
||||
try{
|
||||
//创建一个非堵塞的server端Socket
|
||||
ia=new NioSocketAcceptor();
|
||||
//创建 自定义协议编码解码过滤器ProtocolCodecFilter
|
||||
ProtocolCodecFilter pf=new ProtocolCodecFilter((new MyTextLineCodecFactory(Charset .forName("utf-8"), "\r\n")));
|
||||
//设置端口
|
||||
InetSocketAddress pt=new InetSocketAddress(PORT);
|
||||
// 设置过滤器(使用Mina提供的文本换行符编解码器)
|
||||
ia.getFilterChain().addLast("codec", pf);
|
||||
//设置读取数据的缓存区大小
|
||||
ia.getSessionConfig().setReadBufferSize(2048);
|
||||
//读写通道10秒内无操作进入空闲状态
|
||||
ia.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);
|
||||
//绑定逻辑处理器
|
||||
ia.setHandler(new MinaServerHandler());
|
||||
//绑定端口
|
||||
ia.bind(pt);
|
||||
logger.info("服务端启动成功...端口号为:"+PORT);
|
||||
|
||||
}catch(Exception e){
|
||||
logger.error("服务器的异常..."+e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package com.pancm.nio.mina.demo1;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.mina.core.service.IoHandlerAdapter;
|
||||
import org.apache.mina.core.session.IdleStatus;
|
||||
import org.apache.mina.core.session.IoSession;
|
||||
|
||||
|
||||
/**
|
||||
* @author ZERO:
|
||||
* @version 2017-3-27 下午3:59:33
|
||||
* 业务逻辑实现
|
||||
*/
|
||||
public class MinaServerHandler extends IoHandlerAdapter {
|
||||
public static Logger logger=Logger.getLogger(MinaServerHandler.class);
|
||||
|
||||
@Override
|
||||
public void sessionCreated(IoSession session) throws Exception{
|
||||
logger.info("服务端与客户端创建连接...");
|
||||
super.sessionCreated(session);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void sessionOpened(IoSession session) throws Exception{
|
||||
logger.info("服务端与客户端连接打开...");
|
||||
super.sessionOpened(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void messageReceived(IoSession session,Object message) throws Exception{
|
||||
String msg=message.toString();
|
||||
logger.info("服务端收到的数据为:"+msg);
|
||||
if("bye".equals(msg)){ //服务端断开的条件
|
||||
session.close();
|
||||
}
|
||||
Date date=new Date();
|
||||
String mg="Come on:"+date;
|
||||
logger.info("服务端返回给客户端的数据:"+mg);
|
||||
session.write(mg); //返回给服务端数据
|
||||
}
|
||||
|
||||
@Override
|
||||
public void messageSent(IoSession session, Object message) throws Exception {
|
||||
logger.info("服务端发送数据 = "+message);
|
||||
// session.close(); //发送成功后主动断开与客户端的连接 实现短连接
|
||||
logger.info("服务端发送信息成功...");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sessionClosed(IoSession session) throws Exception {
|
||||
logger.info("断开连接");
|
||||
super.sessionClosed(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sessionIdle(IoSession session, IdleStatus status)
|
||||
throws Exception {
|
||||
logger.info("服务端进入空闲状态...");
|
||||
super.sessionIdle(session, status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(IoSession session, Throwable cause)
|
||||
throws Exception {
|
||||
logger.error("服务端发送异常...", cause);
|
||||
super.exceptionCaught(session, cause);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
package com.pancm.nio.mina.demo1;
|
||||
|
||||
import java.nio.charset.CharacterCodingException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.mina.core.buffer.IoBuffer;
|
||||
import org.apache.mina.core.session.IoSession;
|
||||
import org.apache.mina.filter.codec.ProtocolDecoder;
|
||||
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
|
||||
|
||||
/**
|
||||
* @author ZERO
|
||||
* @version 2017-3-28 上午10:44:55
|
||||
* 设置编码解码器
|
||||
*/
|
||||
|
||||
public class MyTextLineCodecDecoder implements ProtocolDecoder {
|
||||
private static Logger logger = Logger.getLogger(MyTextLineCodecDecoder.class);
|
||||
|
||||
private Charset charset; // 编码格式
|
||||
|
||||
private String delimiter; // 文本分隔符
|
||||
private IoBuffer delimBuf; // 文本分割符匹配的变量
|
||||
|
||||
// 定义常量值,作为每个IoSession中保存解码任务的key值
|
||||
private static String CONTEXT = MyTextLineCodecDecoder.class.getName() + ".context";
|
||||
|
||||
public MyTextLineCodecDecoder(Charset charset,String delimiter){
|
||||
this.charset=charset;
|
||||
this.delimiter=delimiter;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out)
|
||||
throws Exception {
|
||||
Context ctx = getContext(session);
|
||||
if (delimiter == null || "".equals(delimiter)) {
|
||||
// 如果文本换行符未指定,使用默认值
|
||||
delimiter = "\r\n";
|
||||
}
|
||||
|
||||
if (charset == null) {
|
||||
charset = Charset.forName("utf-8");
|
||||
}
|
||||
decodeNormal(ctx, in, out);
|
||||
|
||||
}
|
||||
|
||||
private void decodeNormal(Context ctx, IoBuffer in, ProtocolDecoderOutput out) throws CharacterCodingException {
|
||||
|
||||
// 取出未完成任务中已经匹配的文本换行符的个数
|
||||
int matchCount = ctx.getMatchCount();
|
||||
|
||||
// 设置匹配文本换行符的IoBuffer变量
|
||||
if (delimBuf == null) {
|
||||
IoBuffer tmp = IoBuffer.allocate(2).setAutoExpand(true);
|
||||
tmp.putString(delimiter, charset.newEncoder());
|
||||
tmp.flip();
|
||||
delimBuf = tmp;
|
||||
}
|
||||
|
||||
//解码的IoBuffer中数据的原始信息
|
||||
int oldPos = in.position(); //输出值为0
|
||||
int oldLimit = in.limit(); //输出值为1
|
||||
|
||||
logger.info("******************************************************************************");
|
||||
logger.info("开始进入解码方法-----------------------------------------------------------------");
|
||||
logger.info("");
|
||||
logger.info("init Start--------------------------------------------------------------------");
|
||||
logger.info("in.postion() = "+oldPos);
|
||||
logger.info("in.Limit() = "+oldLimit);
|
||||
logger.info("in.capacity() = "+in.capacity());
|
||||
logger.info("matchCount = "+matchCount);
|
||||
logger.info("init End---------------------------------------------------------------------");
|
||||
logger.info("");
|
||||
|
||||
//变量解码的IoBuffer
|
||||
while (in.hasRemaining()) {
|
||||
|
||||
byte b = in.get();
|
||||
logger.info("");
|
||||
logger.info("输入进来的字符为 = "+(char)b+",对应的ascii值 = "+b);
|
||||
logger.info("in.position() = "+in.position()+",in.limit() = "+in.limit());
|
||||
logger.info("");
|
||||
|
||||
//当b的ascii值为13,10 即为\r,\n时,会进入下述if语句
|
||||
if (delimBuf.get(matchCount) == b) {
|
||||
|
||||
// b='\r'时,matchCount=1, b='\n'时,matchCount=2
|
||||
matchCount++;
|
||||
|
||||
logger.info("matchCount = "+matchCount);
|
||||
//当前匹配到字节个数与文本换行符字节个数相同,即 b='\n'时
|
||||
//此时matchCount=2, delimBuf.limit()=2
|
||||
|
||||
if (matchCount == delimBuf.limit()) {
|
||||
|
||||
// 获得当前匹配到的position(position前所有数据有效)
|
||||
int pos = in.position(); //值为2
|
||||
logger.info("pos = "+pos);
|
||||
|
||||
in.limit(pos); //值为2
|
||||
// position回到原始位置
|
||||
in.position(oldPos); //值为0
|
||||
|
||||
// 追加到Context对象未完成数据后面
|
||||
ctx.append(in); //将 \r\n这两个字符添加到 ctx.getBuf()中
|
||||
|
||||
// in中匹配结束后剩余数据
|
||||
in.limit(oldLimit); //值为2
|
||||
in.position(pos); //值为2
|
||||
|
||||
IoBuffer buf = ctx.getBuf(); //此时是得到 he\r\n
|
||||
buf.flip(); //此时 buf.position=0,buf.limit()=4
|
||||
|
||||
buf.limit(buf.limit() - matchCount); //4-2 = 2
|
||||
try{
|
||||
// 输出解码内容 ,即 he
|
||||
out.write(buf.getString(ctx.getDecoder()));
|
||||
}
|
||||
finally {
|
||||
buf.clear(); // 释放缓存空间
|
||||
}
|
||||
|
||||
matchCount = 0;
|
||||
|
||||
}
|
||||
}else { //h字符,e字符时,均会进入 此else逻辑判断中
|
||||
|
||||
//把in中未解码内容放回buf中
|
||||
//下面会在 输入的字符不是 \r\n时会需要保存使用
|
||||
in.position(oldPos);
|
||||
ctx.append(in);
|
||||
ctx.setMatchCount(matchCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 从IoSession中获取Context对象
|
||||
private Context getContext(IoSession session) {
|
||||
Context ctx;
|
||||
ctx = (Context) session.getAttribute(CONTEXT);
|
||||
|
||||
if (ctx == null) {
|
||||
ctx = new Context();
|
||||
session.setAttribute(CONTEXT, ctx);
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
public void dispose(IoSession arg0) throws Exception {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
public void finishDecode(IoSession arg0, ProtocolDecoderOutput arg1)
|
||||
throws Exception {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
|
||||
// 内部类,保存IoSession解码时未完成的任务
|
||||
private class Context {
|
||||
|
||||
private CharsetDecoder decoder;
|
||||
private IoBuffer buf;
|
||||
// 保存真实解码内容
|
||||
private int matchCount = 0; // 匹配到的文本换行符个数
|
||||
private Context() {
|
||||
decoder = charset.newDecoder();
|
||||
buf = IoBuffer.allocate(80).setAutoExpand(true);
|
||||
}
|
||||
|
||||
// 重置
|
||||
public void reset() {
|
||||
matchCount = 0;
|
||||
decoder.reset();
|
||||
}
|
||||
|
||||
// 追加数据
|
||||
public void append(IoBuffer in) {
|
||||
getBuf().put(in);
|
||||
}
|
||||
|
||||
public CharsetDecoder getDecoder() {
|
||||
return decoder;
|
||||
}
|
||||
|
||||
public IoBuffer getBuf() {
|
||||
return buf;
|
||||
}
|
||||
|
||||
public int getMatchCount() {
|
||||
return matchCount;
|
||||
}
|
||||
|
||||
public void setMatchCount(int matchCount) {
|
||||
this.matchCount = matchCount;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.pancm.nio.mina.demo1;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.mina.core.buffer.IoBuffer;
|
||||
import org.apache.mina.core.session.IoSession;
|
||||
import org.apache.mina.filter.codec.ProtocolEncoder;
|
||||
import org.apache.mina.filter.codec.ProtocolEncoderOutput;
|
||||
|
||||
/**
|
||||
* @author ZERO
|
||||
* @version 2017-3-28 上午11:30:55
|
||||
* 设置编码构造器
|
||||
*/
|
||||
public class MyTextLineCodecEncoder implements ProtocolEncoder{
|
||||
|
||||
private static Logger logger = Logger.getLogger(MyTextLineCodecEncoder.class);
|
||||
|
||||
private Charset charset; // 编码格式
|
||||
private String delimiter; // 文本分隔符
|
||||
public MyTextLineCodecEncoder(Charset charset, String delimiter) {
|
||||
this.charset = charset;
|
||||
this.delimiter = delimiter;
|
||||
}
|
||||
|
||||
public void encode(IoSession session, Object message, ProtocolEncoderOutput out) throws Exception {
|
||||
logger.info("开始进入编码方法-----------------------------------------------------------------");
|
||||
// 如果文本换行符未指定,使用默认值
|
||||
if (delimiter == null || "".equals(delimiter)) {
|
||||
delimiter = "\r\n";
|
||||
}
|
||||
|
||||
if (charset == null) {
|
||||
charset = Charset.forName("utf-8");
|
||||
}
|
||||
|
||||
String value = message.toString();
|
||||
IoBuffer buf = IoBuffer.allocate(value.length()).setAutoExpand(true);
|
||||
//真实数据
|
||||
buf.putString(value, charset.newEncoder());
|
||||
//文本换行符
|
||||
buf.putString(delimiter, charset.newEncoder());
|
||||
buf.flip();
|
||||
out.write(buf);
|
||||
}
|
||||
|
||||
public void dispose(IoSession session) throws Exception {}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.pancm.nio.mina.demo1;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import org.apache.mina.core.session.IoSession;
|
||||
import org.apache.mina.filter.codec.ProtocolCodecFactory;
|
||||
import org.apache.mina.filter.codec.ProtocolDecoder;
|
||||
import org.apache.mina.filter.codec.ProtocolEncoder;
|
||||
|
||||
/**
|
||||
* @author ZERO
|
||||
* @version 2017-3-28 上午11:39:50
|
||||
* 编码格式工厂
|
||||
*/
|
||||
public class MyTextLineCodecFactory implements ProtocolCodecFactory {
|
||||
|
||||
private Charset charset; // 编码格式
|
||||
private String delimiter; // 文本分隔符
|
||||
public MyTextLineCodecFactory(Charset charset, String delimiter) {
|
||||
this.charset = charset;
|
||||
this.delimiter = delimiter;
|
||||
}
|
||||
|
||||
|
||||
public ProtocolDecoder getDecoder(IoSession session) throws Exception {
|
||||
return new MyTextLineCodecDecoder(charset, delimiter);
|
||||
}
|
||||
|
||||
|
||||
public ProtocolEncoder getEncoder(IoSession session) throws Exception {
|
||||
return new MyTextLineCodecEncoder(charset, delimiter);
|
||||
}
|
||||
|
||||
}
|
||||
11
src/main/java/com/pancm/nio/mina/package-info.java
Normal file
11
src/main/java/com/pancm/nio/mina/package-info.java
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* Title: package-info
|
||||
* Description: Mina测试
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017-3-27
|
||||
*/
|
||||
package com.pancm.nio.mina;
|
||||
49
src/main/java/com/pancm/nio/netty/demo/NettyClient.java
Normal file
49
src/main/java/com/pancm/nio/netty/demo/NettyClient.java
Normal file
@@ -0,0 +1,49 @@
|
||||
package com.pancm.nio.netty.demo;
|
||||
|
||||
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
|
||||
import java.io.IOException;
|
||||
/**
|
||||
*
|
||||
* Title: NettyClient
|
||||
* Description: Netty客户端
|
||||
* Version:1.0.0
|
||||
* @author Administrator
|
||||
* @date 2017-8-31
|
||||
*/
|
||||
public class NettyClient {
|
||||
|
||||
public static String host = "127.0.0.1"; //ip地址
|
||||
public static int port = 6789; //端口
|
||||
/// 通过nio方式来接收连接和处理连接
|
||||
private static EventLoopGroup group = new NioEventLoopGroup();
|
||||
private static Bootstrap b = new Bootstrap();
|
||||
private static Channel ch;
|
||||
|
||||
/**
|
||||
* Netty创建全部都是实现自AbstractBootstrap。
|
||||
* 客户端的是Bootstrap,服务端的则是 ServerBootstrap。
|
||||
**/
|
||||
public static void main(String[] args) throws InterruptedException, IOException {
|
||||
System.out.println("客户端成功启动...");
|
||||
b.group(group);
|
||||
b.channel(NioSocketChannel.class);
|
||||
b.handler(new NettyClientFilter());
|
||||
// 连接服务端
|
||||
ch = b.connect(host, port).sync().channel();
|
||||
star();
|
||||
}
|
||||
|
||||
public static void star() throws IOException{
|
||||
String str="Hello Netty";
|
||||
ch.writeAndFlush(str);
|
||||
// ch.writeAndFlush(str+ "\r\n");
|
||||
System.out.println("客户端发送数据:"+str);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.pancm.nio.netty.demo;
|
||||
|
||||
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
|
||||
import io.netty.handler.codec.Delimiters;
|
||||
import io.netty.handler.codec.string.StringDecoder;
|
||||
import io.netty.handler.codec.string.StringEncoder;
|
||||
/**
|
||||
*
|
||||
* Title: NettyClientFilter
|
||||
* Description: Netty客户端 过滤器
|
||||
* Version:1.0.0
|
||||
* @author Administrator
|
||||
* @date 2017-8-31
|
||||
*/
|
||||
public class NettyClientFilter extends ChannelInitializer<SocketChannel> {
|
||||
|
||||
@Override
|
||||
protected void initChannel(SocketChannel ch) throws Exception {
|
||||
ChannelPipeline ph = ch.pipeline();
|
||||
/*
|
||||
* 解码和编码,应和服务端一致
|
||||
* */
|
||||
// ph.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
|
||||
ph.addLast("decoder", new StringDecoder());
|
||||
ph.addLast("encoder", new StringEncoder());
|
||||
ph.addLast("handler", new NettyClientHandler()); //客户端的逻辑
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.pancm.nio.netty.demo;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: NettyClientHandler
|
||||
* Description: 客户端业务逻辑实现
|
||||
* Version:1.0.0
|
||||
* @author Administrator
|
||||
* @date 2017-8-31
|
||||
*/
|
||||
public class NettyClientHandler extends SimpleChannelInboundHandler<String> {
|
||||
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
|
||||
System.out.println("客户端接受的消息: " + msg);
|
||||
}
|
||||
|
||||
//
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||
System.out.println("正在连接... ");
|
||||
super.channelActive(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||
System.out.println("连接关闭! ");
|
||||
super.channelInactive(ctx);
|
||||
}
|
||||
}
|
||||
40
src/main/java/com/pancm/nio/netty/demo/NettyServer.java
Normal file
40
src/main/java/com/pancm/nio/netty/demo/NettyServer.java
Normal file
@@ -0,0 +1,40 @@
|
||||
package com.pancm.nio.netty.demo;
|
||||
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: NettyServer
|
||||
* Description: Netty服务端
|
||||
* Version:1.0.0
|
||||
* @author Administrator
|
||||
* @date 2017-8-31
|
||||
*/
|
||||
public class NettyServer {
|
||||
private static final int port = 6789; //设置服务端端口
|
||||
private static EventLoopGroup group = new NioEventLoopGroup(); // 通过nio方式来接收连接和处理连接
|
||||
private static ServerBootstrap b = new ServerBootstrap();
|
||||
|
||||
/**
|
||||
* Netty创建全部都是实现自AbstractBootstrap。
|
||||
* 客户端的是Bootstrap,服务端的则是 ServerBootstrap。
|
||||
**/
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
try {
|
||||
b.group(group);
|
||||
b.channel(NioServerSocketChannel.class);
|
||||
b.childHandler(new NettyServerFilter()); //设置过滤器
|
||||
// 异步地绑定服务器;调用 sync()方法阻塞 等待直到绑定完成
|
||||
ChannelFuture f = b.bind(port).sync();
|
||||
System.out.println("服务端启动成功,端口是:"+port);
|
||||
// 获取 Channel 的 CloseFuture,并且阻塞当前线程直到它完成
|
||||
f.channel().closeFuture().sync();
|
||||
} finally {
|
||||
group.shutdownGracefully(); //关闭EventLoopGroup,释放掉所有资源包括创建的线程
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.pancm.nio.netty.demo;
|
||||
|
||||
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
|
||||
import io.netty.handler.codec.Delimiters;
|
||||
import io.netty.handler.codec.string.StringDecoder;
|
||||
import io.netty.handler.codec.string.StringEncoder;
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: HelloServerInitializer
|
||||
* Description: Netty 服务端过滤器
|
||||
* Version:1.0.0
|
||||
* @author Administrator
|
||||
* @date 2017-8-31
|
||||
*/
|
||||
public class NettyServerFilter extends ChannelInitializer<SocketChannel> {
|
||||
|
||||
@Override
|
||||
protected void initChannel(SocketChannel ch) throws Exception {
|
||||
ChannelPipeline ph = ch.pipeline();
|
||||
// 以("\n")为结尾分割的 解码器
|
||||
// ph.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
|
||||
// 解码和编码,应和客户端一致
|
||||
ph.addLast("decoder", new StringDecoder());
|
||||
ph.addLast("encoder", new StringEncoder());
|
||||
ph.addLast("handler", new NettyServerHandler());// 服务端业务逻辑
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.pancm.nio.netty.demo;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: HelloServerHandler
|
||||
* Description: 服务端业务逻辑
|
||||
* Version:1.0.0
|
||||
* @author Administrator
|
||||
* @date 2017-8-31
|
||||
*/
|
||||
public class NettyServerHandler extends SimpleChannelInboundHandler<String> {
|
||||
/*
|
||||
* 收到消息时,返回信息
|
||||
*/
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext ctx, String msg)
|
||||
throws Exception {
|
||||
// 收到消息直接打印输出
|
||||
System.out.println("服务端接受的消息 : " + msg);
|
||||
if("quit".equals(msg)){//服务端断开的条件
|
||||
ctx.close();
|
||||
}
|
||||
// 返回客户端消息
|
||||
// ctx.writeAndFlush("收到消息:"+ msg+",当前的时间是:"+MyTools.getNowTime("")+"\n");
|
||||
ctx.writeAndFlush("收到消息:"+ msg+",当前的时间是:"+new Date());
|
||||
}
|
||||
|
||||
/*
|
||||
* 建立连接时,返回消息
|
||||
*/
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||
System.out.println("连接的客户端地址:" + ctx.channel().remoteAddress());
|
||||
ctx.writeAndFlush("客户端"+ InetAddress.getLocalHost().getHostName() + "成功与服务端建立连接! ");
|
||||
super.channelActive(ctx);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.pancm.nio.netty.demo1;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: BaseClient1Handler
|
||||
* Description: 客户端自定义解码器其一
|
||||
* Version:1.0.0
|
||||
* @author panchengming
|
||||
* @date 2017年9月17日
|
||||
*/
|
||||
public class BaseClient1Handler extends ChannelInboundHandlerAdapter{
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||
System.out.println("BaseClient1Handler channelActive");
|
||||
// ctx.fireChannelActive();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||
System.out.println("BaseClient1Handler channelInactive");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.pancm.nio.netty.demo1;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: BaseClient2Handler
|
||||
* Description: 客户端自定义解码器其二
|
||||
* Version:1.0.0
|
||||
* @author panchengming
|
||||
* @date 2017年9月17日
|
||||
*/
|
||||
public class BaseClient2Handler extends ChannelInboundHandlerAdapter{
|
||||
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||
System.out.println("BaseClient2Handler Active");
|
||||
}
|
||||
}
|
||||
75
src/main/java/com/pancm/nio/netty/demo1/NettyClient.java
Normal file
75
src/main/java/com/pancm/nio/netty/demo1/NettyClient.java
Normal file
@@ -0,0 +1,75 @@
|
||||
package com.pancm.nio.netty.demo1;
|
||||
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
import io.netty.handler.codec.string.StringDecoder;
|
||||
import io.netty.handler.codec.string.StringEncoder;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: NettyClient
|
||||
* Description:Netty客户端 测试
|
||||
* Version:1.0.0
|
||||
* @author Administrator
|
||||
* @date 2017-8-31
|
||||
*/
|
||||
public class NettyClient {
|
||||
private static final int port = 1234;
|
||||
private static final String host = "127.0.0.1";
|
||||
private static EventLoopGroup group = new NioEventLoopGroup(); // 通过nio方式来接收连接和处理连接
|
||||
private static Bootstrap b = new Bootstrap();
|
||||
private static Channel ch ;
|
||||
/**
|
||||
* Netty创建全部都是实现自AbstractBootstrap。
|
||||
* 客户端的是Bootstrap,服务端的则是 ServerBootstrap。
|
||||
**/
|
||||
public static void main(String[] args) throws Exception {
|
||||
try{
|
||||
b.group(group)
|
||||
.channel(NioSocketChannel.class)
|
||||
.option(ChannelOption.TCP_NODELAY, true)
|
||||
.handler(new ChannelInitializer<SocketChannel>() {
|
||||
@Override
|
||||
public void initChannel(SocketChannel ch) throws Exception {
|
||||
ChannelPipeline p = ch.pipeline();
|
||||
p.addLast("decoder", new StringDecoder());
|
||||
p.addLast("encoder", new StringEncoder());
|
||||
p.addLast(new BaseClient1Handler());
|
||||
p.addLast(new BaseClient2Handler());
|
||||
}
|
||||
});
|
||||
|
||||
ChannelFuture future = b.connect(host, port).sync(); // 连接服务端
|
||||
System.out.println("客户端连接成功!");
|
||||
future.channel().writeAndFlush("Hello Netty Server ,I am a common client");//发送消息
|
||||
future.channel().closeFuture().sync(); //关闭
|
||||
} finally {
|
||||
group.shutdownGracefully(); //释放资源
|
||||
}
|
||||
|
||||
// start();
|
||||
}
|
||||
|
||||
public static void start() throws Exception {
|
||||
System.out.println("客户端像服务端发送数据");
|
||||
try {
|
||||
String str="Hello Netty";
|
||||
ch.writeAndFlush(str+"\r\n");//发送消息
|
||||
System.out.println("客户端发送的消息:"+str);
|
||||
ch.closeFuture().sync(); // 应用程序会一直等待,直到channel关闭
|
||||
} finally {
|
||||
// group.shutdownGracefully().sync(); //关闭EventLoopGroup,释放掉所有资源包括创建的线程
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.pancm.nio.netty.demo1;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: NettyClientHandler
|
||||
* Description:客户端业务逻辑
|
||||
* Version:1.0.0
|
||||
* @author Administrator
|
||||
* @date 2017-8-31
|
||||
*/
|
||||
public class NettyClientHandler extends SimpleChannelInboundHandler<String> {
|
||||
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext chc, String str)
|
||||
throws Exception {
|
||||
// TODO Auto-generated method stub
|
||||
System.out.println("消息为:"+str);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext chc) throws Exception {
|
||||
System.out.println("正在连接...");
|
||||
super.channelActive(chc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelInactive(ChannelHandlerContext chc) throws Exception {
|
||||
System.out.println("连接关闭");
|
||||
super.channelInactive(chc);
|
||||
}
|
||||
|
||||
}
|
||||
72
src/main/java/com/pancm/nio/netty/demo1/NettyServer.java
Normal file
72
src/main/java/com/pancm/nio/netty/demo1/NettyServer.java
Normal file
@@ -0,0 +1,72 @@
|
||||
package com.pancm.nio.netty.demo1;
|
||||
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import io.netty.handler.codec.string.StringDecoder;
|
||||
import io.netty.handler.codec.string.StringEncoder;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: NettyServer
|
||||
* Description: Netty服务端 测试自定义channelhandler
|
||||
* Version:1.0.0
|
||||
* @author Administrator
|
||||
* @date 2017-8-31
|
||||
*/
|
||||
|
||||
public class NettyServer {
|
||||
private static final int port = 1234;
|
||||
public static void main(String[] args) {
|
||||
System.out.println("开始运行...");
|
||||
try {
|
||||
start();
|
||||
} catch (InterruptedException e) {
|
||||
System.out.println("运行异常...");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Netty创建全部都是实现自AbstractBootstrap。
|
||||
* 客户端的是Bootstrap,服务端的则是 ServerBootstrap。
|
||||
**/
|
||||
public static void start() throws InterruptedException {
|
||||
ServerBootstrap sb = new ServerBootstrap();// 引导辅助程序
|
||||
EventLoopGroup group = new NioEventLoopGroup();// 通过nio方式来接收连接和处理连接
|
||||
try {
|
||||
sb.group(group); // 通过nio方式来接收连接和处理连接
|
||||
sb.channel(NioServerSocketChannel.class);// 设置nio类型的channel
|
||||
sb.childHandler(new ChannelInitializer<SocketChannel>() {//有连接到达时会创建一个channel
|
||||
protected void initChannel(SocketChannel ch) throws Exception {
|
||||
ChannelPipeline p = ch.pipeline();
|
||||
|
||||
// 字符串解码 和 编码
|
||||
p.addLast("decoder", new StringDecoder());
|
||||
p.addLast("encoder", new StringEncoder());
|
||||
// 在channel队列中添加一个handler来处理业务
|
||||
p.addLast("handler", new NettyServerHandler());
|
||||
// 以("\n")为结尾分割的 解码器
|
||||
// cp.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
|
||||
}
|
||||
});
|
||||
ChannelFuture f = sb.bind(port).sync();// 配置完成,开始绑定server,通过调用sync同步方法阻塞直到绑定成功
|
||||
System.out.println("服务端已启动... 端口是:"+port);
|
||||
f.channel().closeFuture().sync();// 应用程序会一直等待,直到channel关闭
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
// group.shutdownGracefully().sync();//关闭EventLoopGroup,释放掉所有资源包括创建的线程
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.pancm.nio.netty.demo1;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: NettyServerHandler
|
||||
* Description:Netty服务端业务逻辑实现
|
||||
* Version:1.0.0
|
||||
* @author Administrator
|
||||
* @date 2017-8-31
|
||||
*/
|
||||
|
||||
|
||||
public class NettyServerHandler extends SimpleChannelInboundHandler<String> {
|
||||
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext ctx, String msg)
|
||||
throws Exception {
|
||||
// 收到消息直接打印输出
|
||||
System.out.println(ctx.channel().remoteAddress() + " Say : " + msg);
|
||||
|
||||
// 返回客户端消息 - 我已经接收到了你的消息
|
||||
ctx.writeAndFlush("Received your message !\n");
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* 覆盖 channelActive 方法 在channel被启用的时候触发 (在建立连接的时候)
|
||||
*
|
||||
* channelActive 和 channelInActive 在后面的内容中讲述,这里先不做详细的描述
|
||||
*/
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||
|
||||
System.out.println("连接的客户端地址:" + ctx.channel().remoteAddress());
|
||||
ctx.writeAndFlush("客户端"+ InetAddress.getLocalHost().getHostName() + "成功与服务端建立连接! \n");
|
||||
super.channelActive(ctx);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Sharable表示此对象在channel间共享
|
||||
* handler类是我们的具体业务类
|
||||
* */
|
||||
/*@Sharable//注解@Sharable可以让它在channels间共享
|
||||
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) {
|
||||
System.out.println("服务端接受的数据为:" + msg);
|
||||
if("quit".equals(msg)){ //服务端断开的条件
|
||||
ctx.close();
|
||||
}
|
||||
Date date=new Date();
|
||||
ctx.write(date);//回写数据
|
||||
}
|
||||
public void channelReadComplete(ChannelHandlerContext ctx) {
|
||||
System.out.println("1111");
|
||||
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER) //flush掉所有写回的数据
|
||||
.addListener(ChannelFutureListener.CLOSE); //当flush完成后关闭channel
|
||||
}
|
||||
public void exceptionCaught(ChannelHandlerContext ctx,Throwable cause) {
|
||||
System.out.println("2222");
|
||||
cause.printStackTrace();//捕捉异常信息
|
||||
ctx.close();//出现异常时关闭channel
|
||||
}
|
||||
}*/
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.pancm.nio.netty.demo2;
|
||||
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
import io.netty.handler.codec.string.StringDecoder;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: NettyClientDemo2
|
||||
* Description: Netty客户端 用于测试粘包、拆包
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年9月20日
|
||||
*/
|
||||
public class NettyClientDemo2 {
|
||||
public static String host = "127.0.0.1"; //ip地址
|
||||
public static int port = 2345; //端口
|
||||
/// 通过nio方式来接收连接和处理连接
|
||||
private static EventLoopGroup group = new NioEventLoopGroup();
|
||||
private static Bootstrap b = new Bootstrap();
|
||||
private static Channel ch;
|
||||
|
||||
/**
|
||||
* Netty创建全部都是实现自AbstractBootstrap。
|
||||
* 客户端的是Bootstrap,服务端的则是ServerBootstrap。
|
||||
**/
|
||||
public static void main(String[] args) throws InterruptedException, IOException {
|
||||
b.group(group)
|
||||
.channel(NioSocketChannel.class)
|
||||
.option(ChannelOption.TCP_NODELAY,true)
|
||||
.handler(new ChannelInitializer<SocketChannel>() {
|
||||
@Override
|
||||
public void initChannel(SocketChannel ch) throws Exception {
|
||||
ChannelPipeline p = ch.pipeline();
|
||||
p.addLast(new StringDecoder()); //绑定解码器
|
||||
p.addLast(new NettyClientHandlerDemo2()); //绑定自定义业务
|
||||
}
|
||||
});
|
||||
// 连接服务端
|
||||
ch = b.connect(host, port).sync().channel();
|
||||
System.out.println("客户端成功启动...");
|
||||
// star();
|
||||
}
|
||||
|
||||
public static void star() throws IOException{
|
||||
String str="你好 Netty!";
|
||||
byte[] by=str.getBytes();
|
||||
ByteBuf message = Unpooled.buffer(by.length); ;
|
||||
message.writeBytes(by);
|
||||
ch.writeAndFlush(message);
|
||||
System.out.println("客户端发送数据:"+str);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
package com.pancm.nio.netty.demo2;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: NettyClientHandlerDemo2
|
||||
* Description: Netty客户端业务逻辑处理
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年9月20日
|
||||
*/
|
||||
public class NettyClientHandlerDemo2 extends ChannelInboundHandlerAdapter{
|
||||
|
||||
private byte[] req;
|
||||
|
||||
private int counter;
|
||||
|
||||
public NettyClientHandlerDemo2() {
|
||||
// req = ("书到用时方恨少,事非经过不知难!").getBytes();
|
||||
|
||||
//用于测试字节解码器 LineBasedFrameDecoder(2048)
|
||||
req = ("春江潮水连海平,海上明月共潮生。"
|
||||
+" 滟滟随波千万里,何处春江无月明! "
|
||||
+" 江流宛转绕芳甸,月照花林皆似霰;"
|
||||
+" 空里流霜不觉飞,汀上白沙看不见。"
|
||||
+" 江天一色无纤尘,皎皎空中孤月轮。"
|
||||
+" 江畔何人初见月?江月何年初照人?"
|
||||
+" 人生代代无穷已,江月年年望相似。"
|
||||
+" 不知江月待何人,但见长江送流水。"
|
||||
+" 白云一片去悠悠,青枫浦上不胜愁。"
|
||||
+" 谁家今夜扁舟子?何处相思明月楼?"
|
||||
+" 可怜楼上月徘徊,应照离人妆镜台。"
|
||||
+" 玉户帘中卷不去,捣衣砧上拂还来。"
|
||||
+" 此时相望不相闻,愿逐月华流照君。"
|
||||
+" 鸿雁长飞光不度,鱼龙潜跃水成文。"
|
||||
+" 昨夜闲潭梦落花,可怜春半不还家。"
|
||||
+" 江水流春去欲尽,江潭落月复西斜。"
|
||||
+" 斜月沉沉藏海雾,碣石潇湘无限路。"
|
||||
+" 不知乘月几人归,落月摇情满江树。"
|
||||
+" 噫吁嚱,危乎高哉!蜀道之难,难于上青天!蚕丛及鱼凫,开国何茫然!尔来四万八千岁,不与秦塞通人烟。"
|
||||
+" 西当太白有鸟道,可以横绝峨眉巅。地崩山摧壮士死,然后天梯石栈相钩连。上有六龙回日之高标,下有冲波逆折之回川。"
|
||||
+" 黄鹤之飞尚不得过,猿猱欲度愁攀援。青泥何盘盘,百步九折萦岩峦。扪参历井仰胁息,以手抚膺坐长叹。"
|
||||
+" 问君西游何时还?畏途巉岩不可攀。但见悲鸟号古木,雄飞雌从绕林间。又闻子规啼夜月,愁空山。"
|
||||
+" 蜀道之难,难于上青天,使人听此凋朱颜!连峰去天不盈尺,枯松倒挂倚绝壁。飞湍瀑流争喧豗,砯崖转石万壑雷。"
|
||||
+" 其险也如此,嗟尔远道之人胡为乎来哉!剑阁峥嵘而崔嵬,一夫当关,万夫莫开。"
|
||||
+" 所守或匪亲,化为狼与豺。朝避猛虎,夕避长蛇;磨牙吮血,杀人如麻。锦城虽云乐,不如早还家。"
|
||||
+" 蜀道之难,难于上青天,侧身西望长咨嗟!"+System.getProperty("line.separator")).getBytes();
|
||||
|
||||
//用于测试 固定字符切分解码器 DelimiterBasedFrameDecoder(1024,Unpooled.copiedBuffer("~_~".getBytes())
|
||||
/* req = ("春江潮水连海平,海上明月共潮生。"
|
||||
+" 滟滟随波千万里,何处春江无月明! "
|
||||
+" 江流宛转绕芳甸,月照花林皆似霰;"
|
||||
+" 空里流霜不觉飞,汀上白沙看不见。"
|
||||
+" 江天一色无纤尘,皎皎空中孤月轮。"
|
||||
+" 江畔何人初见月?江月何年初照人?"
|
||||
+" 人生代代无穷已,江月年年望相似。~_~"
|
||||
+" 不知江月待何人,但见长江送流水。"
|
||||
+" 白云一片去悠悠,青枫浦上不胜愁。"
|
||||
+" 谁家今夜扁舟子?何处相思明月楼?"
|
||||
+" 可怜楼上月徘徊,应照离人妆镜台。"
|
||||
+" 玉户帘中卷不去,捣衣砧上拂还来。"
|
||||
+" 此时相望不相闻,愿逐月华流照君。~_~"
|
||||
+" 鸿雁长飞光不度,鱼龙潜跃水成文。"
|
||||
+" 昨夜闲潭梦落花,可怜春半不还家。"
|
||||
+" 江水流春去欲尽,江潭落月复西斜。"
|
||||
+" 斜月沉沉藏海雾,碣石潇湘无限路。"
|
||||
+" 不知乘月几人归,落月摇情满江树。~_~"
|
||||
+" 噫吁嚱,危乎高哉!蜀道之难,难于上青天!蚕丛及鱼凫,开国何茫然!尔来四万八千岁,不与秦塞通人烟。"
|
||||
+" 西当太白有鸟道,可以横绝峨眉巅。地崩山摧壮士死,然后天梯石栈相钩连。~_~ 上有六龙回日之高标,下有冲波逆折之回川。"
|
||||
+" 黄鹤之飞尚不得过,猿猱欲度愁攀援。~_~ 青泥何盘盘,百步九折萦岩峦。扪参历井仰胁息,以手抚膺坐长叹。"
|
||||
+" 问君西游何时还?畏途巉岩不可攀。但见悲鸟号古木,雄飞雌从绕林间。又闻子规啼夜月,愁空山。"
|
||||
+" 蜀道之难,难于上青天,使人听此凋朱颜!连峰去天不盈尺,枯松倒挂倚绝壁。~_~ 飞湍瀑流争喧豗,砯崖转石万壑雷。"
|
||||
+" 其险也如此,嗟尔远道之人胡为乎来哉!剑阁峥嵘而崔嵬,一夫当关,万夫莫开。"
|
||||
+" 所守或匪亲,化为狼与豺。朝避猛虎,夕避长蛇;磨牙吮血,杀人如麻。锦城虽云乐,不如早还家。"
|
||||
+" 蜀道之难,难于上青天,侧身西望长咨嗟!"+System.getProperty("line.separator")).getBytes(); */
|
||||
|
||||
|
||||
|
||||
|
||||
/* req = ("AAAAAAAAAAAAAAAA"
|
||||
+" BBBBBBBBBBBBBBBB "
|
||||
+" CCCCCCCCCCCCCCCCC"
|
||||
+" DDDDDDDDDDDDD"
|
||||
+" EEEEEEEEEEEEEE"
|
||||
+" FFFFFFFFFFFFFF"
|
||||
+" GGGGGGGGGGGG ~_~"
|
||||
+" HHHHHHHHHHHHHHHH"
|
||||
+" IIIIIIIIIIIIII"
|
||||
+" JJJJJJJJJJJJJJJJJJJ"
|
||||
+" KKKKKKKKKKKKKKKKK"
|
||||
+" LLLLLLLLLLLLLLLLL"
|
||||
+" MMMMMMMMMMMMMMMMMM ~_~"
|
||||
+" NNNNNNNNNNNNNNNN"
|
||||
+" OOOOOOOOOOOOOOOOOOOO"
|
||||
+" PPPPPPPPPPPPPP"
|
||||
+" QQQQQQQQQQQQQQQQQQQQ"
|
||||
+" RRRRRRRRRRRRRR ~_~"
|
||||
+" SSSSSSSSSSSSSSSSS"
|
||||
+" TTTTTT ~_~ TTTTTTT"+System.getProperty("line.separator")).getBytes(); */
|
||||
|
||||
//System.getProperty("line.separator") 结束标记
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||
ByteBuf message = null;
|
||||
//会发生粘包现象
|
||||
// for (int i = 0; i < 100; i++) {
|
||||
// message = Unpooled.buffer(req.length);
|
||||
// message.writeBytes(req);
|
||||
// ctx.writeAndFlush(message);
|
||||
// }
|
||||
message = Unpooled.buffer(req.length);
|
||||
message.writeBytes(req);
|
||||
ctx.writeAndFlush(message);
|
||||
System.out.println("一次发送消息过多,发送拆包现象! ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg)
|
||||
throws Exception {
|
||||
String buf = (String) msg;
|
||||
System.out.println("现在 : " + buf + " ; 条数是 : "+ ++counter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.pancm.nio.netty.demo2;
|
||||
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
|
||||
import io.netty.handler.codec.FixedLengthFrameDecoder;
|
||||
import io.netty.handler.codec.LineBasedFrameDecoder;
|
||||
import io.netty.handler.codec.string.StringDecoder;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: NettyServerDemo2
|
||||
* Description: Netty服务端 用于测试粘包、拆包
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年9月20日
|
||||
*/
|
||||
public class NettyServerDemo2 {
|
||||
private final static int port=2345;
|
||||
|
||||
public void start(){
|
||||
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
|
||||
EventLoopGroup workerGroup = new NioEventLoopGroup();
|
||||
try {
|
||||
ServerBootstrap sbs = new ServerBootstrap().group(bossGroup,workerGroup).channel(NioServerSocketChannel.class).localAddress(new InetSocketAddress(port))
|
||||
.childHandler(new ChannelInitializer<SocketChannel>() {
|
||||
protected void initChannel(SocketChannel ch) throws Exception {
|
||||
ChannelPipeline p = ch.pipeline();
|
||||
|
||||
p.addLast(new LineBasedFrameDecoder(2048)); //字节解码器 ,其中2048是规定一行数据最大的字节数。 用于解决拆包问题
|
||||
// p.addLast(new FixedLengthFrameDecoder(100)); //定长数据帧的解码器 ,每帧数据100个字节就切分一次。 用于解决粘包问题
|
||||
// p.addLast(new DelimiterBasedFrameDecoder(1024,Unpooled.copiedBuffer("~_~".getBytes()))); //固定字符切分解码器 ,会以"~_~"为分隔符。 注意此方法要放到StringDecoder()上面
|
||||
p.addLast(new StringDecoder()); //设置解码器
|
||||
p.addLast(new NettyServerHandlerDemo2()); //绑定自定义事物
|
||||
};
|
||||
|
||||
}).option(ChannelOption.SO_BACKLOG, 128)
|
||||
.childOption(ChannelOption.SO_KEEPALIVE, true);
|
||||
// 绑定端口,开始接收进来的连接
|
||||
ChannelFuture future = sbs.bind(port).sync();
|
||||
|
||||
System.out.println("服务端启动成功,端口为 :" + port );
|
||||
future.channel().closeFuture().sync();
|
||||
} catch (Exception e) {
|
||||
bossGroup.shutdownGracefully(); //关闭EventLoopGroup,释放掉所有资源包括创建的线程
|
||||
workerGroup.shutdownGracefully(); //关闭EventLoopGroup,释放掉所有资源包括创建的线程
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
new NettyServerDemo2().start();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.pancm.nio.netty.demo2;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: NettyServerHandlerDemo2
|
||||
* Description: Netty服务端业务逻辑处理 用于测试粘包、拆包
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年9月20日
|
||||
*/
|
||||
public class NettyServerHandlerDemo2 extends ChannelInboundHandlerAdapter{
|
||||
|
||||
|
||||
private int counter;
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
|
||||
String body = (String)msg;
|
||||
System.out.println("接受的数据是: " + body + ";条数是: " + ++counter);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
cause.printStackTrace();
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.pancm.nio.netty.demo3;
|
||||
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: NettyClientDemo3
|
||||
* Description: Netty客户端 测试自定义解码器
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年9月21日
|
||||
*/
|
||||
public class NettyClientDemo3 {
|
||||
public static String host = "127.0.0.1"; //ip地址
|
||||
public static int port = 3456; //端口
|
||||
/// 通过nio方式来接收连接和处理连接
|
||||
private static EventLoopGroup group = new NioEventLoopGroup();
|
||||
private static Bootstrap b = new Bootstrap();
|
||||
private static Channel ch=null;
|
||||
|
||||
/**
|
||||
* Netty创建全部都是实现自AbstractBootstrap。
|
||||
* 客户端的是Bootstrap,服务端的则是ServerBootstrap。
|
||||
**/
|
||||
public static void main(String[] args) throws InterruptedException, IOException {
|
||||
b.group(group)
|
||||
.channel(NioSocketChannel.class)
|
||||
.option(ChannelOption.TCP_NODELAY,true)
|
||||
.handler(new ChannelInitializer<SocketChannel>() {
|
||||
@Override
|
||||
public void initChannel(SocketChannel ch) throws Exception {
|
||||
ChannelPipeline p = ch.pipeline();
|
||||
p.addLast(new NettyEncoder()); //绑定自定义编码器
|
||||
p.addLast(new NettyClientHandlerDemo3()); //绑定自定义业务
|
||||
}
|
||||
});
|
||||
// 连接服务端
|
||||
ch = b.connect(host, port).sync().channel();
|
||||
System.out.println("客户端成功启动...");
|
||||
star();
|
||||
}
|
||||
|
||||
public static void star() throws IOException{
|
||||
String str="你好,Netty";
|
||||
NettyMsg customMsg = new NettyMsg((byte)0xAB, (byte)0xCD, str.length(), str);
|
||||
ch.writeAndFlush(customMsg);
|
||||
System.out.println("客户端发送数据:"+customMsg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.pancm.nio.netty.demo3;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
|
||||
/**
|
||||
*
|
||||
* Description:
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年9月21日
|
||||
*/
|
||||
public class NettyClientHandlerDemo3 extends ChannelInboundHandlerAdapter {
|
||||
|
||||
/**
|
||||
* 连接时发送消息
|
||||
*/
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||
NettyMsg customMsg = new NettyMsg((byte)0xAB, (byte)0xCD, "Hello,Netty".length(), "Hello,Netty");
|
||||
ctx.writeAndFlush(customMsg);
|
||||
}
|
||||
|
||||
}
|
||||
70
src/main/java/com/pancm/nio/netty/demo3/NettyDecoder.java
Normal file
70
src/main/java/com/pancm/nio/netty/demo3/NettyDecoder.java
Normal file
@@ -0,0 +1,70 @@
|
||||
package com.pancm.nio.netty.demo3;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ByteToMessageCodec;
|
||||
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
|
||||
|
||||
/**
|
||||
*
|
||||
* Description: Netty自定义解码器
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年9月21日
|
||||
*/
|
||||
public class NettyDecoder extends ByteToMessageCodec<NettyMsg> {
|
||||
|
||||
//判断传送客户端传送过来的数据是否按照协议传输,头部信息的大小应该是 byte+byte+int = 1+1+4 = 6
|
||||
private static final int HEADER_SIZE = 6;
|
||||
|
||||
/** 类型 系统编号 0xAB 表示A系统,0xBC 表示B系统 */
|
||||
private byte type;
|
||||
|
||||
/** 信息标志 0xAB 表示心跳包 0xBC 表示超时包 0xCD 业务信息包 */
|
||||
private byte flag;
|
||||
|
||||
/** 主题信息的长度 */
|
||||
private int length;
|
||||
|
||||
/** 主题信息 */
|
||||
private String body;
|
||||
|
||||
|
||||
@Override
|
||||
protected void encode(ChannelHandlerContext ctx, NettyMsg msg, ByteBuf out)
|
||||
throws Exception {
|
||||
System.out.println("msg:"+msg);
|
||||
if (out == null) {
|
||||
return ;
|
||||
}
|
||||
if (out.readableBytes() < HEADER_SIZE) {
|
||||
throw new Exception("可读信息段比头部信息都小,你在逗我?");
|
||||
}
|
||||
//注意在读的过程中,readIndex的指针也在移动
|
||||
type = out.readByte();
|
||||
|
||||
flag = out.readByte();
|
||||
|
||||
length = out.readInt();
|
||||
|
||||
if (out.readableBytes() < length) {
|
||||
throw new Exception("body字段你告诉我长度是"+length+",但是真实情况是没有这么多,你又逗我?");
|
||||
}
|
||||
ByteBuf buf = out.readBytes(length);
|
||||
byte[] req = new byte[buf.readableBytes()];
|
||||
buf.readBytes(req);
|
||||
body = new String(req, "UTF-8");
|
||||
NettyMsg customMsg = new NettyMsg(type,flag,length,body);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf in,
|
||||
List<Object> out) throws Exception {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
74
src/main/java/com/pancm/nio/netty/demo3/NettyDecoder2.java
Normal file
74
src/main/java/com/pancm/nio/netty/demo3/NettyDecoder2.java
Normal file
@@ -0,0 +1,74 @@
|
||||
package com.pancm.nio.netty.demo3;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
|
||||
|
||||
/**
|
||||
*
|
||||
* Description: Netty自定义解码器
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年9月21日
|
||||
*/
|
||||
public class NettyDecoder2 extends LengthFieldBasedFrameDecoder {
|
||||
|
||||
//判断传送客户端传送过来的数据是否按照协议传输,头部信息的大小应该是 byte+byte+int = 1+1+4 = 6
|
||||
private static final int HEADER_SIZE = 6;
|
||||
|
||||
/** 类型 系统编号 0xAB 表示A系统,0xBC 表示B系统 */
|
||||
private byte type;
|
||||
|
||||
/** 信息标志 0xAB 表示心跳包 0xBC 表示超时包 0xCD 业务信息包 */
|
||||
private byte flag;
|
||||
|
||||
/** 主题信息的长度 */
|
||||
private int length;
|
||||
|
||||
/** 主题信息 */
|
||||
private String body;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param maxFrameLength 解码时,处理每个帧数据的最大长度
|
||||
* @param lengthFieldOffset 该帧数据中,存放该帧数据的长度的数据的起始位置
|
||||
* @param lengthFieldLength 记录该帧数据长度的字段本身的长度
|
||||
* @param lengthAdjustment 修改帧数据长度字段中定义的值,可以为负数
|
||||
* @param initialBytesToStrip 解析的时候需要跳过的字节数
|
||||
* @param failFast 为true,当frame长度超过maxFrameLength时立即报TooLongFrameException异常,为false,读取完整个帧再报异常
|
||||
*/
|
||||
public NettyDecoder2(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength,
|
||||
int lengthAdjustment, int initialBytesToStrip, boolean failFast) {
|
||||
super(maxFrameLength, lengthFieldOffset, lengthFieldLength,
|
||||
lengthAdjustment, initialBytesToStrip, failFast);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
|
||||
if (in == null) {
|
||||
return null;
|
||||
}
|
||||
if (in.readableBytes() < HEADER_SIZE) {
|
||||
throw new Exception("可读信息段比头部信息都小,你在逗我?");
|
||||
}
|
||||
|
||||
//注意在读的过程中,readIndex的指针也在移动
|
||||
type = in.readByte();
|
||||
|
||||
flag = in.readByte();
|
||||
|
||||
length = in.readInt();
|
||||
|
||||
if (in.readableBytes() < length) {
|
||||
throw new Exception("body字段你告诉我长度是"+length+",但是真实情况是没有这么多,你又逗我?");
|
||||
}
|
||||
ByteBuf buf = in.readBytes(length);
|
||||
byte[] req = new byte[buf.readableBytes()];
|
||||
buf.readBytes(req);
|
||||
body = new String(req, "UTF-8");
|
||||
|
||||
NettyMsg customMsg = new NettyMsg(type,flag,length,body);
|
||||
return customMsg;
|
||||
}
|
||||
|
||||
}
|
||||
33
src/main/java/com/pancm/nio/netty/demo3/NettyEncoder.java
Normal file
33
src/main/java/com/pancm/nio/netty/demo3/NettyEncoder.java
Normal file
@@ -0,0 +1,33 @@
|
||||
package com.pancm.nio.netty.demo3;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
|
||||
/**
|
||||
*
|
||||
* Description:Netty自定义编码器
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年9月21日
|
||||
*/
|
||||
public class NettyEncoder extends MessageToByteEncoder<NettyMsg> {
|
||||
|
||||
@Override
|
||||
protected void encode(ChannelHandlerContext ctx, NettyMsg msg, ByteBuf out) throws Exception {
|
||||
if(null == msg){
|
||||
throw new Exception("消息不能为空!");
|
||||
}
|
||||
|
||||
String body = msg.getBody();
|
||||
byte[] bodyBytes = body.getBytes(Charset.forName("utf-8"));
|
||||
out.writeByte(msg.getType());
|
||||
out.writeByte(msg.getFlag());
|
||||
out.writeInt(bodyBytes.length);
|
||||
out.writeBytes(bodyBytes);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
84
src/main/java/com/pancm/nio/netty/demo3/NettyMsg.java
Normal file
84
src/main/java/com/pancm/nio/netty/demo3/NettyMsg.java
Normal file
@@ -0,0 +1,84 @@
|
||||
package com.pancm.nio.netty.demo3;
|
||||
|
||||
/**
|
||||
*
|
||||
* Description: Netty 自定义消息
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年9月21日
|
||||
*/
|
||||
public class NettyMsg {
|
||||
|
||||
|
||||
/** 类型 系统编号 0xAB 表示A系统,0xBC 表示B系统 */
|
||||
private byte type;
|
||||
|
||||
/** 信息标志 0xAB 表示心跳包 0xBC 表示超时包 0xCD 业务信息包 */
|
||||
private byte flag;
|
||||
|
||||
/** 主题信息的长度 */
|
||||
private int length;
|
||||
|
||||
/** 主题信息 */
|
||||
private String body;
|
||||
|
||||
public NettyMsg() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param type 类型 系统编号 0xAB 表示A系统,0xBC 表示B系统
|
||||
* @param flag 信息标志 0xAB 表示心跳包 0xBC 表示超时包 0xCD 业务信息包
|
||||
* @param length 主题信息的长度
|
||||
* @param body 主题信息
|
||||
*/
|
||||
public NettyMsg(byte type, byte flag, int length, String body) {
|
||||
this.type = type;
|
||||
this.flag = flag;
|
||||
this.length = length;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
public byte getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(byte type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public byte getFlag() {
|
||||
return flag;
|
||||
}
|
||||
|
||||
public void setFlag(byte flag) {
|
||||
this.flag = flag;
|
||||
}
|
||||
|
||||
public int getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
public void setLength(int length) {
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
public String getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
public void setBody(String body) {
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重写toString方法,方便打印日志
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NettyMsg [type=" + type + ", flag=" + flag + ", length="
|
||||
+ length + ", body=" + body + "]";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.pancm.nio.netty.demo3;
|
||||
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
/**
|
||||
*
|
||||
* Description: Netty 服务端 测试自定义解码器
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年9月21日
|
||||
*/
|
||||
public class NettyServerDemo3 {
|
||||
|
||||
private static final int MAX_FRAME_LENGTH = 1024 * 1024;
|
||||
private static final int LENGTH_FIELD_LENGTH = 4;
|
||||
private static final int LENGTH_FIELD_OFFSET = 2;
|
||||
private static final int LENGTH_ADJUSTMENT = 0;
|
||||
private static final int INITIAL_BYTES_TO_STRIP = 0;
|
||||
|
||||
private final static int port=3456;
|
||||
|
||||
|
||||
public void start(){
|
||||
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
|
||||
EventLoopGroup workerGroup = new NioEventLoopGroup();
|
||||
try {
|
||||
ServerBootstrap sbs = new ServerBootstrap().group(bossGroup,workerGroup).channel(NioServerSocketChannel.class).localAddress(new InetSocketAddress(port))
|
||||
.childHandler(new ChannelInitializer<SocketChannel>() {
|
||||
|
||||
protected void initChannel(SocketChannel ch) throws Exception {
|
||||
ch.pipeline().addLast(new NettyDecoder2(MAX_FRAME_LENGTH,LENGTH_FIELD_LENGTH,LENGTH_FIELD_OFFSET,LENGTH_ADJUSTMENT,INITIAL_BYTES_TO_STRIP,false));
|
||||
// ch.pipeline().addLast(new NettyDecoder(MAX_FRAME_LENGTH,LENGTH_FIELD_LENGTH,LENGTH_FIELD_OFFSET,LENGTH_ADJUSTMENT,INITIAL_BYTES_TO_STRIP,false));
|
||||
ch.pipeline().addLast(new NettyServerHandlerDemo3());
|
||||
};
|
||||
|
||||
}).option(ChannelOption.SO_BACKLOG, 128)
|
||||
.childOption(ChannelOption.SO_KEEPALIVE, true);
|
||||
// 绑定端口,开始接收进来的连接
|
||||
ChannelFuture future = sbs.bind(port).sync();
|
||||
|
||||
System.out.println("Netty服务端成功启动!端口为: " + port );
|
||||
future.channel().closeFuture().sync();
|
||||
} catch (Exception e) {
|
||||
bossGroup.shutdownGracefully();
|
||||
workerGroup.shutdownGracefully();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
new NettyServerDemo3().start();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.pancm.nio.netty.demo3;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
|
||||
/**
|
||||
*
|
||||
* Description:服务端业务逻辑处理类
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年9月21日
|
||||
*/
|
||||
public class NettyServerHandlerDemo3 extends SimpleChannelInboundHandler<Object> {
|
||||
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
if(msg instanceof NettyMsg) {
|
||||
NettyMsg customMsg = (NettyMsg)msg;
|
||||
System.out.println("接受的数据:"+ctx.channel().remoteAddress()+" send "+customMsg.getBody());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.pancm.nio.netty.demo4;
|
||||
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
import io.netty.handler.codec.string.StringDecoder;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: NettyClientDemo4
|
||||
* Description: Netty客户端
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年9月21日
|
||||
*/
|
||||
public class NettyClientDemo4 {
|
||||
public static String host = "127.0.0.1"; //ip地址
|
||||
public static int port = 4567; //端口
|
||||
/// 通过nio方式来接收连接和处理连接
|
||||
private static EventLoopGroup group = new NioEventLoopGroup();
|
||||
private static Bootstrap b = new Bootstrap();
|
||||
private static Channel ch=null;
|
||||
|
||||
/**
|
||||
* Netty创建全部都是实现自AbstractBootstrap。
|
||||
* 客户端的是Bootstrap,服务端的则是ServerBootstrap。
|
||||
**/
|
||||
public static void main(String[] args) throws InterruptedException, IOException {
|
||||
b.group(group)
|
||||
.channel(NioSocketChannel.class)
|
||||
.option(ChannelOption.TCP_NODELAY,true)
|
||||
.handler(new ChannelInitializer<SocketChannel>() {
|
||||
@Override
|
||||
public void initChannel(SocketChannel ch) throws Exception {
|
||||
ChannelPipeline p = ch.pipeline();
|
||||
p.addLast(new StringDecoder()); //绑定自定义编码器
|
||||
p.addLast(new NettyClientHandlerDemo4()); //绑定自定义业务
|
||||
}
|
||||
});
|
||||
// 连接服务端
|
||||
ch = b.connect(host, port).sync().channel();
|
||||
System.out.println("客户端成功启动...");
|
||||
//发送消息
|
||||
star();
|
||||
}
|
||||
|
||||
public static void star() throws IOException{
|
||||
NettySendBody nsb=new NettySendBody();
|
||||
nsb.put("Netty","Hello");
|
||||
nsb.put("JAVA","从入门到入土");
|
||||
nsb.put("SQL","从删库到跑路");
|
||||
ch.writeAndFlush(nsb);
|
||||
System.out.println("客户端发送数据:"+nsb.toString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.pancm.nio.netty.demo4;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
|
||||
/**
|
||||
*
|
||||
* Description:
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年9月21日
|
||||
*/
|
||||
public class NettyClientHandlerDemo4 extends ChannelInboundHandlerAdapter {
|
||||
|
||||
/**
|
||||
* 连接时发送消息
|
||||
*/
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||
NettySendBody nst = new NettySendBody();
|
||||
nst.put("1111", "2222");
|
||||
ctx.writeAndFlush(nst);
|
||||
System.out.println(nst);
|
||||
}
|
||||
|
||||
}
|
||||
74
src/main/java/com/pancm/nio/netty/demo4/NettySendBody.java
Normal file
74
src/main/java/com/pancm/nio/netty/demo4/NettySendBody.java
Normal file
@@ -0,0 +1,74 @@
|
||||
package com.pancm.nio.netty.demo4;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
*
|
||||
* Description: Netty 传输对象
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年9月24日
|
||||
*/
|
||||
public class NettySendBody implements Serializable{
|
||||
|
||||
/**
|
||||
* 序列化
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
/** 创建集合 */
|
||||
private ConcurrentHashMap<String, String> data;
|
||||
/** 时间戳 */
|
||||
private long timestamp;
|
||||
|
||||
public NettySendBody() {
|
||||
data = new ConcurrentHashMap<String, String>();
|
||||
timestamp = System.currentTimeMillis(); //取当前时间
|
||||
}
|
||||
|
||||
|
||||
public ConcurrentHashMap<String, String> getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(ConcurrentHashMap<String, String> data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public void setTimestamp(long timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
public String get(String k) {
|
||||
return data.get(k);
|
||||
}
|
||||
|
||||
public void put(String k, String v) {
|
||||
data.put(k, v);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
buffer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||
buffer.append("<sent>");
|
||||
buffer.append("<timestamp>").append(timestamp).append("</timestamp>");
|
||||
buffer.append("<data>");
|
||||
for (String key : data.keySet()) {
|
||||
buffer.append("<" + key + ">").append(data.get(key)).append(
|
||||
"</" + key + ">");
|
||||
}
|
||||
buffer.append("</data>");
|
||||
buffer.append("</sent>");
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.pancm.nio.netty.demo4;
|
||||
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import io.netty.handler.codec.string.StringDecoder;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
/**
|
||||
*
|
||||
* Description: Netty 服务端 测试自定义解码器
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年9月21日
|
||||
*/
|
||||
public class NettyServerDemo4 {
|
||||
|
||||
private final static int port=4567;
|
||||
|
||||
|
||||
public void start(){
|
||||
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
|
||||
EventLoopGroup workerGroup = new NioEventLoopGroup();
|
||||
try {
|
||||
ServerBootstrap sbs = new ServerBootstrap().group(bossGroup,workerGroup).channel(NioServerSocketChannel.class).localAddress(new InetSocketAddress(port))
|
||||
.childHandler(new ChannelInitializer<SocketChannel>() {
|
||||
|
||||
protected void initChannel(SocketChannel ch) throws Exception {
|
||||
ChannelPipeline p = ch.pipeline();
|
||||
p.addLast(new StringDecoder());
|
||||
p.addLast(new NettyServerHandlerDemo4()); //绑定自定义业务逻辑
|
||||
};
|
||||
|
||||
}).option(ChannelOption.SO_BACKLOG, 128)
|
||||
.childOption(ChannelOption.SO_KEEPALIVE, true);
|
||||
// 绑定端口,开始接收进来的连接
|
||||
ChannelFuture future = sbs.bind(port).sync();
|
||||
|
||||
System.out.println("Netty服务端启动成功,端口为: " + port );
|
||||
future.channel().closeFuture().sync(); //释放监听
|
||||
} catch (Exception e) {
|
||||
bossGroup.shutdownGracefully(); //释放资源
|
||||
workerGroup.shutdownGracefully();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
new NettyServerDemo4().start();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.pancm.nio.netty.demo4;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
|
||||
/**
|
||||
*
|
||||
* Description:服务端业务逻辑处理类
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年9月21日
|
||||
*/
|
||||
public class NettyServerHandlerDemo4 extends ChannelInboundHandlerAdapter {
|
||||
|
||||
/**
|
||||
* 处理业务逻辑消息
|
||||
*/
|
||||
protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
System.out.println(" ----- "+msg);
|
||||
if(msg instanceof NettySendBody) {
|
||||
NettySendBody nsb = (NettySendBody)msg;
|
||||
System.out.println("服务端接受的消息为:"+nsb.toString());
|
||||
NettySendBody nsb1 = new NettySendBody();
|
||||
nsb1.put("3333","44444");
|
||||
ctx.writeAndFlush(nsb1);
|
||||
}else{
|
||||
System.out.println("收到非法请求");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
System.out.println(" ----- "+msg);
|
||||
if(msg instanceof NettySendBody) {
|
||||
NettySendBody nsb = (NettySendBody)msg;
|
||||
System.out.println("服务端接受的消息为:"+nsb.toString());
|
||||
NettySendBody nsb1 = new NettySendBody();
|
||||
nsb1.put("3333","44444");
|
||||
ctx.writeAndFlush(nsb1);
|
||||
}else{
|
||||
System.out.println("收到非法请求");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.pancm.nio.netty.demo5;
|
||||
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
import io.netty.handler.codec.string.StringDecoder;
|
||||
import io.netty.handler.codec.string.StringEncoder;
|
||||
import io.netty.handler.timeout.IdleStateHandler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: NettyClientDemo5
|
||||
* Description: Netty客户端 心跳测试
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年9月21日
|
||||
*/
|
||||
public class NettyClientDemo5 {
|
||||
public static String host = "127.0.0.1"; //ip地址
|
||||
public static int port = 5678; //端口
|
||||
/// 通过nio方式来接收连接和处理连接
|
||||
private static EventLoopGroup group = new NioEventLoopGroup();
|
||||
private static Bootstrap b = new Bootstrap();
|
||||
private static Channel ch=null;
|
||||
|
||||
/**
|
||||
* Netty创建全部都是实现自AbstractBootstrap。
|
||||
* 客户端的是Bootstrap,服务端的则是ServerBootstrap。
|
||||
**/
|
||||
public static void main(String[] args) throws InterruptedException, IOException {
|
||||
b.group(group)
|
||||
.channel(NioSocketChannel.class)
|
||||
.option(ChannelOption.TCP_NODELAY,true)
|
||||
.handler(new ChannelInitializer<SocketChannel>() {
|
||||
@Override
|
||||
public void initChannel(SocketChannel ch) throws Exception {
|
||||
ChannelPipeline p = ch.pipeline();
|
||||
//入参说明: 读超时时间、写超时时间、所有类型的超时时间、时间格式
|
||||
//因为服务端设置的超时时间是5秒,所以设置4秒
|
||||
p.addLast( new IdleStateHandler(0, 4, 0, TimeUnit.SECONDS));
|
||||
p.addLast( new StringDecoder());
|
||||
p.addLast( new StringEncoder());
|
||||
p.addLast(new NettyClientHandlerDemo5()); //绑定自定义业务
|
||||
}
|
||||
});
|
||||
// 连接服务端
|
||||
ch = b.connect(host, port).sync().channel();
|
||||
System.out.println("客户端成功启动...");
|
||||
//发送消息
|
||||
// star();
|
||||
}
|
||||
|
||||
public static void star() throws IOException{
|
||||
String str="你好啊,Netty服务端";
|
||||
ch.writeAndFlush(str);
|
||||
System.out.println("客户端发送数据:"+str);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package com.pancm.nio.netty.demo5;
|
||||
|
||||
import com.pancm.utils.MyTools;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import io.netty.handler.timeout.IdleState;
|
||||
import io.netty.handler.timeout.IdleStateEvent;
|
||||
import io.netty.util.CharsetUtil;
|
||||
import io.netty.util.ReferenceCountUtil;
|
||||
|
||||
/**
|
||||
*
|
||||
* Description: Netty业务处理 心跳测试
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年9月21日
|
||||
*/
|
||||
public class NettyClientHandlerDemo5 extends ChannelInboundHandlerAdapter {
|
||||
|
||||
/**心跳命令 */
|
||||
private static final ByteBuf HEARTBEAT_SEQUENCE = Unpooled.unreleasableBuffer(Unpooled.copiedBuffer("Heartbeat",
|
||||
CharsetUtil.UTF_8));
|
||||
|
||||
private static final int TRY_TIMES = 3;
|
||||
|
||||
private int currentTime = 0;
|
||||
|
||||
/**
|
||||
* 建立连接时
|
||||
*/
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||
System.out.println("激活时间是:"+MyTools.getNowTime(""));
|
||||
ctx.fireChannelActive();
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭连接时
|
||||
*/
|
||||
@Override
|
||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||
System.out.println("停止时间是:"+MyTools.getNowTime(""));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
|
||||
System.out.println("循环触发时间:"+MyTools.getNowTime(""));
|
||||
if (evt instanceof IdleStateEvent) {
|
||||
IdleStateEvent event = (IdleStateEvent) evt;
|
||||
System.out.println("event.state():"+event.state()+",IdleState.READER_IDLE:"+IdleState.READER_IDLE);
|
||||
if (event.state() == IdleState.WRITER_IDLE) {
|
||||
System.out.println("TRY_TIMES:"+TRY_TIMES);
|
||||
if(currentTime <= TRY_TIMES){
|
||||
System.out.println("currentTime:"+currentTime);
|
||||
currentTime++;
|
||||
ctx.channel().writeAndFlush(HEARTBEAT_SEQUENCE.duplicate());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 业务逻辑处理
|
||||
*/
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
System.out.println("接受的消息:"+msg);
|
||||
String message = (String) msg;
|
||||
if (message.equals("Heartbeat")) {
|
||||
ctx.write("成功收到心跳信息");
|
||||
ctx.flush();
|
||||
}
|
||||
ReferenceCountUtil.release(msg);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.pancm.nio.netty.demo5;
|
||||
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import io.netty.handler.codec.string.StringDecoder;
|
||||
import io.netty.handler.codec.string.StringEncoder;
|
||||
import io.netty.handler.timeout.IdleStateHandler;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
*
|
||||
* Description: Netty 服务端 测试心跳
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年9月21日
|
||||
*/
|
||||
public class NettyServerDemo5 {
|
||||
/** 设置端口 */
|
||||
private final static int port=5678;
|
||||
|
||||
|
||||
public void start(){
|
||||
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
|
||||
EventLoopGroup workerGroup = new NioEventLoopGroup();
|
||||
try {
|
||||
ServerBootstrap sbs = new ServerBootstrap().group(bossGroup,workerGroup).channel(NioServerSocketChannel.class).localAddress(new InetSocketAddress(port))
|
||||
.childHandler(new ChannelInitializer<SocketChannel>() {
|
||||
|
||||
protected void initChannel(SocketChannel ch) throws Exception {
|
||||
ChannelPipeline p = ch.pipeline();
|
||||
//入参说明: 读超时时间、写超时时间、所有类型的超时时间、时间格式
|
||||
p.addLast(new IdleStateHandler(5, 0, 0, TimeUnit.SECONDS));
|
||||
p.addLast(new StringDecoder()); //String解码器
|
||||
p.addLast(new StringEncoder()); //String编码器
|
||||
p.addLast(new NettyServerHandlerDemo5()); //绑定自定义业务逻辑
|
||||
};
|
||||
|
||||
}).option(ChannelOption.SO_BACKLOG, 128)
|
||||
.childOption(ChannelOption.SO_KEEPALIVE, true);
|
||||
// 绑定端口,开始接收进来的连接
|
||||
ChannelFuture future = sbs.bind(port).sync();
|
||||
|
||||
System.out.println("Netty服务端启动成功,端口为: " + port );
|
||||
future.channel().closeFuture().sync(); //释放监听
|
||||
} catch (Exception e) {
|
||||
bossGroup.shutdownGracefully(); //释放资源
|
||||
workerGroup.shutdownGracefully();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
new NettyServerDemo5().start();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.pancm.nio.netty.demo5;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import io.netty.handler.timeout.IdleState;
|
||||
import io.netty.handler.timeout.IdleStateEvent;
|
||||
|
||||
/**
|
||||
*
|
||||
* Description:服务端业务逻辑处理类
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年9月21日
|
||||
*/
|
||||
public class NettyServerHandlerDemo5 extends ChannelInboundHandlerAdapter {
|
||||
/** 时间 */
|
||||
private int loss_connect_time = 0;
|
||||
/** 发送次数 */
|
||||
private int count = 1;
|
||||
|
||||
@Override
|
||||
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
|
||||
if (evt instanceof IdleStateEvent) {
|
||||
IdleStateEvent event = (IdleStateEvent) evt;
|
||||
System.out.println("event.state():"+event.state()+",IdleState.READER_IDLE:"+IdleState.READER_IDLE);
|
||||
if (event.state() == IdleState.READER_IDLE) {
|
||||
loss_connect_time++;
|
||||
System.out.println("5 秒没有接收到客户端的信息了");
|
||||
if (loss_connect_time > 2) {
|
||||
System.out.println("关闭这个不活跃的channel");
|
||||
ctx.channel().close();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
super.userEventTriggered(ctx, evt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 处理业务逻辑
|
||||
*/
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
System.out.println(" ----- "+msg);
|
||||
String a="你好啊"+",count:"+count;
|
||||
ctx.writeAndFlush(a);
|
||||
count++;
|
||||
}
|
||||
|
||||
/**
|
||||
* 异常处理
|
||||
*/
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
cause.printStackTrace();
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
}
|
||||
41
src/main/java/com/pancm/nio/netty/demo6/NettyServer.java
Normal file
41
src/main/java/com/pancm/nio/netty/demo6/NettyServer.java
Normal file
@@ -0,0 +1,41 @@
|
||||
package com.pancm.nio.netty.demo6;
|
||||
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: NettyServer
|
||||
* Description: Netty服务端 Http测试
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年10月26日
|
||||
*/
|
||||
public class NettyServer {
|
||||
private static final int port = 6789; //设置服务端端口
|
||||
private static EventLoopGroup group = new NioEventLoopGroup(); // 通过nio方式来接收连接和处理连接
|
||||
private static ServerBootstrap b = new ServerBootstrap();
|
||||
|
||||
/**
|
||||
* Netty创建全部都是实现自AbstractBootstrap。
|
||||
* 客户端的是Bootstrap,服务端的则是 ServerBootstrap。
|
||||
**/
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
try {
|
||||
b.group(group);
|
||||
b.channel(NioServerSocketChannel.class);
|
||||
b.childHandler(new NettyServerFilter()); //设置过滤器
|
||||
// 服务器绑定端口监听
|
||||
ChannelFuture f = b.bind(port).sync();
|
||||
System.out.println("服务端启动成功,端口是:"+port);
|
||||
// 监听服务器关闭监听
|
||||
f.channel().closeFuture().sync();
|
||||
} finally {
|
||||
group.shutdownGracefully(); //关闭EventLoopGroup,释放掉所有资源包括创建的线程
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.pancm.nio.netty.demo6;
|
||||
|
||||
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.handler.codec.http.HttpObjectAggregator;
|
||||
import io.netty.handler.codec.http.HttpRequestDecoder;
|
||||
import io.netty.handler.codec.http.HttpResponseEncoder;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: NettyServerFilter
|
||||
* Description: Netty 服务端过滤器
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年10月26日
|
||||
*/
|
||||
public class NettyServerFilter extends ChannelInitializer<SocketChannel> {
|
||||
|
||||
@Override
|
||||
protected void initChannel(SocketChannel ch) throws Exception {
|
||||
ChannelPipeline ph = ch.pipeline();
|
||||
//处理http服务的关键handler
|
||||
ph.addLast("encoder",new HttpResponseEncoder());
|
||||
ph.addLast("decoder",new HttpRequestDecoder());
|
||||
ph.addLast("aggregator", new HttpObjectAggregator(10*1024*1024));
|
||||
ph.addLast("handler", new NettyServerHandler());// 服务端业务逻辑
|
||||
}
|
||||
}
|
||||
123
src/main/java/com/pancm/nio/netty/demo6/NettyServerHandler.java
Normal file
123
src/main/java/com/pancm/nio/netty/demo6/NettyServerHandler.java
Normal file
@@ -0,0 +1,123 @@
|
||||
package com.pancm.nio.netty.demo6;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import io.netty.handler.codec.http.DefaultFullHttpResponse;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.FullHttpResponse;
|
||||
import io.netty.handler.codec.http.HttpHeaderNames;
|
||||
import io.netty.handler.codec.http.HttpMethod;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.handler.codec.http.HttpVersion;
|
||||
import io.netty.util.CharsetUtil;
|
||||
import java.net.InetAddress;
|
||||
|
||||
/**
|
||||
*
|
||||
* Title: NettyServerHandler
|
||||
* Description: 服务端业务逻辑
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年10月26日
|
||||
*/
|
||||
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
|
||||
private String result="";
|
||||
/*
|
||||
* 收到消息时,返回信息
|
||||
*/
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
if(! (msg instanceof FullHttpRequest)){
|
||||
result="未知请求!";
|
||||
send(ctx,result,HttpResponseStatus.BAD_REQUEST);
|
||||
return;
|
||||
}
|
||||
FullHttpRequest httpRequest = (FullHttpRequest)msg;
|
||||
try{
|
||||
String path=httpRequest.uri(); //获取路径
|
||||
String body = getBody(httpRequest); //获取参数
|
||||
HttpMethod method=httpRequest.method();//获取请求方法
|
||||
//如果不是这个路径,就直接返回错误
|
||||
if(!"/test".equalsIgnoreCase(path)){
|
||||
result="非法请求!";
|
||||
send(ctx,result,HttpResponseStatus.BAD_REQUEST);
|
||||
return;
|
||||
}
|
||||
System.out.println("接收到:"+method+" 请求");
|
||||
//如果是GET请求
|
||||
if(HttpMethod.GET.equals(method)){
|
||||
//接受到的消息,做业务逻辑处理...
|
||||
System.out.println("body:"+body);
|
||||
result="GET请求";
|
||||
send(ctx,result,HttpResponseStatus.OK);
|
||||
return;
|
||||
}
|
||||
//如果是POST请求
|
||||
if(HttpMethod.POST.equals(method)){
|
||||
//接受到的消息,做业务逻辑处理...
|
||||
System.out.println("body:"+body);
|
||||
result="POST请求";
|
||||
send(ctx,result,HttpResponseStatus.OK);
|
||||
return;
|
||||
}
|
||||
|
||||
//如果是PUT请求
|
||||
if(HttpMethod.PUT.equals(method)){
|
||||
//接受到的消息,做业务逻辑处理...
|
||||
System.out.println("body:"+body);
|
||||
result="PUT请求";
|
||||
send(ctx,result,HttpResponseStatus.OK);
|
||||
return;
|
||||
}
|
||||
//如果是DELETE请求
|
||||
if(HttpMethod.DELETE.equals(method)){
|
||||
//接受到的消息,做业务逻辑处理...
|
||||
System.out.println("body:"+body);
|
||||
result="DELETE请求";
|
||||
send(ctx,result,HttpResponseStatus.OK);
|
||||
return;
|
||||
}
|
||||
}catch(Exception e){
|
||||
System.out.println("处理请求失败!");
|
||||
e.printStackTrace();
|
||||
}finally{
|
||||
//释放请求
|
||||
httpRequest.release();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取body参数
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
private String getBody(FullHttpRequest request){
|
||||
ByteBuf buf = request.content();
|
||||
return buf.toString(CharsetUtil.UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送的返回值
|
||||
* @param ctx 返回
|
||||
* @param context 消息
|
||||
* @param status 状态
|
||||
*/
|
||||
private void send(ChannelHandlerContext ctx, String context,HttpResponseStatus status) {
|
||||
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status, Unpooled.copiedBuffer(context, CharsetUtil.UTF_8));
|
||||
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain; charset=UTF-8");
|
||||
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* 建立连接时,返回消息
|
||||
*/
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||
System.out.println("连接的客户端地址:" + ctx.channel().remoteAddress());
|
||||
ctx.writeAndFlush("客户端"+ InetAddress.getLocalHost().getHostName() + "成功与服务端建立连接! ");
|
||||
super.channelActive(ctx);
|
||||
}
|
||||
}
|
||||
11
src/main/java/com/pancm/nio/netty/demo6/package-info.java
Normal file
11
src/main/java/com/pancm/nio/netty/demo6/package-info.java
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* Title: package-info
|
||||
* Description: Http服务测试
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017年10月26日
|
||||
*/
|
||||
package com.pancm.nio.netty.demo6;
|
||||
11
src/main/java/com/pancm/nio/netty/package-info.java
Normal file
11
src/main/java/com/pancm/nio/netty/package-info.java
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* Title: package-info
|
||||
* Description: Netty 测试
|
||||
* Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2017-8-31
|
||||
*/
|
||||
package com.pancm.nio.netty;
|
||||
8
src/main/java/com/pancm/nio/package-info.java
Normal file
8
src/main/java/com/pancm/nio/package-info.java
Normal file
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* @Title: package-info
|
||||
* @Description: nio 相关的代码
|
||||
* @Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2018年9月21日
|
||||
*/
|
||||
package com.pancm.nio;
|
||||
67
src/main/java/com/pancm/others/JsoupHtml.java
Normal file
67
src/main/java/com/pancm/others/JsoupHtml.java
Normal file
@@ -0,0 +1,67 @@
|
||||
package com.pancm.others;
|
||||
|
||||
import java.io.IOException;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.select.Elements;
|
||||
|
||||
/**
|
||||
*
|
||||
* @Title: JsoupHtml
|
||||
* @Description: 爬虫测试
|
||||
* 使用 jsoup
|
||||
* @Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2018年3月21日
|
||||
*/
|
||||
public class JsoupHtml {
|
||||
|
||||
private String url="http://sou.zhaopin.com/jobs/searchresult.ashx?jl="; //智联招聘网站
|
||||
private String city="深圳"; //搜索工作的城市
|
||||
private String keywords="java"; //搜索工作的关键字
|
||||
public JsoupHtml(String city,String keywords){
|
||||
this.city=city;
|
||||
this.keywords =keywords;
|
||||
|
||||
}
|
||||
|
||||
public void getZhiLianWork(){
|
||||
try {
|
||||
for (int i=0;i<10;i++) {
|
||||
System.out.println("*********开始遍历第"+(i+1)+"页的求职信息*********");
|
||||
Document doc = Jsoup.connect(url+city+"&kw="+keywords+"&p="+(i+1)+"&isadv=0").get();
|
||||
Element content = doc.getElementById("newlist_list_content_table");
|
||||
if(content == null){
|
||||
continue;
|
||||
}
|
||||
Elements zwmcEls = content.getElementsByClass("zwmc");
|
||||
Elements gsmcEls = content.getElementsByClass("gsmc");
|
||||
Elements zwyxEls = content.getElementsByClass("zwyx");
|
||||
Elements gzddEls = content.getElementsByClass("gzdd");
|
||||
Elements gxsjEls = content.getElementsByClass("gxsj");
|
||||
for(int j = 0;j<zwmcEls .size();j++){
|
||||
|
||||
System.out.println(
|
||||
zwmcEls.get(j).tagName("a").text()+"*****"+gsmcEls.get(j).tagName("a").text()+
|
||||
"*****"+zwyxEls.get(j).tagName("a").text()+"*****"+gzddEls.get(j).tagName("a").text()+
|
||||
"*****"+gxsjEls.get(j).tagName("a").text());
|
||||
System.out.println();
|
||||
}
|
||||
System.out.println("*********结束遍历第"+(i+1)+"页的求职信息*********");
|
||||
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
public static void main(String[] args) {
|
||||
|
||||
JsoupHtml jHtml = new JsoupHtml("上海", "java");
|
||||
jHtml.getZhiLianWork();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user