要完成该项目,需要确保你的虚拟机(或服务器)已经安装了以下大数据框架:
前端构建查询系统使用了SSM框架:
本次项目使用IEDA2018作为开发工具。
/**
* 主呼叫记录生成类
* 模拟一个主动呼叫的电话
*/
public class App {
//初始化工作
public static Map<String,String> allCallers = new HashMap();
public static List<String> phoneNumber = new ArrayList();
static {
//加载所有用户号码和姓名信息
allCallers.put("15810092493", "萧邦主");
allCallers.put("18000696806", "赵贺彪");
allCallers.put("15151889601", "张倩");
allCallers.put("13269361119", "王世昌");
allCallers.put("15032293356", "张涛");
allCallers.put("17731088562", "张阳");
allCallers.put("15338595369", "李进全");
allCallers.put("15733218050", "杜泽文");
allCallers.put("15614201525", "任宗阳");
allCallers.put("15778423030", "梁鹏");
allCallers.put("18641241020", "郭美彤");
allCallers.put("15732648446", "刘飞飞");
allCallers.put("13341109505", "段光星");
allCallers.put("13560190665", "唐会华");
allCallers.put("18301589432", "杨力谋");
allCallers.put("13520404983", "温海英");
allCallers.put("18332562075", "朱尚宽");
allCallers.put("15902136987", "张翔");
allCallers.put("13801358247", "杨超凡");
allCallers.put("15975500987", "何潮辉");
allCallers.put("13013685036", "庄银泳");
allCallers.put("15019933667", "萧金辉");
allCallers.put("18301930136", "黄海锋");
//加载所有用户号码到此集合
phoneNumber.addAll(allCallers.keySet());
}
public static void main(String[] args) throws Exception{
while (true){
if(args.length != 1){
System.err.println("You should input a path to save the logs");
System.exit(1);
}
// 第一个参数即是存储电话号码的文件
genCallLog(args[0]);
}
}
public static void genCallLog (String logFile) throws Exception{
Random r = new Random();
//文件输出流,追加写入文件
FileWriter writer = new FileWriter(logFile,true);
//产生一个主叫
String callerNumber = phoneNumber.get(r.nextInt(phoneNumber.size()));
String callerName = allCallers.get(callerNumber);
String calleeNumber;
String calleeName;
//产生一个被叫
while (true) {
calleeNumber = phoneNumber.get(r.nextInt(phoneNumber.size()));
//主叫与被叫默认不为同一个人
if (!calleeNumber.equals(callerNumber)) {
calleeName = allCallers.get(calleeNumber);
break;
}
}
//通话时间生成
int year = r.nextInt(2) == 0 ? 2018 : 2019;
int month = r.nextInt(12);
int day = r.nextInt(getDay(month)) + 1;
int hour = r.nextInt(24);
int min = r.nextInt(60);
int sec = r.nextInt(60);
//使用日期类格式化时间
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR, year);
calendar.set(Calendar.MONTH, month);
calendar.set(Calendar.DAY_OF_MONTH, day);
calendar.set(Calendar.HOUR_OF_DAY, hour);
calendar.set(Calendar.MINUTE, min);
calendar.set(Calendar.SECOND, sec);
Date timeDate = calendar.getTime();
SimpleDateFormat sdf = new SimpleDateFormat();
sdf.applyPattern("yyyy/MM/dd hh:mm:ss");
String time = sdf.format(timeDate);
//通话时长
DecimalFormat df = new DecimalFormat();
df.applyPattern("000");
// 默认通话时间范围[0,1800)秒
int dur = r.nextInt(60 * 30);
String duration = df.format(dur);
//通话记录
String log = callerNumber + "," + calleeNumber + "," + time + "," + duration;
//将通话记录写入到外部存储系统
writer.write(log + "\r\n");
writer.flush();
//休眠200ms
Thread.sleep(200);
}
// 根据月份返回该月最多的天数
public static int getDay(int month){
if(month == 2)
return 28;
if(month == 1 || month == 3 || month == 5 || month == 7
|| month == 8 || month == 10 || month == 12)
return 31;
return 30;
}
}
create 'ns1:calllog','f1'
,在名字空间ns1中创建一张calllog表,列族为f1。 <repositories>
<repository>
<id>cloudera</id>
<url>https://repository.cloudera.com/artifactory/cloudera-repos</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka_2.11</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-client</artifactId>
<version>1.2.0-cdh5.7.0</version>
</dependency>
</dependencies>
<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.0.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.20.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
<!-- <sourceDirectory>src/main/scala</sourceDirectory>
<testSourceDirectory>src/test/scala</testSourceDirectory>-->
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<configuration>
<downloadSources>true</downloadSources>
<buildcommands>
<buildcommand>ch.epfl.lamp.sdt.core.scalabuilder</buildcommand>
</buildcommands>
<additionalProjectnatures>
<projectnature>ch.epfl.lamp.sdt.core.scalanature</projectnature>
</additionalProjectnatures>
<classpathContainers>
<classpathContainer>org.eclipse.jdt.launching.JRE_CONTAINER</classpathContainer>
<classpathContainer>ch.epfl.lamp.sdt.launching.SCALA_CONTAINER</classpathContainer>
</classpathContainers>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
</build>
在resources目录下创建project.properties文件,该文件是一个该模块下的全局配置文件,用于该模块对Kafka,HBase等的配置:#----- kafka配置 ----#
#zk服务器
zookeeper.connect=hadoop00:2181
#消费者组
group.id=g1
zookeeper.session.timeout.ms=500
zookeeper.sync.time.ms=250
auto.commit.interval.ms=1000
#消费偏移量,从头消费smallest
auto.offset.reset=smallest
#主题
kafka.topic=calllog
#----- HBase配置 ------#
hbase.zookeeper.quorum=hadoop00:2181
hbase.tablename=ns1:calllog
partition.num=100
#---- 其他配置 ----#
#呼叫标志位,1代表主叫,0代表被叫
callerflag=1
calleeflag=0
在java目录下创建类PropertiesUtil,用于解析配置文件,代码如下:/**
* 配置文件工具类
*/
public class PropertiesUtil {
//单例模式
private PropertiesUtil(){}
//静态配置对象
public static Properties props = null;
//初始化对象
static {
InputStream in = ClassLoader.getSystemResourceAsStream("project.properties");
props = new Properties();
try {
props.load(in);
} catch (IOException e) {
e.printStackTrace();
}
}
//获得配置属性
public static String getProperty(String key){
return props.getProperty(key);
}
}
接着在java目录下创建类HbaseDao用于处理通话记录,主要负责三个工作:计算该通话记录存储的region,产生RowKey,数据入库。HbaseDao代码如下:/**
* 访问Hbase
*/
public class HbaseDao {
private Table table = null;
private TableName tableName = null;
// 是否是主叫标志位
private String flag = null;
// HBase的分区个数
private int partitonsNum = 0;
//初始化
public HbaseDao(){
Configuration conf = HBaseConfiguration.create();
conf.set("hbase.zookeeper.quorum",PropertiesUtil.getProperty("hbase.zookeeper.quorum"));
try {
Connection con = ConnectionFactory.createConnection(conf);
tableName = TableName.valueOf(PropertiesUtil.getProperty("hbase.tablename"));
table = con.getTable(tableName);
flag = PropertiesUtil.getProperty("callerflag");
partitonsNum = Integer.parseInt(PropertiesUtil.getProperty("partition.num"));
} catch (IOException e) {
e.printStackTrace();
}
}
//将通话记录插入到HBase,设计RowKey
public void put(String log){
String[] arr = log.split(",");
String caller = arr[0];
String callee = arr[1];
String callDate = arr[2];
//对日期格式化
String callDateFormat = callDate.replace("/",""); //删除/
callDateFormat = callDateFormat.replace(" ",""); //删除空格
callDateFormat = callDateFormat.replace(":",""); //删除:
String duration = arr[3];
// 根据主叫号码以及呼叫日期生成哈希码
// 可以确保同一个用户的同一个月的通话记录会被放在同一个region中
// 不同用户或者同一用户的不同月份的通话记录尽可能发散存储,避免出现热点
String hashCode = getHashCode(caller,callDateFormat);
// 拼接HBase的RowKey
String rowKey = hashCode + "," + caller + "," + callDateFormat + "," + flag + "," + callee + "," + duration;
//创建Put对象
Put put = new Put(rowKey.getBytes());
// 在列族添中加相应的列
put.addColumn("f1".getBytes(),"caller".getBytes(),caller.getBytes());
put.addColumn("f1".getBytes(),"callee".getBytes(),callee.getBytes());
put.addColumn("f1".getBytes(),"callDate".getBytes(),callDateFormat.getBytes());
put.addColumn("f1".getBytes(),"callDuration".getBytes(),duration.getBytes());
//插入表中
try {
table.put(put);
} catch (IOException e) {
e.printStackTrace();
}
}
// 该方法用于计算出该通话记录所在的region区域号
private String getHashCode(String caller,String callDateFormat){
//取电话号码最后5位
int len = caller.length();
String number = caller.substring(len - 5);
//取年份和月份
String date = callDateFormat.substring(0,6);
//取哈希值
int code = (Integer.parseInt(date) ^ Integer.parseInt(number) ) % partitonsNum;
//格式化后返回
DecimalFormat df = new DecimalFormat();
df.applyPattern("00");
return df.format(code);
}
}
最后再在java目录下创建HbaseConsumer类,该类用于消费Flume收集的通话记录日志,并调用HbaseDao,将数据写入HBase,完整代码如下:/**
* 1.启动kafka消费者,从kafka订阅消息(通话记录)
* 2.将数据插入HBase中
*/
public class HbaseConsumer {
public static void main(String[] args) {
//创建HbaseDao,与Hbase交互
HbaseDao hbaseDao = new HbaseDao();
//消费者配置对象
ConsumerConfig config = new ConsumerConfig(PropertiesUtil.props);
//获得主题
String topic = PropertiesUtil.getProperty("kafka.topic");
//创建Map集合存放订阅的主题
Map<String, Integer> map = new HashMap<String, Integer>();
//设置主题,可以订阅多个主题
map.put(topic, new Integer(1));
//传入主题,得到订阅的消息,kafka流集合
//<主题,消息>
Map<String, List<KafkaStream<byte[], byte[]>>> msgs = Consumer.createJavaConsumerConnector(config).createMessageStreams(map);
//根据主题得到消息集合(只订阅了一个主题,直接get)
List<KafkaStream<byte[], byte[]>> msgList = msgs.get(topic);
//迭代消息集合
for(KafkaStream<byte[],byte[]> stream : msgList){
ConsumerIterator<byte[],byte[]> it = stream.iterator();
while(it.hasNext()){
byte[] log = it.next().message();
//将数据写入Hbase
hbaseDao.put(new String(log));
}
}
}
}
<repositories>
<repository>
<id>cloudera</id>
<url>https://repository.cloudera.com/artifactory/cloudera-repos</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-client</artifactId>
<version>1.2.0-cdh5.7.0</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-server</artifactId>
<version>1.2.0-cdh5.7.0</version>
</dependency>
</dependencies>
<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.0.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.20.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
<!-- <sourceDirectory>src/main/scala</sourceDirectory>
<testSourceDirectory>src/test/scala</testSourceDirectory>-->
<plugins>
<!-- <plugin>
<groupId>org.scala-tools</groupId>
<artifactId>maven-scala-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
<configuration>
<scalaVersion>${scala.version}</scalaVersion>
<args>
<arg>-target:jvm-1.5</arg>
</args>
</configuration>
</plugin>-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<configuration>
<downloadSources>true</downloadSources>
<buildcommands>
<buildcommand>ch.epfl.lamp.sdt.core.scalabuilder</buildcommand>
</buildcommands>
<additionalProjectnatures>
<projectnature>ch.epfl.lamp.sdt.core.scalanature</projectnature>
</additionalProjectnatures>
<classpathContainers>
<classpathContainer>org.eclipse.jdt.launching.JRE_CONTAINER</classpathContainer>
<classpathContainer>ch.epfl.lamp.sdt.launching.SCALA_CONTAINER</classpathContainer>
</classpathContainers>
</configuration>
</plugin>
</plugins>
</build>
并在该模块的java目录下创建如下的包:/**
* 协处理工具类
*/
public class Util {
// RowKey的盐析处理
// 由电话号码及通话的时间算出一个region号
public static String getHashCode(String caller,String callDateFormat,int partitonsNum){
//创建格式化类
DecimalFormat df = new DecimalFormat();
//取年份和月份
String date = callDateFormat.substring(0,6);
//取电话号码最后5位
int len = caller.length();
String number = caller.substring(len - 5);
//取哈希值
int code = (Integer.parseInt(date) ^ Integer.parseInt(number) ) % partitonsNum;
//格式化后返回
df.applyPattern("00");
return df.format(code);
// 拼接RowKey
public static String getRowKey(String hashCode,String caller,String callDate,String flag,String callee,String callDuration){
return hashCode + "," + caller + "," + callDate + "," + flag + "," + callee + "," + callDuration;
}
}
在App目录下创建类CallCoprocessor,该类是HBase的协处理器,完整代码如下:/**
* 通话记录协处理器
* 1.在插入一条主叫通话记录的同时插入一条被叫通话记录
* 2.在查被叫信息时通过value找出主叫
*/
public class CallCoprocessor extends BaseRegionObserver {
//重写父类方法,在插入一条主叫通话记录的同时插入一条被叫通话记录
@Override
public void postPut(ObserverContext<RegionCoprocessorEnvironment> e, Put put, WALEdit edit, Durability durability) throws IOException {
super.postPut(e, put, edit, durability);
//获得表名
String tableName = e.getEnvironment().getRegion().getRegionInfo().getTable().getNameAsString();
//判断吧是否为通话记录表,如果不是则跳过
if(!tableName.equals("calllog")){
return;
}
//获得当前插入的RowKey
String callerRow = Bytes.toString(put.getRow());
//切割
String[] row = callerRow.split(",");
//判断是否是主叫插入,若不是则退出
if(row[3].equals("0")){
return;
}
//获得各个属性值
String caller = row[1];
String callDate = row[2];
String callee = row[4];
String callDuration = row[5];
//设置为被叫插入
String flag = "0";
//取得哈希值
String hashCode = Util.getHashCode(callee,callDate,100);
//被叫RowKey
String calleeRow = Util.getRowKey(hashCode,callee,callDate,flag,caller,callDuration);
//创建Put对象
Put putCallee = new Put(calleeRow.getBytes());
//被叫存储
putCallee.addColumn("f1".getBytes(),"caller".getBytes(),callee.getBytes());
putCallee.addColumn("f1".getBytes(),"callDate".getBytes(),callDate.getBytes());
putCallee.addColumn("f1".getBytes(),"callee".getBytes(),caller.getBytes());
putCallee.addColumn("f1".getBytes(),"callDuration".getBytes(),callDuration.getBytes());
//插入表中
Table table = e.getEnvironment().getTable(TableName.valueOf(tableName));
table.put(putCallee);
}
}
java -cp jar包 类名 存储通话日志文件的绝对路径
$HBASE_HOME/lib
目录下。然后进入$HBASE_HOME/conf
目录下,编辑hbase-site.xml文件,添加如下配置:<property>
<name>hbase.coprocessor.region.classes</name>
<value>com.project.coprocessor.App.CallCoprocessor</value>
</property>
其中value的值是你的协处理器代码所在的全类名,该配置在所有HBase的节点都要修改,然后重启HBase集群。$FlUME_HOME/conf
目录下创建Calllog.conf配置文件,该文件内容如下:a1.sources=execSource
a1.sinks=kafkaSink
a1.channels=memoryChannel
a1.sources.execSource.type = exec
a1.sources.execSource.command = tail -F /home/hadoop/data/calllog.log
a1.sinks.kafkaSink.type = org.apache.flume.sink.kafka.KafkaSink
a1.sinks.kafkaSink.kafka.topic = calllog
a1.sinks.kafkaSink.kafka.bootstrap.servers = hadoop01:9092
a1.sinks.kafkaSink.kafka.flumeBatchSize = 20
a1.sinks.kafkaSink.kafka.producer.acks = 1
a1.channels.memoryChannel.type=memory
a1.sources.execSource.channels=memoryChannel
a1.sinks.kafkaSink.channel=memoryChannel
其中:$KAFKA_HOME/bin
目录下执行命令:./kafka-topics.sh --create --zookeeper hadoop00:2181 --topic calllog --replication-factor 3 --partitions 3
java -cp jar包 类名 存储通话日志文件的绝对路径
flume-ng agent -f $FLUME_HOME/conf/calllog.conf -n a1 &
java -cp jar包 类名
scan 'ns1:calllog'
,会发现如下的记录:<repositories>
<repository>
<id>cloudera</id>
<url>https://repository.cloudera.com/artifactory/cloudera-repos</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.2.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.3.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.10</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.17</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-client</artifactId>
<version>1.2.0-cdh5.7.0</version>
</dependency>
<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-jdbc</artifactId>
<version>2.1.0</version>
</dependency>
</dependencies>
然后在java目录下,创建如下的包:<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd" default-autowire="byType">
<!-- 配置事务特征 -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" isolation="DEFAULT"/>
</tx:attributes>
</tx:advice>
<!-- 配置事务切面 -->
<aop:config>
<aop:advisor advice-ref="txAdvice" pointcut="execution(* *..*Service.*(..))" />
</aop:config>
<!-- 扫描包 -->
<context:component-scan base-package= "com.project.ssm.dao,com.project.ssm.service" />
<!-- 数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://hadoop00:3306/mybatis?user=root&password=root&useUnicode=true&characterEncoding=utf8"/>
<property name="user" value="root"/>
<property name="password" value="root"/>
<property name="maxPoolSize" value="10"/>
<property name="minPoolSize" value="2"/>
<property name="initialPoolSize" value="3"/>
<property name="acquireIncrement" value="2"/>
</bean>
<!-- mybatis整合spring的核心类。 -->
<bean id="sf" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 指定数据源 -->
<property name="dataSource" ref="dataSource" />
<!-- 指定mybatis配置文件 -->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<!-- 数据源事务管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
</beans>
(2).mybatis-config.xml(MyBatis的核心配置文件)<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<typeAlias type="com.project.ssm.domain.Person" alias="_person"/>
</typeAliases>
<!-- 引入映射文件 -->
<mappers>
<mapper resource="PersonMapper.xml"/>
</mappers>
</configuration>
(3).PersonMapper.xml(PersonDao的MyBatis配置文件)<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="person">
<insert id="insert">
insert into persons(name,phone) values(#{name},#{phone})
</insert>
<!-- selectOne -->
<select id="selectOne" parameterType="String" resultType="_person">
select
id,
name,
phone
from persons where phone = #{phone}
</select>
<!-- selectList -->
<select id="selectList" resultType="_person">
select
id,
name,
phone
from persons
</select>
</mapper>
(4).project.properties(访问HBase要用到的配置文件,要将相关配置改为你的配置)#----- kafka配置 ----#
#zk服务器
zookeeper.connect=hadoop01:2181
#消费者组
group.id=g1
zookeeper.session.timeout.ms=500
zookeeper.sync.time.ms=250
auto.commit.interval.ms=1000
#消费偏移量,从头消费
auto.offset.reset=smallest
#主题
kafka.topic=calllog
#----- HBase配置 ------#
hbase.zookeeper.quorum=hadoop01:2181
hbase.tablename=ns1:calllog
partition.num=100
#---- 其他配置 ----#
#呼叫标志位,1代表主叫,0代表被叫
callerflag=1
calleeflag=0
在web/WEB-INF下新建一个Spring MVC的配置文件dispatcher-servlet.xml:<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!-- 配置扫描路径 -->
<context:component-scan base-package="com.project.ssm.web.controller" />
<!-- 使用注解驱动 -->
<mvc:annotation-driven />
<mvc:resources mapping="/js/**" location="/js/"/>
<mvc:resources mapping="/css/**" location="/css/"/>
<mvc:resources mapping="/images/**" location="/images/"/>
<mvc:resources mapping="/html/**" location="/html/"/>
<!-- 内部资源视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/" />
<property name="suffix" value=".jsp"/>
</bean>
</beans>
2.在dao目录下创建一个接口PersonDao,该接口用于查询MySQL中电话用户的基本信息:/**
* 通讯人信息Dao,在MySQL中查询用户信息
*/
public interface PersonDao {
//插入一条信息
public void addOne(Person person);
//根据电话号码查询信息
public Person findByPhone(String phone);
//查询所有
public List<Person> findAll();
}
在dao目录包下创建impl包,再在impl包中创建类PersonDaoImpl,该类实现PersonDao接口:/**
* PersonDao实现类
*/
@Repository("PersonDao")
public class PersonDaoImpl extends SqlSessionDaoSupport implements PersonDao {
public void addOne(Person person) {
getSqlSession().insert("person.insert",person);
}
public Person findByPhone(String phone) {
return getSqlSession().selectOne("person.selectOne",phone);
}
public List<Person> findAll() {
return getSqlSession().selectList("person.selectList");
}
}
3.在domain包下创建如下几个类:/**
* 通讯人信息
*/
public class Person {
private Integer id;
private String name;
private String phone;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
(2).CallLog/**
* 通话记录的全部信息
*/
public class CallLog {
private String caller ;
private String callee ;
private String callDate ;
private String callDuration ;
private String callerName;
private String calleeName;
private boolean flag;
public String getCallerName() {
return callerName;
}
public void setCallerName(String callerName) {
this.callerName = callerName;
}
public String getCalleeName() {
return calleeName;
}
public void setCalleeName(String calleeName) {
this.calleeName = calleeName;
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
public String getCaller() {
return caller;
}
public void setCaller(String caller) {
this.caller = caller;
}
public String getCallee() {
return callee;
}
public void setCallee(String callee) {
this.callee = callee;
}
public String getCallDate() {
//格式化时间
try {
SimpleDateFormat sf1 = new SimpleDateFormat();
SimpleDateFormat sf2 = new SimpleDateFormat();
sf1.applyPattern("yyyyMMddHHmmss");
sf2.applyPattern("yyyy-MM-dd HH:mm:ss");
return sf2.format(sf1.parse(callDate));
}catch (Exception e){
e.printStackTrace();
}
return null;
}
public void setCallDate(String callDate) {
this.callDate = callDate;
}
public String getCallDuration() {
return callDuration;
}
public void setCallDuration(String callDuration) {
this.callDuration = callDuration;
}
}
(3).CallLogRage /**
* 封装了按时段查询通话记录的参数
*/
public class CallLogRange {
private String startPoint ;
private String endPoint ;
public String getStartPoint() {
return startPoint;
}
public void setStartPoint(String startPoint) {
this.startPoint = startPoint;
}
public String getEndPoint() {
return endPoint;
}
public void setEndPoint(String endPoint) {
this.endPoint = endPoint;
}
public String toString() {
return startPoint + " - " + endPoint ;
}
}
(4).CallMessageStat/**
* 统计电话用户通话记录类
*/
public class CallMessageStat {
String caller;
String callerName;
Integer callNum;
Integer callDuration;
public String getCaller() {
return caller;
}
public void setCaller(String caller) {
this.caller = caller;
}
public String getCallerName() {
return callerName;
}
public void setCallerName(String callerName) {
this.callerName = callerName;
}
public Integer getCallNum() {
return callNum;
}
public void setCallNum(Integer calleeNum) {
this.callNum = calleeNum;
}
public Integer getCallDuration() {
return callDuration;
}
public void setCallDuration(Integer calleeDuration) {
this.callDuration = calleeDuration;
}
}
4.在util包下创建两个类:**
* 配置文件工具类
*/
public class PropertiesUtil {
//单例模式
private PropertiesUtil(){}
//静态配置对象
public static Properties props = null;
//初始化对象
static {
InputStream in = ClassLoader.getSystemResourceAsStream("project.properties");
props = new Properties();
try {
props.load(in);
} catch (IOException e) {
e.printStackTrace();
}
}
//获得配置属性
public static String getProperty(String key){
return props.getProperty(key);
}
}
(2).CallLogUtil类,该类为后续的查询提供了:计算region区域号,按时间段计算region区域范围等功能,是该模块的核心类之一:/**
* CallLog工具类
*/
public class CallLogUtil {
private static SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
private static SimpleDateFormat sdfFriend = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
//格式化
private static DecimalFormat df = new DecimalFormat();
public static String getHashCode(String caller,String callDateFormat,int partitonsNum) {
//取年份和月份
String date = callDateFormat.substring(0, 6);
//取电话号码最后5位
int len = caller.length();
String number = caller.substring(len - 5);
//取哈希值
int code = (Integer.parseInt(date) ^ Integer.parseInt(number) ) % partitonsNum;
//格式化后返回
DecimalFormat df = new DecimalFormat();
df.applyPattern("00");
return df.format(code);
}
//得到起始RowKey
public static String getStartRow(String caller,String startDate,int partitonsNum){
String hashCode = getHashCode(caller,startDate,partitonsNum);
return hashCode + "," + caller + "," + startDate;
}
//得到结束RowKey
//注意,StopKey的哈希值由startKey计算得来!!!!
public static String getStopRow(String caller,String startDate,String stopDate,int partitonsNum){
String hashCode = getHashCode(caller,startDate,partitonsNum);
return hashCode + "," + caller + "," + stopDate;
}
/**
* 计算查询时间范围
*/
public static List<CallLogRange> getCallLogRanges(String startStr ,String endStr){
try{
SimpleDateFormat sdfYMD = new SimpleDateFormat("yyyyMMdd");
SimpleDateFormat sdfYM = new SimpleDateFormat("yyyyMM");
DecimalFormat df00 = new DecimalFormat("00");
//
List<CallLogRange> list = new ArrayList<CallLogRange>();
//字符串时间
String startPrefix = startStr.substring(0, 6);
String endPrefix = endStr.substring(0, 6);
int endDay = Integer.parseInt(endStr.substring(6, 8));
//结束点
String endPoint = endPrefix + df00.format(endDay + 1);
//日历对象
Calendar c = Calendar.getInstance();
//同年月
if (startPrefix.equals(endPrefix)) {
CallLogRange range = new CallLogRange();
range.setStartPoint(startStr); //设置起始点
range.setEndPoint(endPoint); //设置结束点
list.add(range);
} else {
//1.起始月
CallLogRange range = new CallLogRange();
range.setStartPoint(startStr);
//设置日历的时间对象
c.setTime(sdfYMD.parse(startStr));
c.add(Calendar.MONTH, 1);
range.setEndPoint(sdfYM.format(c.getTime()));
list.add(range);
//是否是最后一月
while (true) {
//到了结束月份
if (endStr.startsWith(sdfYM.format(c.getTime()))) {
range = new CallLogRange();
range.setStartPoint(sdfYM.format(c.getTime()));
range.setEndPoint(endPoint);
list.add(range);
break;
} else {
range = new CallLogRange();
//起始时间
range.setStartPoint(sdfYM.format(c.getTime()));
//增加月份
c.add(Calendar.MONTH, 1);
range.setEndPoint(sdfYM.format(c.getTime()));
list.add(range);
}
}
}
return list ;
}
catch(Exception e){
e.printStackTrace();
}
return null ;
}
}
5.在services包下添加服务接口:/**
*与HBase直接交互的服务
*/
public interface CallLogService {
public List<CallLog> findAll();
public List<CallLog> findByDate(String caller, List<CallLogRange> list);
}
(2).HiveCallLogService/**
* 与Hive交互的服务
*/
public interface HiveCallLogService {
public List<CallLog> findLatestCallLog(String phoneNum);
public List<CallMessageStat> findCallMessageStat();
}
(3).PersonService/**
* 交互MySQLService类
*/
public interface PersonService {
//插入一条信息
public void addOne(Person person);
//根据电话号码查询信息
public Person findByPhone(String phone);
//查询所有
public List<Person> findAll();
}
然后在该包下创建impl包,以实现以上3个接口,在impl包下创建以下类:/**
* PersonService的实现类
*/
@Service("PersonService")
public class PersonServiceImpl implements PersonService {
@Resource(name = "PersonDao")
private PersonDao personDao;
public void addOne(Person person) {
personDao.addOne(person);
}
public Person findByPhone(String phone) {
return personDao.findByPhone(phone);
}
public List<Person> findAll() {
return personDao.findAll();
}
}
(2).CallLogServiceImpl/**
* 交互HBase提供查询服务
*/
@Service("callLogService")
public class CallLogServiceImpl implements CallLogService{
@Resource(name = "PersonService")
private PersonService personService;
private Table table ;
public CallLogServiceImpl(){
try {
Configuration conf = HBaseConfiguration.create();
conf.set("hbase.zookeeper.quorum", "hadoop01:2181");
Connection conn = ConnectionFactory.createConnection(conf);
TableName name = TableName.valueOf("ns1:calllog");
table = conn.getTable(name);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
*查询所有log
*/
public List<CallLog> findAll() {
List<CallLog> list = new ArrayList<CallLog>();
try {
Scan scan = new Scan();
ResultScanner rs = table.getScanner(scan);
Iterator<Result> it = rs.iterator();
boolean flag = false;
CallLog log = null ;
String callerName = null;
String calleeName = null;
while(it.hasNext()){
log = new CallLog();
Result r = it.next();
String rowKey = Bytes.toString(r.getRow());
String[] row = rowKey.split(",");
//查询主叫的姓名
callerName = personService.findByPhone(row[1]).getName();
//查询被叫的姓名
calleeName = personService.findByPhone(row[4]).getName();
flag = row[3].equals("1")?true:false;
log.setCallDate(row[2]);
log.setCallee(row[4]);
log.setCaller(row[1]);
log.setCallerName(callerName);
log.setCalleeName(calleeName);
log.setCallDuration(row[5]);
log.setFlag(flag);
list.add(log);
}
return list ;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public List<CallLog> findByDate(String call, List<CallLogRange> ranges) {
List<CallLog> list = new ArrayList<CallLog>();
try {
for(CallLogRange range : ranges) {
Scan scan = new Scan();
//设置起始RowKey
scan.setStartRow((CallLogUtil.getStartRow(call,range.getStartPoint(),100)).getBytes());
//设置结束RowKey
scan.setStopRow((CallLogUtil.getStopRow(call,range.getStartPoint(),range.getEndPoint(),100)).getBytes());
ResultScanner rs = table.getScanner(scan);
Iterator<Result> it = rs.iterator();
CallLog log = null;
boolean flag = false;
while (it.hasNext()) {
log = new CallLog();
Result r = it.next();
String rowKey = Bytes.toString(r.getRow());
String[] row = rowKey.split(",");
flag = row[3].equals("1")?true:false;
log.setCaller(row[1]);
log.setCallDate(row[2]);
log.setCallee(row[4]);
log.setCallDuration(row[5]);
log.setFlag(flag);
list.add(log);
}
}
return list;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
(3).HiveCallLogServiceImpl/**
* 使用Hive对通话日志统计实现类
*/
@Service("hiveCallLogService")
public class HiveCallLogServiceImpl implements HiveCallLogService {
@Resource(name = "PersonService")
private PersonService personService;
//hiveserver2连接串
private static String url = "jdbc:hive2://hadoop00:10000/mydb";
//驱动程序类
private static String driverClass = "org.apache.hive.jdbc.HiveDriver" ;
// 与Hive的JDBC连接
private static Connection connection = null;
//加载hive驱动,初始化JDBC连接
static{
try {
Class.forName(driverClass);
connection = DriverManager.getConnection(url);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 查询最近的3个通话记录,使用hive进行mr查询.
*/
public List<CallLog> findLatestCallLog(String phoneNum){
try {
List<CallLog> list = new ArrayList<CallLog>();
String sql = "select * " +
"from calllogs_in_hbase where caller like '%"+ phoneNum +"%' limit 3" ;
PreparedStatement ps = connection.prepareStatement(sql);
ResultSet rs = ps.executeQuery();
CallLog log = null ;
String callerName = null;
String calleeName = null;
String id = null;
String[] arr = null;
Boolean flag = null;
while (rs.next()){
log = new CallLog();
id = rs.getString("id");
arr = id.split(",");
callerName = personService.findByPhone(arr[1]).getName();
calleeName = personService.findByPhone(arr[4]).getName();
flag = arr[3].equals("1")?true:false;
log.setCaller(arr[1]);
log.setCallee(arr[4]);
log.setCallDate(arr[2]);
log.setCallDuration(arr[5]);
log.setCallerName(callerName);
log.setCalleeName(calleeName);
log.setFlag(flag);
list.add(log);
}
rs.close();
return list ;
} catch (Exception e) {
e.printStackTrace();
}
return null ;
}
/**
* 查询每个用户的所有通话记录的个数,以及通话时长
* @return
*/
public List<CallMessageStat> findCallMessageStat() {
List<CallMessageStat> callMessageStats = new ArrayList<CallMessageStat>();
CallMessageStat callMessageStat ;
try {
String sql = "select caller, count(caller) as callNum,sum(callduration) as callDurations " +
"from calllogs_in_hbase group by caller";
PreparedStatement ps = connection.prepareStatement(sql);
ResultSet resultSet = ps.executeQuery();
while (resultSet.next()){
String caller = resultSet.getString("caller");
// 查询用户的姓名
String callerName = personService.findByPhone(caller).getName();
Integer callNum = resultSet.getInt("callNum");
Integer callDurations = resultSet.getInt("callDurations");
// 将统计信息封装
callMessageStat = new CallMessageStat();
callMessageStat.setCaller(caller);
callMessageStat.setCallerName(callerName);
callMessageStat.setCallNum(callNum);
callMessageStat.setCallDuration(callDurations);
// 将封装好的对象放入集合
callMessageStats.add(callMessageStat);
System.out.println(callMessageStat);
}
}catch (Exception e){
e.printStackTrace();
}
return callMessageStats;
}
}
6.在web.controller包下创建类CallLogController用于接收前端页面的请求并提供服务:/**
*通话记录查询服务Controller类
*/
@Controller
public class CallLogController {
// 注入callLogService,此服务直接与HBase交互
@Resource(name="callLogService")
private CallLogService cs ;
//注入hiveservice,此服务与hiveServer2交互
@Resource(name="hiveCallLogService")
private HiveCallLogService hcs ;
//全表扫描,查询所有用户的通话记录信息
@RequestMapping("/callLog/findAll")
public String findAll(Model m){
List<CallLog> list = cs.findAll();
m.addAttribute("callLogs",list);
return "callLog/callLogList" ;
}
//跳转至查询页面
@RequestMapping("/callLog/LogByDate")
public String LogByDatePage(){
return "callLog/LogByDatePage" ;
}
//按时间段查询通话记录
@RequestMapping(value = "/callLog/findLogByDate",method = RequestMethod.POST)
public String findLogByDate(Model m,@RequestParam("caller") String caller ,@RequestParam("startDate") String startDate
,@RequestParam("endDate") String endDate){
//得到所有的时间段
List<CallLogRange> list = CallLogUtil.getCallLogRanges(startDate,endDate);
//按时间得到所有的通话记录
List<CallLog> logList = cs.findByDate(caller,list);
m.addAttribute("callLogs",logList);
return "callLog/callLogList" ;
}
//根据号码查找最近的三次通话页面跳转
@RequestMapping("/callLog/toFindLatestCallLog")
public String toFindLatestCallLog(){
return "/callLog/findLatestCallLog";
}
//根据号码查找最近的三次通话
@RequestMapping(value = "/callLog/findLatestCallLog",method = RequestMethod.POST)
public String findLatestCallLog(Model m,@RequestParam("caller") String caller){
List<CallLog> list = hcs.findLatestCallLog(caller);
System.out.println(list.size());
m.addAttribute("callLogs",list);
return "callLog/latestCallLog" ;
}
// 查找一个用户所有的用户通话记录统计
@RequestMapping("/callLog/toFindCallMessage")
public String toFindCallMessage(Model m){
List<CallMessageStat> list = hcs.findCallMessageStat();
m.addAttribute("callMessages",list);
return "/callLog/callMessageLogList";
}
}
7.在web目录下创建三个目录用以存放前端界面相关的文件:body{
border : 1px solid blue ;
margin: 0px;
/*background-color: aquamarine;*/
}
table {
border: 1px solid cadetblue;
border-collapse: collapse;
width: 400px;
margin: 50px auto;
}
table td {
text-align: center;
height: 45px;
}
table tr:nth-child(even) {
background-color: beige;
}
再创建一个js目录,里面放入jQuery的框架即可,我使用的是jquery-3.2.0.min.js,可以自行下载。<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
<title>所有通话记录</title>
<link rel="stylesheet" type="text/css" href="../css/my.css">
</head>
<body>
<table id="t1" border="1px" class="t-1" style="width: 800px">
<tr>
<td>电话1</td>
<td>姓名1</td>
<td>电话2</td>
<td>姓名2</td>
<td>主(被)叫</td>
<td>通话时间</td>
<td>通话时长</td>
</tr>
<c:forEach items="${callLogs}" var="log">
<tr>
<td><c:out value="${log.caller}"/></td>
<td><c:out value="${log.callerName}"/></td>
<td><c:out value="${log.callee}"/></td>
<td><c:out value="${log.calleeName}"/></td>
<td>
<c:if test="${log.flag == true}">主叫</c:if>
<c:if test="${log.flag == false}">被叫</c:if>
</td>
<td><c:out value="${log.callDate}"/></td>
<td><c:out value="${log.callDuration}"/></td>
</tr>
</c:forEach>
<tr>
<td colspan="7" style="text-align: right">
</td>
</tr>
</table>
</body>
</html>
(2).callMessageLogList.jsp<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
<title>所有通话记录统计</title>
<link rel="stylesheet" type="text/css" href="../css/my.css">
</head>
<body>
<table id="t1" border="1px" class="t-1" style="width: 800px">
<tr>
<td>号码</td>
<td>姓名</td>
<td>通话个数</td>
<td>通话总时长(秒)</td>
</tr>
<c:forEach items="${callMessages}" var="message">
<tr>
<td><c:out value="${message.caller}"/></td>
<td><c:out value="${message.callerName}"/></td>
<td><c:out value="${message.callNum}"/></td>
<td><c:out value="${message.callDuration}"/></td>
</tr>
</c:forEach>
<tr>
<td colspan="4" style="text-align: right">
</td>
</tr>
</table>
</body>
</html>
(3).findLatestCallLogList.jsp<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
<title>查询最近三次通话记录</title>
<link rel="stylesheet" type="text/css" href="../css/my.css">
</head>
<body>
<form action=' ' method="post">
<table>
<tr>
<td>电话号码 :</td>
<td><input type="text" name="caller"></td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="查询"/>
</td>
</tr>
</table>
</form>
</body>
</html>
(4).latestCallLog.jsp<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
<title>最近三次通话记录</title>
<link rel="stylesheet" type="text/css" href="../css/my.css">
</head>
<body>
<c:if test="${callLogs == null}">
无记录!
</c:if>
<c:if test="${callLogs != null}">
<c:forEach items="${callLogs}" var="log">
<table id="t1" border="1px" class="t-1" style="width: 800px">
<tr>
<td>电话1</td>
<td><c:out value="${log.caller}" /></td>
</tr>
<tr>
<td>姓名1</td>
<td><c:out value="${log.callerName}" /></td>
</tr>
<tr>
<td>电话2</td>
<td><c:out value="${log.callee}"/></td>
</tr>
<tr>
<td>姓名2</td>
<td><c:out value="${log.calleeName}"/></td>
</tr>
<tr>
<td>被叫/主叫</td>
<c:if test="${log.flag == true}"><td>主叫</td></c:if>
<c:if test="${log.flag == false}"><td>被叫</td></c:if>
</tr>
<tr>
<td>时间</td>
<td><c:out value="${log.callDate}"/></td>
</tr>
<tr>
<td>时长</td>
<td><c:out value="${log.callDuration}"/></td>
</tr>
</table>
</c:forEach>
</c:if>
</body>
</html>
(5).LogByDatePage.jsp<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
<title>时间段查询通话记录</title>
<link rel="stylesheet" type="text/css" href="../css/my.css">
</head>
<body>
<form action=' ' method="post">
<table>
<tr>
<td>电话号码 :</td>
<td><input type="text" name="caller"></td>
</tr>
<tr>
<td>起始时间 :</td>
<td><input type="text" name="startDate"></td>
</tr>
<tr>
<td>结束时间:</td>
<td><input type="text" name="endDate"></td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="查询"/>
</td>
</tr>
</table>
</form>
</body>
</html>
(8).在MySQL中创建一张表用于存储用户的基本信息,有三个字段:id(int),create external table calllogs_in_hbase(id string, caller string,callDate string,callee string,callDuration string) STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler' WITH SERDEPROPERTIES ("hbase.columns.mapping" = ":key,f1:caller,f1:callDate,f1:callee,f1:callDuration") TBLPROPERTIES ("hbase.table.name" = "ns1:calllog")
$HIVE_HOME/bin
目录下,执行命令:./hive --service hiveserver2
netstat -anop|grep 10000