一、概述

Spark Core、Spark-SQL与Spark-Streaming都是相同的,编写好之后打成jar包使用spark-submit命令提交到集群运行应用
$SPARK_HOME/bin#./spark-submit  --master spark://Master01:7077  --class MainClassFullName [--files $HIVE_HOME/conf/hive-site.xml] JarNameFullPath [slices]

说明:
--master参数用于指定提交到的Spark集群入口,这个入口通常是Spark的Master节点(即Master进程或ResourceManager进程所在的节点),如果需要为该参数指定一个高可用集群则集群节点之间使用英文逗号分割
--class参数用于指定Spark之Driver的入口Main类(必须指定该Main类的全名)
如果使用Spark操作Hive仓库则需要使用--files参数指定Hive的配置文件
如果使用Spark操作关系数据库则需要将关系数据库的驱动包放置于Spark安装目录下的library目录下(在Spark2.x中应该放置于jars目录下),如:
[hadoop@CloudDeskTop jars]$ pwd
/software/spark-2.1.1/jars
JarNameFullPath表示的是提交的Spark应用所在的JAR包全名(最好指定为绝对的全路径)
slices:表示的是读取数据的并行度(值为一个数值,根据实际的物理内存配置来指定,内存较小时指定为1或者不用指定),一般在Streaming应用中是不需要指定的

二、Spark之JDBC实战

(一)、本地模式操作

典型业务场景描述:将CloudDeskTop客户端本地的数据,通过Spark处理,然后将结果写入远端关系数据库中,供前端在线事务系统使用

1、在Eclipse4.5中建立工程RDDToJDBC,并创建一个文件夹lib用于放置第三方驱动包

[hadoop@CloudDeskTop software]$ cd /project/RDDToJDBC/
[hadoop@CloudDeskTop RDDToJDBC]$ mkdir -p lib
[hadoop@CloudDeskTop RDDToJDBC]$ ls
bin lib src

2、添加必要的环境

2.1、将MySql的jar包拷贝到工程目录RDDToJDBC下的lib目录下
[hadoop@CloudDeskTop software]$ cp -a /software/hive-1.2.2/lib/mysql-connector-java-3.0.17-ga-bin.jar /project/RDDToJDBC/lib/
2.1、将Spark的开发库Spark2.1.1-All追加到RDDToJDBC工程的classpath路径中去(可以通过添加用户库的方式来解决);Spark2.1.1-All中包含哪些包,请点击此处

3、基于RDD到DB的Java源码

 package com.mmzs.bigdata.spark.core.local;

 import java.io.File;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List; import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaPairRDD;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.api.java.function.FlatMapFunction;
import org.apache.spark.api.java.function.Function2;
import org.apache.spark.api.java.function.PairFunction;
import org.apache.spark.api.java.function.VoidFunction; import scala.Tuple2;
import scala.Tuple4; public class RDDToDB {
/**
* 全局计数器
*/
private static int count; /**
* 数据库连接
*/
private static Connection conn; /**
* 预编译语句
*/
private static PreparedStatement pstat; private static final File OUT_PATH=new File("/home/hadoop/test/output"); static{
delDir(OUT_PATH);
try {
String sql="insert into wordcount(word,count) values(?,?)";
String url="jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8";
Class.forName("com.mysql.jdbc.Driver");
conn=DriverManager.getConnection(url, "root", "123456");
pstat=conn.prepareStatement(sql);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* 删除任何目录或文件
* @param f
*/
private static void delDir(File f){
if(!f.exists())return;
if(f.isFile()||(f.isDirectory()&&f.listFiles().length==0)){
f.delete();
return;
}
File[] files=f.listFiles();
for(File fp:files)delDir(fp);
f.delete();
} //分批存储
private static void batchSave(Tuple2<String, Integer> line,boolean isOver){
try{
pstat.setString(1, line._1());
pstat.setInt(2, line._2()); if(isOver){//如果结束了循环则直接写磁盘
pstat.addBatch();
pstat.executeBatch();
pstat.clearBatch();
pstat.clearParameters();
}else{ //如果没有结束则将sql语句添加到批处理中去
pstat.addBatch();
count++;
if(count%100==0){ //如果满一个批次就提交一次批处理操作
pstat.executeBatch();
pstat.clearBatch();
pstat.clearParameters();
}
}
}catch(SQLException e){
e.printStackTrace();
}
} /**
* 将RDD集合中的数据存储到关系数据库MYSql中去
* @param statResRDD
*/
private static void saveToDB(JavaPairRDD<String, Integer> statResRDD){
final long rddNum=statResRDD.count();
statResRDD.foreach(new VoidFunction<Tuple2<String,Integer>>(){
private long count=0;
@Override
public void call(Tuple2<String, Integer> line) throws Exception {
if(++count<rddNum){
batchSave(line,false);
}else{
batchSave(line,true);
}
}
}); try{
if(null!=pstat)pstat.close();
if(null!=conn)conn.close();
}catch(SQLException e){
e.printStackTrace();
}
} public static void main(String[] args) {
SparkConf conf=new SparkConf();
conf.setAppName("Java Spark local");
conf.setMaster("local"); //根据Spark配置生成Spark上下文
JavaSparkContext jsc=new JavaSparkContext(conf); //读取本地的文本文件成内存中的RDD集合对象
JavaRDD<String> lineRdd=jsc.textFile("/home/hadoop/test/jdbc"); //切分每一行的字串为单词数组,并将字串数组中的单词字串释放到外层的JavaRDD集合中
JavaRDD<String> flatMapRdd=lineRdd.flatMap(new FlatMapFunction<String,String>(){
@Override
public Iterator<String> call(String line) throws Exception {
String[] words=line.split(" ");
List<String> list=Arrays.asList(words);
Iterator<String> its=list.iterator();
return its;
}
}); //为JavaRDD集合中的每一个单词进行计数,将其转换为元组
JavaPairRDD<String, Integer> mapRdd=flatMapRdd.mapToPair(new PairFunction<String, String,Integer>(){
@Override
public Tuple2<String,Integer> call(String word) throws Exception {
return new Tuple2<String,Integer>(word,1);
}
}); //根据元组中的第一个元素(Key)进行分组并统计单词出现的次数
JavaPairRDD<String, Integer> reduceRdd=mapRdd.reduceByKey(new Function2<Integer,Integer,Integer>(){
@Override
public Integer call(Integer pre, Integer next) throws Exception {
return pre+next;
}
}); //将单词元组中的元素反序以方便后续排序
JavaPairRDD<Integer, String> mapRdd02=reduceRdd.mapToPair(new PairFunction<Tuple2<String, Integer>,Integer,String>(){
@Override
public Tuple2<Integer, String> call(Tuple2<String, Integer> wordTuple) throws Exception {
return new Tuple2<Integer,String>(wordTuple._2,wordTuple._1);
}
}); //将JavaRDD集合中的单词按出现次数进行将序排列
JavaPairRDD<Integer, String> sortRdd=mapRdd02.sortByKey(false, 1); //排序之后将元组中的顺序换回来
JavaPairRDD<String, Integer> mapRdd03=sortRdd.mapToPair(new PairFunction<Tuple2<Integer, String>,String,Integer>(){
@Override
public Tuple2<String, Integer> call(Tuple2<Integer, String> wordTuple) throws Exception {
return new Tuple2<String, Integer>(wordTuple._2,wordTuple._1);
}
}); //存储统计之后的结果到磁盘文件中去
//mapRdd03.saveAsTextFile("/home/hadoop/test/jdbc/output"); saveToDB(mapRdd03); //关闭Spark上下文
jsc.close();
}
}

4、测试Spark的JDBC应用

4.1、初始化MySql数据库服务(节点在192.168.154.134上)

A、启动MySql数据库服务

[root@DB03 ~]# cd /software/mysql-5.5.32/multi-data/3306/
[root@DB03 3306]# ls
data my.cnf my.cnf.bak mysqld
[root@DB03 3306]# ./mysqld start
Starting MySQL...

B、建立test库

[root@CloudDeskTop 3306]# cd /software/mysql-5.5.32/bin/
[root@CloudDeskTop bin]# ./mysql -h192.168.154.134 -P3306 -uroot -p123456 -e "show databases;"
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
+--------------------+
[root@CloudDeskTop bin]# ./mysql -h192.168.154.134 -P3306 -uroot -p123456 -e "create database test character set utf8;"
[root@CloudDeskTop bin]# ./mysql -h192.168.154.134 -P3306 -uroot -p123456 -e "show databases;"
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| test |
+--------------------+

C、建立wordcount表

[root@DB03 bin]# ./mysql -h192.168.154.134 -P3306 -uroot -p123456 -e "create table if not exists test.wordcount(wid int(11) auto_increment primary key,word varchar(30),count int(3))engine=myisam charset=utf8;"
[root@DB03 bin]# ./mysql -h192.168.154.134 -P3306 -uroot -p123456 -e "desc test.wordcount;"
+-------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+----------------+
| wid | int(11) | NO | PRI | NULL | auto_increment |
| word | varchar(30) | YES | | NULL | |
| count | int(3) | YES | | NULL | |
+-------+-------------+------+-----+---------+----------------+ #目前数据库表中还没有数据
[root@DB03 bin]# ./mysql -h192.168.154.134 -P3306 -uroot -p123456 -e "select * from test.wordcount;"
4.2、准备Spark的源数据
[hadoop@CloudDeskTop jdbc]$ pwd
/home/hadoop/test/jdbc
[hadoop@CloudDeskTop jdbc]$ ls
myuser testJDBC.txt
[hadoop@CloudDeskTop jdbc]$ cat testJDBC.txt myuser
zhnag san shi yi ge hao ren
jin tian shi yi ge hao tian qi
wo zai zhe li zuo le yi ge ce shi
yi ge guan yu scala de ce shi
welcome to mmzs
欢迎 欢迎
lisi 123456 165 1998-9-9
lisan 123ss 187 2009-10-19
wangwu 123qqwe 177 1990-8-3
4.3、在Eclipse4.5中直接运行Spark代码,观察Eclipse控制台输出
4.4、检查在关系数据库MySql中是否已经存在数据

[root@CloudDeskTop bin]# ./mysql -h192.168.154.134 -P3306 -uroot -p123456 -e "select * from test.wordcount;"

(二)、集群模式操作

典型业务场景描述:将HDFS集群中的数据通过Spark处理之后,将结果写入远端关系数据库中,供前端在线事务系统使用

1、在Eclipse4.5中的工程RDDToJDBC下创建一个package文件夹用于放置打包文件

[hadoop@CloudDeskTop software]$ cd /project/RDDToJDBC/
[hadoop@CloudDeskTop RDDToJDBC]$ mkdir -p package
[hadoop@CloudDeskTop RDDToJDBC]$ ls
bin package src

2、将关系数据库的驱动包放置到Spark安装目录下的jars目录下

在客户端上传所需的mysql-connector-java-3.0.17-ga-bin.jar包:
[hadoop@CloudDeskTop jars]# pwd
/software/spark-2.1.1/jars
然后分发到集群:
[hadoop@CloudDeskTop software]$ scp -r /software/spark-2.1.1/jars/mysql-connector-java-3.0.17-ga-bin.jar master01:/software/spark-2.1.1/jars/
[hadoop@master01 software]$ scp -r /software/spark-2.1.1/jars/mysql-connector-java-3.0.17-ga-bin.jar master02:/software/spark-2.1.1/jars/
[hadoop@master01 software]$ scp -r /software/spark-2.1.1/jars/mysql-connector-java-3.0.17-ga-bin.jar slave01:/software/spark-2.1.1/jars/
[hadoop@master01 software]$ scp -r /software/spark-2.1.1/jars/mysql-connector-java-3.0.17-ga-bin.jar slave02:/software/spark-2.1.1/jars/
[hadoop@master01 software]$ scp -r /software/spark-2.1.1/jars/mysql-connector-java-3.0.17-ga-bin.jar slave03:/software/spark-2.1.1/jars/

3、开发源码

 package com.mmzs.bigdata.spark.core.cluster;

 import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List; import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaPairRDD;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.api.java.function.FlatMapFunction;
import org.apache.spark.api.java.function.Function2;
import org.apache.spark.api.java.function.PairFunction;
import org.apache.spark.api.java.function.VoidFunction; import scala.Tuple2; public class RDDToDB {
/**
* 全局计数器
*/
private static int count; /**
* 数据库连接
*/
private static Connection conn; /**
* 预编译语句
*/
private static PreparedStatement pstat; static{
try {
String sql="insert into wordcount(word,count) values(?,?)";
String url="jdbc:mysql://192.168.154.134:3306/test?useUnicode=true&characterEncoding=utf8";
Class.forName("com.mysql.jdbc.Driver");
conn=DriverManager.getConnection(url, "root", "123456");
pstat=conn.prepareStatement(sql);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
} /**
* 批量存储数据
* @param line
* @throws SQLException
*/
private static void batchSave(Tuple2<String, Integer> line,boolean isOver){
try{
pstat.setString(1, line._1());
pstat.setInt(2, line._2()); if(isOver){//如果结束了循环则直接写磁盘。
//如果RDD数据已经迭代结束,则执行剩下的批量语句。
pstat.addBatch();
pstat.executeBatch();
pstat.clearBatch();
pstat.clearParameters();
}else{ //如果没有结束则将sql语句添加到批处理中去。
//如果RDD数据的迭代还未曾结束,则直接将当前语句添加到批处理计划中去;
//但是如果批处理语句数量超过了100则冲刷一次缓冲区中批处理并重置计数器。
pstat.addBatch();
count++;
if(count%100==0){ //如果满一个批次就提交一次批处理操作
pstat.executeBatch();
pstat.clearBatch();
pstat.clearParameters();
}
}
}catch(SQLException e){
e.printStackTrace();
}
} /**
* 将RDD集合中的数据存储到关系数据库MYSql中去。
* 存储结果到关系数据库中
* 必须将内部类对象方法(如:call)中的操作分离到一个独立的方法(如:batchSave)中去,
* 因为Spark给定的内部类API都是可序列化的,而执行JDBC操作的Statement和Connection都是不能被序列化的
* @param wordGroupList
* @throws ClassNotFoundException
*/
private static void saveToDB(JavaPairRDD<String, Integer> statResRDD){
final long rddNum=statResRDD.count();
statResRDD.foreach(new VoidFunction<Tuple2<String,Integer>>(){
private long count=0;
@Override
public void call(Tuple2<String, Integer> line) throws Exception {
if(++count<rddNum){
batchSave(line,false);
}else{
batchSave(line,true);
}
}
}); try{
if(null!=pstat)pstat.close();
if(null!=conn)conn.close();
}catch(SQLException e){
e.printStackTrace();
}
} public static void main(String[] args) {
SparkConf conf=new SparkConf();
conf.setAppName("Java Spark Cluster"); //根据Spark配置生成Spark上下文
JavaSparkContext jsc=new JavaSparkContext(conf); //读取本地的文本文件成内存中的RDD集合对象
JavaRDD<String> lineRdd=jsc.textFile("/spark/input", 1); //切分每一行的字串为单词数组,并将字串数组中的单词字串释放到外层的JavaRDD集合中
JavaRDD<String> flatMapRdd=lineRdd.flatMap(new FlatMapFunction<String,String>(){
@Override
public Iterator<String> call(String line) throws Exception {
String[] words=line.split(" ");
List<String> list=Arrays.asList(words);
Iterator<String> its=list.iterator();
return its;
}
}); //为JavaRDD集合中的每一个单词进行计数,将其转换为元组
JavaPairRDD<String, Integer> mapRdd=flatMapRdd.mapToPair(new PairFunction<String, String,Integer>(){
@Override
public Tuple2<String,Integer> call(String word) throws Exception {
return new Tuple2<String,Integer>(word,1);
}
}); //根据元组中的第一个元素(Key)进行分组并统计单词出现的次数
JavaPairRDD<String, Integer> reduceRdd=mapRdd.reduceByKey(new Function2<Integer,Integer,Integer>(){
@Override
public Integer call(Integer pre, Integer next) throws Exception {
return pre+next;
}
}); //将单词元组中的元素反序以方便后续排序
JavaPairRDD<Integer, String> mapRdd02=reduceRdd.mapToPair(new PairFunction<Tuple2<String, Integer>,Integer,String>(){
@Override
public Tuple2<Integer, String> call(Tuple2<String, Integer> wordTuple) throws Exception {
return new Tuple2<Integer,String>(wordTuple._2,wordTuple._1);
}
}); //将JavaRDD集合中的单词按出现次数进行将序排列
JavaPairRDD<Integer, String> sortRdd=mapRdd02.sortByKey(false, 1); //排序之后将元组中的顺序换回来
JavaPairRDD<String, Integer> mapRdd03=sortRdd.mapToPair(new PairFunction<Tuple2<Integer, String>,String,Integer>(){
@Override
public Tuple2<String, Integer> call(Tuple2<Integer, String> wordTuple) throws Exception {
return new Tuple2<String, Integer>(wordTuple._2,wordTuple._1);
}
}); //存储统计之后的结果到磁盘文件中去
//mapRdd03.saveAsTextFile("/spark/output"); saveToDB(mapRdd03); //关闭Spark上下文
jsc.close();
}
}

说明:
  在集群模式下,Spark操作关系数据库是通过启动一个Job来完成的,而启动Job则是通过RDD的操作来触发的,因此在Spark集群模式下其关系数据库的所有操作必须位于RDD操作级别才是有效的,否则数据的操作将无法影响到关系数据库中去,而RDD级别之外的操作都属于Spark Core的客户端Driver级别(比如:SparkSQL和SparkStreaming),在上面的代码中,只有RDD对象在被foreachXXX时才会进入到SparkCore级别的Job操作,在RDD之外的操作是属于Driver级别的操作,无法启动Job。
  在基于RDD级别的SparkCore操作过程中,其数据都是被封装成Job提交到集群,并在集群的各个节点上执行分配的Task,数据在各个Task节点之间传递需要数据本身支持可序列化,因此在Spark应用中出现的高频率内部类对象(比如上面的VoidFunction)都必须支持可序列化,这意味着在这些内部类对象中出现的成员也必须是可序列化的,因此我们在这些内部类对象所在的上下文中编写代码时必须注意不能出现不可序列化的对象或引用(如不能出现基于瞬态的流化对象Connection、Statement、Thread等),即在这些内部类对象上下文中出现的对象引用必须是实现了java.io.Seralizable接口的。

4、打包工程代码到dist目录下

[hadoop@CloudDeskTop ~]$ cd /project/RDDToJDBC/bin/
[hadoop@CloudDeskTop bin]$ ls
com mysql-connector-java-3.0.17-ga-bin.jar
[hadoop@CloudDeskTop bin]$ jar -cvfe /project/RDDToJDBC/package/RDDToJDBC.jar com.mmzs.bigdata.spark.core.cluster.RDDToDB com/
[hadoop@CloudDeskTop bin]$ cd ../package
[hadoop@CloudDeskTop package]$ ls
RDDToJDBC.jar

5、集群模式下的应用提交测试

A、启动spark集群运行环境:[hadoop@master01 install]$ sh start-total.sh

#!/bin/bash
echo "请首先确认你已经切换到hadoop用户"
#启动zookeeper集群
for node in hadoop@slave01 hadoop@slave02 hadoop@slave03;do ssh $node "source /etc/profile; cd /software/zookeeper-3.4.10/bin/; ./zkServer.sh start; jps";done #开启dfs集群
cd /software/ && start-dfs.sh && jps #开启spark集群
#启动master01的Master进程,slave节点的Worker进程
cd /software/spark-2.1.1/sbin/ && ./start-master.sh && ./start-slaves.sh && jps
#启动master02的Master进程
ssh hadoop@master02 "cd /software/spark-2.1.1/sbin/; ./start-master.sh; jps" #spark集群的日志服务,一般不开,因为比较占资源
#cd /software/spark-2.1.1/sbin/ && ./start-history-server.sh && cd - && jps start-spark.sh

start-spark.sh

B、在CloudDeskTop客户端节点上提交Spark应用
#将数据库中的旧数据删除掉
[root@CloudDeskTop bin]# pwd
/software/mysql-5.5.32/bin
[root@CloudDeskTop bin]# ./mysql -h192.168.154.134 -P3306 -uroot -p123456 -e "truncate table test.wordcount;"
[root@CloudDeskTop bin]# ./mysql -h192.168.154.134 -P3306 -uroot -p123456 -e "select * from test.wordcount;"

#准备源数据
[hadoop@CloudDeskTop jdbc]$ hdfs dfs -put testJDBC.txt /spark/input/
[hadoop@master02 ~]$ hdfs dfs -ls /spark/
Found 1 items
drwxr-xr-x - hadoop supergroup 0 2018-02-26 21:56 /spark/input
[hadoop@master02 ~]$ hdfs dfs -ls /spark/input
Found 1 items
-rw-r--r-- 3 hadoop supergroup 156 2018-02-26 21:56 /spark/input/testJDBC.txt
[hadoop@master02 ~]$ hdfs dfs -cat /spark/input/testJDBC.txt
zhnag san shi yi ge hao ren
jin tian shi yi ge hao tian qi
wo zai zhe li zuo le yi ge ce shi
yi ge guan yu scala de ce shi
welcome to mmzs
欢迎 欢迎

#提交Spark应用

首先:
[hadoop@CloudDeskTop lib]$ cd /software/spark-2.1.1/bin/
然后:
第一种提交方式:(可能会出现空指针异常的情况)
[hadoop@CloudDeskTop bin]$ ./spark-submit --master spark://master01:7077 --class com.mmzs.bigdata.spark.core.cluster.RDDToDB /project/RDDToJDBC/package/RDDToJDBC.jar
第二种提交方式:
[hadoop@CloudDeskTop bin]$ ./spark-submit --master spark://master01:7077 --class com.mmzs.bigdata.spark.core.cluster.RDDToDB --jars /software/spark-2.1.1/jars/mysql-connector-java-3.0.17-ga-bin.jar /project/RDDToJDBC/package/RDDToJDBC.jar

C、测试关系数据库中是否已经有数据
 [root@CloudDeskTop bin]# ./mysql -h192.168.154.134 -P3306 -uroot -p123456 -e "select * from test.wordcount;"

spark之JDBC开发(实战)的更多相关文章

  1. spark之JDBC开发(连接数据库测试)

    spark之JDBC开发(连接数据库测试) 以下操作属于本地模式操作: 1.在Eclipse4.5中建立工程RDDToJDBC,并创建一个文件夹lib用于放置第三方驱动包 [hadoop@CloudD ...

  2. 大数据开发实战:Spark Streaming流计算开发

    1.背景介绍 Storm以及离线数据平台的MapReduce和Hive构成了Hadoop生态对实时和离线数据处理的一套完整处理解决方案.除了此套解决方案之外,还有一种非常流行的而且完整的离线和 实时数 ...

  3. 大数据开发实战:Stream SQL实时开发一

    1.流计算SQL原理和架构 流计算SQL通常是一个类SQL的声明式语言,主要用于对流式数据(Streams)的持续性查询,目的是在常见流计算平台和框架(如Storm.Spark Streaming.F ...

  4. Spark SQL知识点与实战

    Spark SQL概述 1.什么是Spark SQL Spark SQL是Spark用于结构化数据(structured data)处理的Spark模块. 与基本的Spark RDD API不同,Sp ...

  5. 第五篇 :微信公众平台开发实战Java版之如何获取公众号的access_token以及缓存access_token

    一.access_token简介 为了使第三方开发者能够为用户提供更多更有价值的个性化服务,微信公众平台 开放了许多接口,包括自定义菜单接口.客服接口.获取用户信息接口.用户分组接口.群发接口等, 开 ...

  6. Java Web整合开发实战:基于Struts 2+Hibernate+Spring 目录

    第1篇 Java Web开发基础第1章 Web的工作机制( 教学视频:31分钟) 1.1 理解Web的概念 1.1.1 Web的定义 1.1.2 Web的三个核心标准 1.2 C/S与B/S两种软件体 ...

  7. Spring 3.x 实践 第一个例子(Spring 3.x 企业应用开发实战读书笔记第二章)

    前言:工作之后一直在搞android,现在需要更多和后台的人员交涉,技术栈不一样,难免鸡同鸭讲,所以稍稍学习下. 这个例子取自于<Spring 3.x 企业应用开发实战>一书中的第二章,I ...

  8. 学习《Spring 3.x 企业应用开发实战》Day-1

    Day-1 记录自己学习spring的笔记 提要:根据<Spring 3.x 企业应用开发实战>开头一个用户登录的例子,按照上面敲的. 1.项目分层

  9. AI应用开发实战

    AI应用开发实战 出发点 目前,人工智能在语音.文字.图像的识别与解析领域带来了跨越式的发展,各种框架.算法如雨后春笋一般,互联网上随处可见与机器学习有关的学习资源,各大mooc平台.博客.公开课都推 ...

随机推荐

  1. 牛客网华为机试题之Python解法

    牛客网华为机试题之Python解法 第1题 字符串最后一个单词的长度 a = input().split(" ") print(len(a[-1])) 第2题 计算字符个数 a = ...

  2. Ubuntu安装pyenv实现python多版本控制

    Ubuntu安装pyenv实现python多版本控制 git clone git://github.com/yyuu/pyenv.git ~/.pyenv echo 'export PYENV_ROO ...

  3. 网络操作系统 第九章 DHCP服务器管理与配置

    本章小结 本章介绍了DHCP服务器的基本概念,基本原理和主要功能,详细说明了Window是下DHCP服务器的安装配置和Linux下DHCP 服务器的安装配置,通过本章的学习.读者能够理解动态主机配置协 ...

  4. Redis和memcached缓存技术

    缓存的定义:缓存就是在内存中存储的数据备份,当数据没有发生本质变化的时候,我们避免数据的查询操作直接连接数据库,而是去    内容中读取数据,这样就大大降低了数据库的读写次数,而且从内存中读数据的速度 ...

  5. CentOS---zabbix使用sendEamil发送报警

    一.sendEmail简介 sendEmail是一个轻量级,命令行的SMTP邮件客户端.如果你需要使用命令行发送邮件,那么sendEmail是非常完美的选择:使用简单并且功能强大.这个被设计用在php ...

  6. Java学习前知识补充

    1  Java  面向对象的编程语言:为了实现人机交互需要语言的过渡(翻译)这时就需要Java虚拟机! 不同系统需要不同的虚拟机 2  学习语言第一件事 搭建环境(运行 Java需要的环境) 在甲骨文 ...

  7. 补发————DOM与BOM

    什么是Dom? DOM是w3c(万维网联盟)的标准. DOM定义了HTML与ML文档的标准: w3c文档对象模型(DOM)是中立于平台与语言的接口,他允许程序和脚本动态访问和更新文档的内容.结构和样式 ...

  8. prim最小生成树

    prim和DIjkstra相似,都使用了贪心策略,加一些限制条件. prim每次会找出尽量小的那个边,将其加入到树中,最终使得生成树长大. 树中有n-1个节点时或者剩下的所有边都是INF,算法结束. ...

  9. Windows 10 IoT Serials 10 – 如何使用OCR引擎进行文字识别

    1. 引言 OCR (Optical Character Recognition,光学字符识别)是指电子设备(例如扫描仪或数码相机)检查纸上打印的字符,通过检测暗.亮的模式确定其形状,然后用字符识别方 ...

  10. vue局部组件

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...