##1,业务场景:
有A,B,C三个服务器,
A 服务器是实时生成日志的,
需求:A服务器的数据传输到C服务器
前提:程序无法部署在A,C服务器上,只能在B服务器上执行
##2,业务开发技术:
scala+spingboot+jpa+redis+mysql+docker
##3,sql
create database skyworth DEFAULT CHARACTER SET 'utf8’;
create table dateinterval(
id int(11) NOT NULL primary key AUTO_INCREMENT ,
name varchar(200),
start_date
datetime NOT NULL,
end_date
datetime NOT NULL,
CREATETIME TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
create table ftpkey(
id int(11) NOT NULL primary key AUTO_INCREMENT ,
d_id int(11),
host varchar(200),
port varchar(200),
username varchar(200),
password varchar(200),
remotePath varchar(200),
CREATETIME TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
4,贴代码
核心代码,在这里,能看懂就看下,看不懂微信我:yyy_yjr
package com.forcetv.ads.service
import java.io.{IOException, _}
import java.text.SimpleDateFormat
import java.util.Date
import java.util.regex.{Matcher, Pattern}
import com.forcetv.ads.cache.{FtpCache, FtpkeyCache}
import com.forcetv.ads.entity.{FtpEntity, FtpKeyEntity}
import com.forcetv.ads.redis.FtpRedis
import javax.annotation.Resource
import org.apache.commons.net.ftp.{FTPClient, FTPFile, FTPReply}
import org.springframework.scheduling.annotation.Async
import org.springframework.stereotype.Component
import scala.beans.BeanProperty
import scala.tools.scalap.scalax.util.StringUtil
/**
- @Author : yang
- @Date : 2019/1/24 11:58 PM
- @Version : 1.2.1
/
@Component
class upanddown {
@Resource
@BeanProperty
var ftpredis:FtpRedis=_
/* - @Description: 从服务器上下载 日志并处理都是在这里 ,time1是为了筛选文件名用的,time2是为了筛选日志里每个时段用的,广告位2 position1 ,广告位2 position2
- @Param: [id, date, name, position1,position2]
- @return: void
- @Author: yang
- @Date: 2019/1/25 12:03 AM
*/
@Resource
@BeanProperty
var ftpcache:FtpCache=_
@Resource
@BeanProperty
var ftpkeycache:FtpkeyCache=_
// val pathname="/Users/yang/Desktop/ftp"
val pathname="/etc/yang"
import java.io.File
def downloadFile (host: String, port: Int, username: String, password: String, remotePath: String): Unit ={
println(“下载”)
val file = new File(pathname)
if(!file.exists()){
file.mkdirs()
}
var result = false
val ftp = new FTPClient
try {
var reply = 0
ftp.connect( host, port.toString.toInt )
// 如果采用默认端口,可以使用ftp.connect(host)的方式直接连接FTP服务器
ftp.login( username, password ) // 登录
reply = ftp.getReplyCode
System.out.println( "reply:" + reply )
if (!FTPReply.isPositiveCompletion( reply )) {
ftp.disconnect()
return result
}
ftp.changeWorkingDirectory( remotePath ) // 转移到FTP服务器目录
ftp.enterLocalPassiveMode()
val fs:Array[FTPFile] = ftp.listFiles
//1,1时间正则生成 找到4分钟前的时间,给ftp文件时间差
val now = new Date()
val date = new Date(now.getTime-240000)
println("当前时间:"+date)
// val date = new Date()
val simpleDateFormat1 = new SimpleDateFormat( “yyyyMMddHH” )
//给下一层传参用的
val simpleDateFormat2 = new SimpleDateFormat( “HH” )
val time2 = simpleDateFormat2.format( date )
val regEx = simpleDateFormat1.format( date )
// 编译正则表达式
val pattern = Pattern.compile( regEx )
for (ff <- fs) {
//1.2正则
val matcher: Matcher = pattern.matcher( ff.getName )
val boolean = matcher.find
/**
* 判断要不要读这个目录,若返回ture需要,false不需要
* 2,在这个 文件夹中出需要调用数据流处理,处理完要返给另外一个ftp服务器
* 3,redis
*/
var name = ftpredis.if_parameter(ff.getName)
// var name=true
if(name&&boolean){
//存储到本地
val localFile = new File(pathname+"/"+ff.getName())
val is = new FileOutputStream(localFile)
ftp.retrieveFile(ff.getName(), is)
is.close();
//读取文本,传输到目标服务器
//包含文件地址+名, 不需要在这一层完成,要在下一层处理广告位1,广告位2,媒体,目标地址,不直接获取内存地址就好
//所以就传一个文件名就好了
file_text(ff.getName,time2,date)
//删除文件
if(localFile.exists()){
localFile.delete()
}
}
}
ftp.logout
result = true
} catch {
case e: IOException =>
e.printStackTrace()
} finally {
if (ftp.isConnected){
try{
ftp.disconnect()
}
catch {
case ioe: IOException =>println(“120,ioe:”+ioe)
}}}
return result
}
/**
* @Description: 把处理好的日志上传到指定服务器
* @Param: []
* @return: void
* @Author: yang
* @Date: 2019/1/25 12:01 AM
*/
val ftp1 = new FTPClient
import org.apache.commons.net.ftp.FTP
import util.control.Breaks._
def uploadFile(id:String,filePath:String,filename:String,input: InputStream): Unit ={
//host
println(“上传”)
val fk:FtpKeyEntity = ftpkeycache.get(id)
val host = fk.getHost
val port = fk.getPort.toInt
val username = fk.getUsername
val password = fk.getPassword
val basePath = fk.getRemotepath
var result = false
try {
var reply = 0
ftp1.connect( host, port ) // 连接FTP服务器
// 如果采用默认端口,可以使用ftp.connect(host)的方式直接连接FTP服务器
ftp1.login( username, password ) // 登录
ftp1.enterLocalPassiveMode()
reply = ftp1.getReplyCode
if (!FTPReply.isPositiveCompletion( reply )) {
ftp1.disconnect()
return result
}
//切换到上传目录
if (!ftp1.changeWorkingDirectory( basePath + filePath )) { //如果目录不存在创建目录
val dirs = filePath.split( “/” )
var tempPath = basePath
for (dir <- dirs) {
if (null == dir || “” == dir) {
break
}
tempPath += “/” + dir
if (!ftp1.changeWorkingDirectory( tempPath )) if (!ftp1.makeDirectory( tempPath )) return result
else ftp1.changeWorkingDirectory( tempPath )
}
}
//设置上传文件的类型为二进制类型
ftp1.setFileType( FTP.BINARY_FILE_TYPE )
//上传文件//appendFile//storeFile
ftp1.storeFile(filename, input)
// if (!ftp1.storeFile( filename, input )) return result
input.close()
// ftp.logout
result = true
}
catch {
case e: IOException =>
e.printStackTrace()
}
finally {
if (ftp1.isConnected) try
ftp1.disconnect()
catch {
case e: IOException =>println(e)
}
}
closeConnections(ftp1)
return result
}
//文本处理,把拿到的日志筛选/加工,就是在这里 参考日志清算代码
//文件要放在这里执行
//参数1,文件,2,时间,3,广告位1,广告位2 ,4,订单人:创维
//,position1:String,position2:String, name:String
//所有的参数在缓存中,可直接获取
import scala.collection.JavaConversions._
def file_text(filename:String,time:String,date:Date): Unit ={
//广告位1
val cache:java.util.Map[String, FtpEntity] = ftpcache.getCache
for(ca<-cache){
//判断时间过期
if( date.before( ca._2.getEnd_date)&& date.after( ca._2.getStart_date)){
text(ca._2.getPosition1, ca._2.getPosition2,filename, ca._2.getName,time, ca._2.getId.toString)
}
}
}
//文件处理及过滤
def text(position1:String,position2:String, filename:String,name:String,time:String,id:String): Unit ={
val f = new File(pathname+"/"+filename)
var s = “”
var br:BufferedReader=null
try {
System.out.println( "按照行读取文件内容" )
br = new BufferedReader(new FileReader(f))
var temp = ""
while((temp=br.readLine())!=null){
s = temp
//处理文件
//etv_hd_booting_2.jpg,21/Jan/2019:13:25:15,75983814@etv1,22.105.154.252,null,null
println("238:"+s)
var position= s.split( "," ).toList( 0 )
//正则判断 参数不为空
var boolean1=false
var boolean2=false
if(null!=position1){
boolean1=patterns(position1,position)
}
if(null!=position2){
boolean2=patterns(position2,position)
}
var boolean_time=false
if(boolean1){
boolean_time=s.split(",").toList(1).split(":").toList(1).equals(time)
}
if(boolean2){
boolean_time=s.split(",").toList(1).split(":").toList(1).equals(time)
}
if(boolean_time){
s+=(","+name)
var ss=s+"\r\n"
//在这里保存文件到本地
files(pathname+"/"+name+"_"+filename,ss)
// val input: InputStream = new ByteArrayInputStream( ss.getBytes() )
//执行目标ftp
// uploadFile( id,"/",filename,input)
}
}
}
catch {
case e: Exception => e.printStackTrace()
} finally{
println(“处理文件”)
// 发送文件到远程ftp服务器
val f1 = new File(pathname+"/"+name+"_"+filename)
try {
val stream = new FileInputStream( f1 )
uploadFile( id, “/”, filename, stream )
} catch {
case e =>println(e)
}
//删除文件
if(f1.exists()){
f1.delete()
}
try {
br.close()
} catch {
case e:IOException =>println(e)
}
}
}
//提取正则
def patterns(param1:String,param2:String): Boolean ={
var boolean=false
val pattern = Pattern.compile( param1 )
val matcher: Matcher = pattern.matcher( param2 )
boolean = matcher.find
boolean
}
def closeConnections(ftpc:FTPClient):Boolean ={
var bool = false
try {
bool = ftpc.logout()
} catch {
case e =>println(e)
}
return bool
}
//文件处理完返回地址及名字
def files(fileName:String,content:String): Unit ={
println(“处理文件”)
val writer = new FileWriter(fileName, true)
writer.write(content)
writer.flush()
writer.close()
}
}
##5,全部代码已经打成压缩包,可下载附件
##6,部分讲解
###程序自动执行,每3分钟获取一次mysql配置信息;因为服务器C可随业务变动
###设计到技术有,spring定时器和Java内存变量的管理注解:@PostConstruct和@PreConstruct注解
详情看代码:
原创开发,请勿抄袭,为保护原创开发的辛苦,严禁翻版,有问题可以微信我,谢谢支持,附件代码下载链接