邮件自动化服务开发:定时拉取MongoDB数据提供给运营人员
2017-09-01 15:55
561 查看
邮件自动化服务开发:定时拉取MongoDB数据提供给运营人员
邮件自动化服务开发:定时拉取MongoDB数据提供给运营人员,一路踩着坑,用了三天时间
有很多是补充上一篇文章的内容。我觉得直接粘贴代码一下,然后在分析比较好。
那就一步一步来吧。总体加在一起代码量也还好,1000行以内,老规矩,从main方法进来:
package com.start;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import com.model.PropertyVO;
import com.model.ShowVO;
import com.mongodb.BasicDBList;
import com.mongodb.MongoClient;
import com.test.MailSender;
import com.start.DoThis2;
public class SendEmail {
public static void main(String[] args) {
System.out.println("-------1.获取配置文件,获取配置实体类------------");
//1.获取配置文件,获取配置实体类
String propertisPath = "/opt/mongo/program/main.properties";
//String
propertisPath = "F:\\1\\main.properties";
Map propertisPathmap = doProperties(propertisPath);
PropertyVO vo = getVo(propertisPathmap);
System.out.println("---------2.创建连接------------");
try {
System.out.println("---------3.获得时间autoDate------------");
//3.获得时间autoDate
String auto = autoDate(vo.getDateTime());
vo.setDateTime(auto);
System.out.println("---------4.得到葛远所要数据------------");
//4.得到葛远所要数据
List voList = getData(vo);
System.out.println("---------5.生成excel文件------------");
//5.生成excel文件
List workbookList=createlist(voList,vo);
try {
writeToXls(workbookList,vo);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("---------6.发送邮件给殷园园------------");
//6.发送邮件给葛远
sendEmail(vo,auto);
} catch (Exception e) {
e.printStackTrace();
String s = e.getMessage();
System.out.println(s);
}
}
/**
* 创建mongo客户端
* @param url
* @param port
* @return
*/
public static MongoClient getClient(PropertyVO vo) {
String mongo_url = vo.getMongoUrl();
Integer mongo_port = vo.getMongoPort();
MongoClient client = null;
try {
client = new MongoClient(mongo_url, mongo_port);
} catch (Exception e) {
}
return client;
}
/**
* 给入db配置,获取数据list
* @param db
* @param autoDate
* @return
*/
public static List getData(PropertyVO proVO) {
//查询1,拿到所有id
BasicDBList queryList = new BasicDBList();//BasicDBList对象,用于像标准sql的in( 元素1,元素2,元素3)
DoThis2 doThis2 = new DoThis2();
queryList = doThis2.start(proVO);
//查询2,拿到所有新增数
List voList = new ArrayList();// 放入vo的list
DoThis3 doThis3 = new DoThis3();
voList= doThis3.start(queryList,proVO);
/**
* 到了这里,我们for循环,处理里面数据,拼装成最后需要用的数据
* 这里代码很容易理解
*/
for (int i = 0; i < voList.size(); i++) {
ShowVO vo = (ShowVO) voList.get(i);
Long lowerNewAdd = vo.getLowerNewAdd();
Long upperNewAdd = vo.getUpperNewAdd();
if (lowerNewAdd == null) {
lowerNewAdd = (long) 0;
}
if (upperNewAdd == null) {
upperNewAdd = (long) 0;
}
Long total = lowerNewAdd + upperNewAdd;
if (total == 0) {
vo.setTotal(total);// 总数
vo.setLowerRate("--");// 低于的比率
vo.setUpperRate("--");// 高于的比率
} else {
double lowerRateLong = (double) lowerNewAdd / (double) total* 100;
double upperRateLong = (double) upperNewAdd / (double) total* 100;
String lower = String.valueOf(lowerRateLong).toString();
String upper = String.valueOf(upperRateLong).toString();
//解决报错:java.lang.StringIndexOutOfBoundsException: String index out of range:
5
if(lower.length()<5) {
lower+="00";
}
if(upper.length()<5) {
upper+="00";
}
String lowerRate = lower.substring(0, 5) + "%";
String upperRate = upper.substring(0, 5) + "%";
vo.setTotal(total);// 总数
vo.setLowerRate(lowerRate);// 低于的比率
vo.setUpperRate(upperRate);// 高于的比率
System.out.println(vo.getCh()+" "+lowerRate+" "+upperRate+"
"+total);
}
}
//测试打印
System.out.println(voList.size());
return voList;
}
/**
* 创建生成的excel的list
* @param voList
* @return
*/
public static List createlist(List voList,PropertyVO provo){
List resultList=new ArrayList();
List biaotou=new ArrayList();
biaotou.add("渠道");
biaotou.add(">="+provo.getVersionValue());
biaotou.add("<"+provo.getVersionValue());
biaotou.add("新增总数");
resultList.add(biaotou);
//for循环拿出传入list数据
for(int i=0;i<voList.size();i++) {
ShowVO vo = new ShowVO();
vo = (ShowVO) voList.get(i);
List neirong=new ArrayList();
neirong.add(vo.getCh());
neirong.add(vo.getUpperRate());
neirong.add(vo.getLowerRate());
neirong.add(vo.getTotal());
resultList.add(neirong);
}
return resultList;
}
/**
* 创建excel邮件,并且保存下来
* @param resultList
* @throws Exception
*/
public static void writeToXls(List resultList,PropertyVO propertyVO)throws Exception{
//创建一个EXCEL
Workbook wb = new HSSFWorkbook();
//创建一个SHEET
Sheet sheet1 = wb.createSheet("报表1");
if(resultList!=null){
for (int i = 0; i < resultList.size(); i++) {
//创建一行
Row row = sheet1.createRow(i);
List rowList=(List)resultList.get(i);
//从一行中一列一列装入
for (int j = 0; j < rowList.size(); j++) {
Cell cell = row.createCell(j);
//解决total为Long类型问题
String cellLiString=String.valueOf(rowList.get(j));
cell.setCellValue(cellLiString );
}
}
}
//保存excel文件
FileOutputStream fileOut = new FileOutputStream(propertyVO.getUrlPath()+"分版本-"+propertyVO.getDateTime()+".xls");
wb.write(fileOut);
fileOut.close();
}
/**
* 发送邮件代码段
*/
public static void sendEmail (PropertyVO propertyVO,String auto) {
String to = propertyVO.getEmailSend();;//发给自己,就是预览信息了
String cc = propertyVO.getEmailSender();
//String
subject=propertyVO.getEmailSubject();//标题
//String
body =propertyVO.getEmailBody();
String subject="外推渠道分版本数据:"+auto;//标题
String body ="附件为外推渠道分版本数据,请知悉。";
File[] adjuctPath = new File[1];
File file=new File(propertyVO.getUrlPath()+"分版本-"+propertyVO.getDateTime()+".xls");//将刚才生成pdf的url拿过来
adjuctPath[0]=file;
String hostName = propertyVO.getEmailHostName(); // 服务器
String userName = propertyVO.getEmailUserName();
String passWd = propertyVO.getEmailPassWd();
String mailFrom = propertyVO.getEmailMailFrom();
MailSender email = new MailSender();
try {
email.sendMail(to, cc, subject, body, adjuctPath, hostName, userName, passWd,
mailFrom);
}catch(Exception e) {
e.printStackTrace();
}
}
/**
* 自动获取昨天的数据,如果没有给nowDate的话,给的是auto
* @param nowDate
* @return
*/
public static String autoDate(String nowDate) {
if(nowDate!=null && !" ".equals(nowDate)) {
if(nowDate.equals("auto")) {
Date date = new Date(new Date().getTime()-24*60*60*1000);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String time = sdf.format(date);
return time;
}else {
//SimpleDateFormat
sdf = new SimpleDateFormat("yyyy-MM-dd");
//String
time = sdf.format(nowDate);
return nowDate;
}
}else {
Date date = new Date(new Date().getTime()-24*60*60*1000);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String time = sdf.format(date);
return time;
}
}
/**
* 给方法用来读取配置文件
* @param propertisUrl
* @return
*/
public static Map doProperties(String propertisUrl){
Properties prop = new Properties();
Map map= new HashMap();
try{
//读取属性文件a.properties
// InputStream in = new BufferedInputStream (new FileInputStream("F:\\python\\pachong.properties"));
InputStream in = new BufferedInputStream (new FileInputStream(propertisUrl));
prop.load(in); ///加载属性列表
Iterator<String> it=prop.stringPropertyNames().iterator();
while(it.hasNext()){
String key=it.next();
System.out.println(key+":"+prop.getProperty(key));
map.put(key, prop.getProperty(key));
}
in.close();
}
catch(Exception e){
System.out.println(e);
}
return map;
}
/**
* 从配置文件中,拿到配置实体类。
* @param propertisPathmap
* @return
*/
public static PropertyVO getVo(Map propertisPathmap) {
String mongo_url = (String) propertisPathmap.get("mongo_url");
//Integer
mongo_port = Integer.parseInt((String) propertisPathmap.get("mongo_port"));
String mongo_db = (String) propertisPathmap.get("mongo_db");
Integer version_value = Integer.parseInt((String) propertisPathmap.get("version_value"));
String date_time = (String) propertisPathmap.get("date_time");
String role_name = (String) propertisPathmap.get("role_name");
String url_path = (String) propertisPathmap.get("url_path");
String emailSend= (String) propertisPathmap.get("emial_send");
String emailSender= (String) propertisPathmap.get("email_sender");
String emailSubject= (String) propertisPathmap.get("email_subject");
String emailBody= (String) propertisPathmap.get("email_body");
String emailHostName= (String) propertisPathmap.get("email_hostName");
String emailUserName= (String) propertisPathmap.get("email_userName");
String emailPassWd= (String) propertisPathmap.get("email_passWd");
String emailMailFrom= (String) propertisPathmap.get("email_mailFrom");
PropertyVO vo = new PropertyVO();
vo.setMongoUrl(mongo_url);
//vo.setMongoPort(mongo_port);
vo.setMongoDb(mongo_db);
vo.setVersionValue(version_value);
vo.setDateTime(date_time);
vo.setRoleName(role_name);
vo.setUrlPath(url_path);
vo.setEmailSend(emailSend);
vo.setEmailSender(emailSender);
vo.setEmailSubject(emailSubject);
vo.setEmailBody(emailBody);
vo.setEmailHostName(emailHostName);
vo.setEmailUserName(emailUserName);
vo.setEmailPassWd(emailPassWd);
vo.setEmailMailFrom(emailMailFrom);
return vo;
}
}
好的,其实注释很清楚了,总共5步走。实现起来也有很多坑,比方说我们测试服务器的mongo版本3.2,正式服务器上面的就是2.5的,差了太多了,所以用的MongoClient在测试服务器上玩的high但是到了正式服务器上就是垃圾,一塌糊涂了。要用DBClient这个类了,好了,
使用配置文件,把配置文件给看一下吧。
把配置文件读成map
第二步,获取autoDate,把时间给,配置类的属性,这个理解吧
这是详细代码:
如果在配置文件里面写了某一天,就会去拉取某一天,如果写的是auto,则是默认就是做一天的。这个代码好理解吧,懂我意思吧。如果时间是空呢,就是昨天了。
第三个就是得到葛远所要数据了,我们把实体传入方法。
进入getData方法呢,首先上来就做了两步,
因为涉及到权限,所以,这里要我们要先用doThis2,来拿到所有的权限内的渠道,即,去渠道表里拿到b渠道组下的所有渠道。我们过去看看吧:
标红处,即是,建立mongo连接,继而依据条件查询,在继而遍历结果集,装入list中,返回出去,这个list里面装的都是type为016的渠道,016是b渠道组的意思,那么,我们就获得了所有要查询的渠道了。具体的mongo操作,详见cms工程下的代码样例。
好的,跳出来,跳出循环我们来看一下,doThis3,
可以看到,老规矩建立连接,继而使用dt条件,条件的String来自我们之前组装的PropertyVO的属性,由我们使用函数得到。可以注意此处使用了mongo语法,$in操作,其实类似的许多用法和函数都可以使用mongo的语法,当然这里我使用的是程序来做计算拼接。
好了,来看最后一个循环,因为这个循环比较复杂,涉及到许多算法逻辑,就直接粘贴代码了,说一下大概意义:
List voList = new ArrayList();// 放入vo的list
Map voMap = new HashMap();// 用于记录不同ch的map,其实就是使用map去重
// 遍历循环从结果集拼装数据
while (cur.hasNext()) {
DBObject doc = cur.next();
String ch = (String) doc.get("ch");// 渠道
Integer version = null;
try {//处理异常,如果是“ ”,会导致无法装箱
String pass = (String) doc.get("m_cd");
if (pass == null || " ".equals(pass)) {
continue;
} else {
version = Integer.parseInt(pass);// 版本
}
} catch (Exception e) {
String s = e.getMessage();
e.printStackTrace();
System.out.println(s);
}
Long newAdd = (Long) doc.get("cnt_n");// 新增数
/**
* 该方法用于处理,将所有数据归类,如果第一次进来,则我们添加该map,key为ch,value为showVo实体类
*/
if (voMap.containsKey(ch)) {// 如果渠道已经在里面了
ShowVO vo = (ShowVO) voMap.get(ch);
if (version >= proVo.getVersionValue()) {// 如果大于143,将新增数累加
Long countUpper = vo.getUpperNewAdd();
if(countUpper == null) {//解决报错空指针的问题
countUpper = (long) 0;
}
Long count = countUpper + newAdd;
vo.setUpperNewAdd(count);
} else {// 如果小于143,将新增数累加
Long countUpper =vo.getLowerNewAdd() ;
if(countUpper == null) {//解决报错空指针的问题
countUpper = (long) 0;
}
Long count =countUpper + newAdd;
vo.setLowerNewAdd(count);
}
} else {// 如果这条记录不再这个map里面
ShowVO vo = new ShowVO();
if (version >= proVo.getVersionValue()) {// 如果大于143,将新增数设置
vo.setUpperNewAdd(newAdd);
vo.setCh(ch);
voMap.put(ch, vo);
} else {// 如果小于143,将新增数设置
vo.setLowerNewAdd(newAdd);
vo.setCh(ch);
voMap.put(ch, vo);
}
}
}
逻辑就是,我们已经用条件查到了表user_channel_val_v数据集,然后把数据机里面的渠道,版本号,新增数拿到,当然做了为空处理,因为写的时候发现有的m_cd版本字段为空字符串,会报错无法被装箱成Integer。
接着,处理,将所有数据归类,如果第一次进来,则我们添加该map,key为ch,value为showVo实体类
渠道没有的话,就创建map,key为ch,value为ShowVO,这个vo稍后带看一下,别着急。这个算法里面做了,没有渠道创建,如果有这个渠道,区分是否大于143(需求需要,后期可能版本号需要改),如果有,那我们就进入key为ch的map,修改value里面的vo属性,这个方法我觉得比较精妙,想了很多方式,还是这个方式,使用对象最为优良。
来看一下ShowVO,只粘贴一部分哈
然后我们来看doThis3最后的一个环节,将我们计算好的map里面所有values拿到,这个时候已经不需要map 的key了(当初使用map是为了聚合,hashMap的特性,key为唯一,可以hash到value,用来去重很不错),这里我们将所有的vo对象装入一个list里面返回出去了。
好了,这里看完了doThis3的操作,继续回到主的函数main里面引用的getData,还记得把。
注意看,这里已经不是聚合了,这里是采用我们for循环,处理里面数据,拼装成最后需要用的数据 这里代码很容易理解,从list里面拿到刚才我们所有的唯一的vo对象,然后for循环,做了什么操作呢,在里面我们要算大于143或者小于143的比重,这个是需求的,还要累加。源数据里面只有各个版本的对应的新增数。我打比方说吧,渠道:a001 版本:123 新增数:12, 渠道:a002 版本:156 新增数:124, 渠道:a001 版本:123
新增数:67,
那么我们就是做聚合,前面那篇文章带大家看过数据了,以前呢,需要运营人员手动的来找,然后手动算,现在由我们这边出了,我用程序算好,自动生成excel发送邮件。造福公司和人类,解放劳动力。
好了扯远了,继续来看,这里有几个坑,都被我已经在注释里面声明了,手下你是0,不能做枫木,所以,我们处理total为0,直接规避这个问题
再者,如果是0.0,将不能被切割subString方法(0,5),故而呢,在这里我们帮他加00,变成0.000,所以,这么写。
到此,getData函数全部分析完毕,然后返回
好了,大功告成,数据也拿到了,现在就是要生成excel文件了,
这里有两个方法,createlist(voList,vo);
writeToXls(workbookList,vo);
我们进去看看, createlist 方法,提供
这个没毛病吧,拼接生成最后excel的方法,再进 writeToXls方法看一看
这里创建行列,然后两层for循环,干出来行列之后,注意这里要解决解决total为Long类型问题,请注意使用String.valueOf(rowList.get(j));再然后,因为对文件操作并没有特殊要求,也不要求备份(因为大不了该配置重跑),所以这里,我们直接从vo属性拿到然后创建文件。
然后到了第五步,修成正果的一步了:
来看一下最后一步的方法。sendEmail(vo,auto);
没什么好说的吧,这个使用了emai发送类的api,点进去看一下
email.sendMail(to, cc, subject, body, adjuctPath, hostName, userName, passWd, mailFrom);
上面这个api发送邮件呢,创建smtp服务,其实也有坑的,当然了,网上也有,但是大部分是不能用的,要么就是邮件服务一定记得开,还有,不要用qq的,新浪的容易出现报错。这里也就不详细说明了。
当然整个开发过程还是有特别多的坑的,那么,总的来说,现在是把坑克服了,比方说,后面重构了,代码,因为mongoClient对老版本没用,换了个api重新写了代码,再有就是上线之后乱码问题啥的,还有么就是堡垒机恶心到我了之类的。
最后说一下上线。
打jar到服务器上,然后,配置文件也放过来,写到crontab里面
crontab会在设置后的两分钟执行,记住了。还有如果出现jar不执行应该是profile,记得source一下,几乎所有的问题最终来自于环境变量,这个我们之前说过。在就是,记得加这个,不然会出现乱码,最后出一下结果邮件:
运营那边已经使用了,但是他忘了谢谢我,哼,很生气。
欧了,完工。继续干活了。
邮件自动化服务开发:定时拉取MongoDB数据提供给运营人员,一路踩着坑,用了三天时间
有很多是补充上一篇文章的内容。我觉得直接粘贴代码一下,然后在分析比较好。
那就一步一步来吧。总体加在一起代码量也还好,1000行以内,老规矩,从main方法进来:
package com.start;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import com.model.PropertyVO;
import com.model.ShowVO;
import com.mongodb.BasicDBList;
import com.mongodb.MongoClient;
import com.test.MailSender;
import com.start.DoThis2;
public class SendEmail {
public static void main(String[] args) {
System.out.println("-------1.获取配置文件,获取配置实体类------------");
//1.获取配置文件,获取配置实体类
String propertisPath = "/opt/mongo/program/main.properties";
//String
propertisPath = "F:\\1\\main.properties";
Map propertisPathmap = doProperties(propertisPath);
PropertyVO vo = getVo(propertisPathmap);
System.out.println("---------2.创建连接------------");
try {
System.out.println("---------3.获得时间autoDate------------");
//3.获得时间autoDate
String auto = autoDate(vo.getDateTime());
vo.setDateTime(auto);
System.out.println("---------4.得到葛远所要数据------------");
//4.得到葛远所要数据
List voList = getData(vo);
System.out.println("---------5.生成excel文件------------");
//5.生成excel文件
List workbookList=createlist(voList,vo);
try {
writeToXls(workbookList,vo);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("---------6.发送邮件给殷园园------------");
//6.发送邮件给葛远
sendEmail(vo,auto);
} catch (Exception e) {
e.printStackTrace();
String s = e.getMessage();
System.out.println(s);
}
}
/**
* 创建mongo客户端
* @param url
* @param port
* @return
*/
public static MongoClient getClient(PropertyVO vo) {
String mongo_url = vo.getMongoUrl();
Integer mongo_port = vo.getMongoPort();
MongoClient client = null;
try {
client = new MongoClient(mongo_url, mongo_port);
} catch (Exception e) {
}
return client;
}
/**
* 给入db配置,获取数据list
* @param db
* @param autoDate
* @return
*/
public static List getData(PropertyVO proVO) {
//查询1,拿到所有id
BasicDBList queryList = new BasicDBList();//BasicDBList对象,用于像标准sql的in( 元素1,元素2,元素3)
DoThis2 doThis2 = new DoThis2();
queryList = doThis2.start(proVO);
//查询2,拿到所有新增数
List voList = new ArrayList();// 放入vo的list
DoThis3 doThis3 = new DoThis3();
voList= doThis3.start(queryList,proVO);
/**
* 到了这里,我们for循环,处理里面数据,拼装成最后需要用的数据
* 这里代码很容易理解
*/
for (int i = 0; i < voList.size(); i++) {
ShowVO vo = (ShowVO) voList.get(i);
Long lowerNewAdd = vo.getLowerNewAdd();
Long upperNewAdd = vo.getUpperNewAdd();
if (lowerNewAdd == null) {
lowerNewAdd = (long) 0;
}
if (upperNewAdd == null) {
upperNewAdd = (long) 0;
}
Long total = lowerNewAdd + upperNewAdd;
if (total == 0) {
vo.setTotal(total);// 总数
vo.setLowerRate("--");// 低于的比率
vo.setUpperRate("--");// 高于的比率
} else {
double lowerRateLong = (double) lowerNewAdd / (double) total* 100;
double upperRateLong = (double) upperNewAdd / (double) total* 100;
String lower = String.valueOf(lowerRateLong).toString();
String upper = String.valueOf(upperRateLong).toString();
//解决报错:java.lang.StringIndexOutOfBoundsException: String index out of range:
5
if(lower.length()<5) {
lower+="00";
}
if(upper.length()<5) {
upper+="00";
}
String lowerRate = lower.substring(0, 5) + "%";
String upperRate = upper.substring(0, 5) + "%";
vo.setTotal(total);// 总数
vo.setLowerRate(lowerRate);// 低于的比率
vo.setUpperRate(upperRate);// 高于的比率
System.out.println(vo.getCh()+" "+lowerRate+" "+upperRate+"
"+total);
}
}
//测试打印
System.out.println(voList.size());
return voList;
}
/**
* 创建生成的excel的list
* @param voList
* @return
*/
public static List createlist(List voList,PropertyVO provo){
List resultList=new ArrayList();
List biaotou=new ArrayList();
biaotou.add("渠道");
biaotou.add(">="+provo.getVersionValue());
biaotou.add("<"+provo.getVersionValue());
biaotou.add("新增总数");
resultList.add(biaotou);
//for循环拿出传入list数据
for(int i=0;i<voList.size();i++) {
ShowVO vo = new ShowVO();
vo = (ShowVO) voList.get(i);
List neirong=new ArrayList();
neirong.add(vo.getCh());
neirong.add(vo.getUpperRate());
neirong.add(vo.getLowerRate());
neirong.add(vo.getTotal());
resultList.add(neirong);
}
return resultList;
}
/**
* 创建excel邮件,并且保存下来
* @param resultList
* @throws Exception
*/
public static void writeToXls(List resultList,PropertyVO propertyVO)throws Exception{
//创建一个EXCEL
Workbook wb = new HSSFWorkbook();
//创建一个SHEET
Sheet sheet1 = wb.createSheet("报表1");
if(resultList!=null){
for (int i = 0; i < resultList.size(); i++) {
//创建一行
Row row = sheet1.createRow(i);
List rowList=(List)resultList.get(i);
//从一行中一列一列装入
for (int j = 0; j < rowList.size(); j++) {
Cell cell = row.createCell(j);
//解决total为Long类型问题
String cellLiString=String.valueOf(rowList.get(j));
cell.setCellValue(cellLiString );
}
}
}
//保存excel文件
FileOutputStream fileOut = new FileOutputStream(propertyVO.getUrlPath()+"分版本-"+propertyVO.getDateTime()+".xls");
wb.write(fileOut);
fileOut.close();
}
/**
* 发送邮件代码段
*/
public static void sendEmail (PropertyVO propertyVO,String auto) {
String to = propertyVO.getEmailSend();;//发给自己,就是预览信息了
String cc = propertyVO.getEmailSender();
//String
subject=propertyVO.getEmailSubject();//标题
//String
body =propertyVO.getEmailBody();
String subject="外推渠道分版本数据:"+auto;//标题
String body ="附件为外推渠道分版本数据,请知悉。";
File[] adjuctPath = new File[1];
File file=new File(propertyVO.getUrlPath()+"分版本-"+propertyVO.getDateTime()+".xls");//将刚才生成pdf的url拿过来
adjuctPath[0]=file;
String hostName = propertyVO.getEmailHostName(); // 服务器
String userName = propertyVO.getEmailUserName();
String passWd = propertyVO.getEmailPassWd();
String mailFrom = propertyVO.getEmailMailFrom();
MailSender email = new MailSender();
try {
email.sendMail(to, cc, subject, body, adjuctPath, hostName, userName, passWd,
mailFrom);
}catch(Exception e) {
e.printStackTrace();
}
}
/**
* 自动获取昨天的数据,如果没有给nowDate的话,给的是auto
* @param nowDate
* @return
*/
public static String autoDate(String nowDate) {
if(nowDate!=null && !" ".equals(nowDate)) {
if(nowDate.equals("auto")) {
Date date = new Date(new Date().getTime()-24*60*60*1000);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String time = sdf.format(date);
return time;
}else {
//SimpleDateFormat
sdf = new SimpleDateFormat("yyyy-MM-dd");
//String
time = sdf.format(nowDate);
return nowDate;
}
}else {
Date date = new Date(new Date().getTime()-24*60*60*1000);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String time = sdf.format(date);
return time;
}
}
/**
* 给方法用来读取配置文件
* @param propertisUrl
* @return
*/
public static Map doProperties(String propertisUrl){
Properties prop = new Properties();
Map map= new HashMap();
try{
//读取属性文件a.properties
// InputStream in = new BufferedInputStream (new FileInputStream("F:\\python\\pachong.properties"));
InputStream in = new BufferedInputStream (new FileInputStream(propertisUrl));
prop.load(in); ///加载属性列表
Iterator<String> it=prop.stringPropertyNames().iterator();
while(it.hasNext()){
String key=it.next();
System.out.println(key+":"+prop.getProperty(key));
map.put(key, prop.getProperty(key));
}
in.close();
}
catch(Exception e){
System.out.println(e);
}
return map;
}
/**
* 从配置文件中,拿到配置实体类。
* @param propertisPathmap
* @return
*/
public static PropertyVO getVo(Map propertisPathmap) {
String mongo_url = (String) propertisPathmap.get("mongo_url");
//Integer
mongo_port = Integer.parseInt((String) propertisPathmap.get("mongo_port"));
String mongo_db = (String) propertisPathmap.get("mongo_db");
Integer version_value = Integer.parseInt((String) propertisPathmap.get("version_value"));
String date_time = (String) propertisPathmap.get("date_time");
String role_name = (String) propertisPathmap.get("role_name");
String url_path = (String) propertisPathmap.get("url_path");
String emailSend= (String) propertisPathmap.get("emial_send");
String emailSender= (String) propertisPathmap.get("email_sender");
String emailSubject= (String) propertisPathmap.get("email_subject");
String emailBody= (String) propertisPathmap.get("email_body");
String emailHostName= (String) propertisPathmap.get("email_hostName");
String emailUserName= (String) propertisPathmap.get("email_userName");
String emailPassWd= (String) propertisPathmap.get("email_passWd");
String emailMailFrom= (String) propertisPathmap.get("email_mailFrom");
PropertyVO vo = new PropertyVO();
vo.setMongoUrl(mongo_url);
//vo.setMongoPort(mongo_port);
vo.setMongoDb(mongo_db);
vo.setVersionValue(version_value);
vo.setDateTime(date_time);
vo.setRoleName(role_name);
vo.setUrlPath(url_path);
vo.setEmailSend(emailSend);
vo.setEmailSender(emailSender);
vo.setEmailSubject(emailSubject);
vo.setEmailBody(emailBody);
vo.setEmailHostName(emailHostName);
vo.setEmailUserName(emailUserName);
vo.setEmailPassWd(emailPassWd);
vo.setEmailMailFrom(emailMailFrom);
return vo;
}
}
好的,其实注释很清楚了,总共5步走。实现起来也有很多坑,比方说我们测试服务器的mongo版本3.2,正式服务器上面的就是2.5的,差了太多了,所以用的MongoClient在测试服务器上玩的high但是到了正式服务器上就是垃圾,一塌糊涂了。要用DBClient这个类了,好了,
使用配置文件,把配置文件给看一下吧。
把配置文件读成map
第二步,获取autoDate,把时间给,配置类的属性,这个理解吧
这是详细代码:
如果在配置文件里面写了某一天,就会去拉取某一天,如果写的是auto,则是默认就是做一天的。这个代码好理解吧,懂我意思吧。如果时间是空呢,就是昨天了。
第三个就是得到葛远所要数据了,我们把实体传入方法。
进入getData方法呢,首先上来就做了两步,
因为涉及到权限,所以,这里要我们要先用doThis2,来拿到所有的权限内的渠道,即,去渠道表里拿到b渠道组下的所有渠道。我们过去看看吧:
标红处,即是,建立mongo连接,继而依据条件查询,在继而遍历结果集,装入list中,返回出去,这个list里面装的都是type为016的渠道,016是b渠道组的意思,那么,我们就获得了所有要查询的渠道了。具体的mongo操作,详见cms工程下的代码样例。
好的,跳出来,跳出循环我们来看一下,doThis3,
可以看到,老规矩建立连接,继而使用dt条件,条件的String来自我们之前组装的PropertyVO的属性,由我们使用函数得到。可以注意此处使用了mongo语法,$in操作,其实类似的许多用法和函数都可以使用mongo的语法,当然这里我使用的是程序来做计算拼接。
好了,来看最后一个循环,因为这个循环比较复杂,涉及到许多算法逻辑,就直接粘贴代码了,说一下大概意义:
List voList = new ArrayList();// 放入vo的list
Map voMap = new HashMap();// 用于记录不同ch的map,其实就是使用map去重
// 遍历循环从结果集拼装数据
while (cur.hasNext()) {
DBObject doc = cur.next();
String ch = (String) doc.get("ch");// 渠道
Integer version = null;
try {//处理异常,如果是“ ”,会导致无法装箱
String pass = (String) doc.get("m_cd");
if (pass == null || " ".equals(pass)) {
continue;
} else {
version = Integer.parseInt(pass);// 版本
}
} catch (Exception e) {
String s = e.getMessage();
e.printStackTrace();
System.out.println(s);
}
Long newAdd = (Long) doc.get("cnt_n");// 新增数
/**
* 该方法用于处理,将所有数据归类,如果第一次进来,则我们添加该map,key为ch,value为showVo实体类
*/
if (voMap.containsKey(ch)) {// 如果渠道已经在里面了
ShowVO vo = (ShowVO) voMap.get(ch);
if (version >= proVo.getVersionValue()) {// 如果大于143,将新增数累加
Long countUpper = vo.getUpperNewAdd();
if(countUpper == null) {//解决报错空指针的问题
countUpper = (long) 0;
}
Long count = countUpper + newAdd;
vo.setUpperNewAdd(count);
} else {// 如果小于143,将新增数累加
Long countUpper =vo.getLowerNewAdd() ;
if(countUpper == null) {//解决报错空指针的问题
countUpper = (long) 0;
}
Long count =countUpper + newAdd;
vo.setLowerNewAdd(count);
}
} else {// 如果这条记录不再这个map里面
ShowVO vo = new ShowVO();
if (version >= proVo.getVersionValue()) {// 如果大于143,将新增数设置
vo.setUpperNewAdd(newAdd);
vo.setCh(ch);
voMap.put(ch, vo);
} else {// 如果小于143,将新增数设置
vo.setLowerNewAdd(newAdd);
vo.setCh(ch);
voMap.put(ch, vo);
}
}
}
逻辑就是,我们已经用条件查到了表user_channel_val_v数据集,然后把数据机里面的渠道,版本号,新增数拿到,当然做了为空处理,因为写的时候发现有的m_cd版本字段为空字符串,会报错无法被装箱成Integer。
接着,处理,将所有数据归类,如果第一次进来,则我们添加该map,key为ch,value为showVo实体类
渠道没有的话,就创建map,key为ch,value为ShowVO,这个vo稍后带看一下,别着急。这个算法里面做了,没有渠道创建,如果有这个渠道,区分是否大于143(需求需要,后期可能版本号需要改),如果有,那我们就进入key为ch的map,修改value里面的vo属性,这个方法我觉得比较精妙,想了很多方式,还是这个方式,使用对象最为优良。
来看一下ShowVO,只粘贴一部分哈
然后我们来看doThis3最后的一个环节,将我们计算好的map里面所有values拿到,这个时候已经不需要map 的key了(当初使用map是为了聚合,hashMap的特性,key为唯一,可以hash到value,用来去重很不错),这里我们将所有的vo对象装入一个list里面返回出去了。
好了,这里看完了doThis3的操作,继续回到主的函数main里面引用的getData,还记得把。
注意看,这里已经不是聚合了,这里是采用我们for循环,处理里面数据,拼装成最后需要用的数据 这里代码很容易理解,从list里面拿到刚才我们所有的唯一的vo对象,然后for循环,做了什么操作呢,在里面我们要算大于143或者小于143的比重,这个是需求的,还要累加。源数据里面只有各个版本的对应的新增数。我打比方说吧,渠道:a001 版本:123 新增数:12, 渠道:a002 版本:156 新增数:124, 渠道:a001 版本:123
新增数:67,
那么我们就是做聚合,前面那篇文章带大家看过数据了,以前呢,需要运营人员手动的来找,然后手动算,现在由我们这边出了,我用程序算好,自动生成excel发送邮件。造福公司和人类,解放劳动力。
好了扯远了,继续来看,这里有几个坑,都被我已经在注释里面声明了,手下你是0,不能做枫木,所以,我们处理total为0,直接规避这个问题
再者,如果是0.0,将不能被切割subString方法(0,5),故而呢,在这里我们帮他加00,变成0.000,所以,这么写。
到此,getData函数全部分析完毕,然后返回
好了,大功告成,数据也拿到了,现在就是要生成excel文件了,
这里有两个方法,createlist(voList,vo);
writeToXls(workbookList,vo);
我们进去看看, createlist 方法,提供
这个没毛病吧,拼接生成最后excel的方法,再进 writeToXls方法看一看
这里创建行列,然后两层for循环,干出来行列之后,注意这里要解决解决total为Long类型问题,请注意使用String.valueOf(rowList.get(j));再然后,因为对文件操作并没有特殊要求,也不要求备份(因为大不了该配置重跑),所以这里,我们直接从vo属性拿到然后创建文件。
然后到了第五步,修成正果的一步了:
来看一下最后一步的方法。sendEmail(vo,auto);
没什么好说的吧,这个使用了emai发送类的api,点进去看一下
email.sendMail(to, cc, subject, body, adjuctPath, hostName, userName, passWd, mailFrom);
上面这个api发送邮件呢,创建smtp服务,其实也有坑的,当然了,网上也有,但是大部分是不能用的,要么就是邮件服务一定记得开,还有,不要用qq的,新浪的容易出现报错。这里也就不详细说明了。
当然整个开发过程还是有特别多的坑的,那么,总的来说,现在是把坑克服了,比方说,后面重构了,代码,因为mongoClient对老版本没用,换了个api重新写了代码,再有就是上线之后乱码问题啥的,还有么就是堡垒机恶心到我了之类的。
最后说一下上线。
打jar到服务器上,然后,配置文件也放过来,写到crontab里面
crontab会在设置后的两分钟执行,记住了。还有如果出现jar不执行应该是profile,记得source一下,几乎所有的问题最终来自于环境变量,这个我们之前说过。在就是,记得加这个,不然会出现乱码,最后出一下结果邮件:
运营那边已经使用了,但是他忘了谢谢我,哼,很生气。
欧了,完工。继续干活了。
相关文章推荐
- Cordys BOP 4平台开发实战——MongoDB提供文档服务(1)
- Java开发MongoClient邮件服务自动化
- JBoss4 应用服务器Web开发人员参考手册(8):提供静态内容服务
- SafeNet为BancNet ATM外包运营提供关键的数据保护和交易安全服务
- 谷歌为Android应用开发人员提供翻译服务
- SafeNet为BancNet ATM外包运营提供关键的数据保护和交易安全服务
- 谷歌为Android应用开发人员提供翻译服务
- Dynamic CRM 2015学习笔记(4)修改开发人员资源(发现服务、组织服务和组织数据服务)url地址及组织名
- 收到封提供K站服务邮件
- Windows Mobile 6 中为开发人员提供的新功能
- git 远程版本库,github提供服务原理,git自动更新发送邮件
- 提供给Android和iOS开发人员的UWP移植向导
- 《BREW进阶与精通——3G移动增值业务的运营、定制与开发》连载之31---LBS基于BREW的位置服务
- Android开发之数据存储之二:SQLite数据库存储方式【免费提供源码下载】
- 实现定时发送邮件功能 数据是从数据库中获取到的
- CSDN.NET - 中国最大的IT技术社区,为IT专业技术人员提供最全面的信息传播和服务平台
- delphi mysql adbquery数据提供程序或其他服务返回 E_FAIL 状态
- 免费超大量邮件发送服务Amazon SES和Mailgun提供SMTP和API支持
- 开发定时服务应用
- 提供一遍好文章(【前端福利】用grunt搭建自动化的web前端开发环境-完整教程)