最近一直在忙于三月份的活动:“桃花朵朵开 求爱上上签”
活动需求:
活动期间,所有*用户可以通过抽签的形式获得**对您春天的祝福。抽签盒中的奖品包括加息券0.5%、加息券0.2%、50元现金红包、10元现金红包、2元现金红包、50积分、10积分
活动一:摇一摇,摇出富贵签
活动期间,用户登录**账户,即可免费享受每日一次抽签机会,中奖概率百分百!
活动二:转一转,赚取友爱签
活动期间,老用户登录**账户,将活动链接分享给新用户,新用户通过该链接注册账户并完成实名认证后,老用户即可增加一次抽签机会,多分享多得!
活动三:投一投,多赢机会签
活动期间,单日每累积投资10000元,即可获得一次抽签机会,单日通过投标获得的抽签机会上限为10次!
需求核心:
一、查询抽签机会
抽签机会(times)=活动一抽签次数(activity1Account)+活动二抽签次数(activity2Account)+活动三抽签次数(activity3Account)-(已经获得的获奖记录(rewardedTimes)-获奖天数(rewardedDays))
因为每天登陆并且抽奖的话,其中的一次抽奖机会来自登陆奖励,所以需要在已经抽奖的总次数中减去获奖的天数,因为只要该用户今天有获奖记录,就说明他已经登陆过,已经登陆就有一次抽签机会。
而这个活动中活动三算是让人比较难琢磨的一个查询,因为不光需要查询他的所有抽奖次数,最关键是每天上限不得超过10次,所以特奉上SQL,其实主要就是用了CASE:
sql.append("SELECT USER_ID,to_char(BID_TIME,'yyyy-mm-dd') AS BID_TIME,")
.append(" CASE")
.append(" WHEN SUM(BID_AMOUNT)/10000>10")
.append(" THEN 10")
.append(" ELSE TRUNC(SUM(BID_AMOUNT)/10000)")
.append(" END")
.append(" FROM T_LOAN_BID")
.append(" WHERE USER_ID=")
.append(userId)
.append(" AND BID_TIME>=TO_DATE('")
.append(dateFormat(startTime))
.append("','yyyy-mm-dd hh24:mi:ss')")
.append(" AND BID_TIME<=TO_DATE('")
.append(dateFormat(endTime))
.append("','yyyy-mm-dd hh24:mi:ss')")
.append("GROUP BY USER_ID,to_char(BID_TIME,'yyyy-mm-dd')");
System.out.println(sql.toString());
二、抽签
抽签其实和“砸金蛋”、“大转盘活动”的逻辑是一样的,主要是对奖品的随机抽取,并且要保证奖品到活动结束仍然剩余而且不能一开始把价值好的奖品抽走了,对于用户的吸引力也不是很大,所以整个抽奖要本着公平公正的原则。下面看一下抽奖的逻辑实现:
/**
*桃花朵朵开 求爱上上签
* @param activityId
* @param userId
* @throws Exception
*/
public Map saveDrawinglots(String activityId, BigDecimal userId,Map resultMap,String path) {
try {
/** 查询本次活动的奖品(根据活动标识,查询属于“桃花朵朵开 求爱上上签”奖品) */
List<RewardPrize> prizes = findBreakEggsPrizes(activityId);
if (prizes.size() <= 0) {// 奖品数量为0
resultMap.put("code", 3);// 奖品抽完了
return null;
}
System.out.println("prizes查询完毕");
/** 根据权重产生随机数 */
MathRandom a = new MathRandom();
int random = a.PercentageRandom(prizes);
/** 根据随机数确定抽中奖品 */
RewardPrize rp = prizes.get(random);
/** 当本类奖品数量为0,但总奖品数不为0时,重新抽奖 */
int prizesCount = 0;
for (int i = 0; i < prizes.size(); i++) {
prizesCount = prizesCount + prizes.get(i).getPrize_amount();
}
if (prizesCount <= 0) {// 奖品数量为0
resultMap.put("code", 3);// 奖品抽完了
return null;
}
while (rp.getPrize_amount() <= 0 && prizesCount > 0) {
random = a.PercentageRandom(prizes);
rp = prizes.get(random);
}
logger.info("用户" + userId + "抽中的奖品是 " + rp.getPrize_name());
System.out.println("用户" + userId + "抽中的奖品是 " + rp.getPrize_name());
/** 插入获奖记录 */
RewardPrizeRecord rpp = new RewardPrizeRecord();
rpp.setUser_id(userId);
rpp.setPrize_id(rp.getId());
rpp.setCreateTime(new Date());
rpp.setIsSend(1);
rpp.setSendTime(new Date());
rpp.setActivityName(queryActivityById(activityId).getActivityName());
prizeRecordDao.save(rpp);
logger.info("用户" + userId + "抽中的奖品 " + rp.getPrize_name()
+ "已经存入获奖记录中!");
System.out.println("用户" + userId + "抽中的奖品 " + rp.getPrize_name()
+ "已经存入获奖记录中!");
/** 将抽中的奖品剩余数量减去1 */
rp.setPrize_amount(rp.getPrize_amount() - 1);
prizeDao.save(rp);
logger.info("奖品 " + rp.getPrize_name() + "的数量减1,剩余数量:"
+ rp.getPrize_amount());
System.out.println("奖品 " + rp.getPrize_name() + "的数量减1,剩余数量:"
+ rp.getPrize_amount());
/** 如果奖品类型为红包,则发送红包(即向红包表插入记录)[0积分 1红包 2实物] */
if (rp.getPrize_type() == 1) {
CapRedpackinfo crpi = new CapRedpackinfo();
crpi.setUserId(userId);// 设置红包发送对象
crpi.setCariEnable(1);// 0不可用 1可用
crpi.setCariStatus(0);// 0未兑换 1已兑换
crpi.setSendDate(new Date());//发送时间
crpi.setCreateTime(new Date());// 创建时间
crpi.setStatus(0);// 0未删除
crpi.setCariAmount(new BigDecimal(String.valueOf(rp
.getPrize_limit())));// 红包金额
crpi.setCariType(3);// 红包类型为活动红包3
crpi.setNote(rp.getPrize_name());// 说明
crpi.setPrizeId(rp.getId().toString());
capRedpackinfoDao.save(crpi);
logger.info("金额为" + rp.getPrize_limit() + "的红包已经插入红包信息表");
System.out
.println("金额为" + rp.getPrize_limit() + "的红包已经插入红包信息表");
}
/** 只有积分发送站内信、短信,通知用户 */
// 发站内信
StringBuffer content = new StringBuffer("");
if (rp.getPrize_type() == 0) {//积分
content.append("尊敬的用户,您在**“桃花朵朵开,求爱上上签”活动中获得"+rp.getPrize_name()+",请进入账户中心-我的积分 查收。");
}else if(rp.getPrize_type() == 1){//红包
content.append("尊敬的用户,您在**“桃花朵朵开,求爱上上签”活动中获得"+rp.getPrize_name()+",请进入账户中心-我的红包 查收。");
}else{//实物
content.append("尊敬的用户,您在**“桃花朵朵开,求爱上上签”活动中获得"+rp.getPrize_name()+",请进入账户中心-消息中心 查收。");
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日HH时mm分");
String msgType ="12"; // 13红包消息,抽到实物就是12系统通知
String title = "活动奖品发放通知";
saveRewardMessage(content, userId, msgType, title);
// 发短信
String target = ((CustUser) resultMap.get("custUser")).getMobile();
List<String> mobile = new ArrayList<String>();
mobile.add(target);
//String smsContent = "恭喜您在普惠理财元旦圣诞砸金蛋活动中获得:" + rp.getPrize_name()+ ",详情请查看平台站内信通知!";
int result = sms.sendSMS(mobile, content.toString());
System.out.println("短信状态:" + result);
System.out.println("短信对象:" + target);
System.out.println("短信内容:" + content);
saveMsgSms(target, content.toString(), result, "");
resultMap.put("code", 4);// 抽奖成功
其中有一个非常重要的方法:PercentageRandom
这个方法用于根据权重来获取用户所抽奖项:
/**
* Math.random()产生一个double型的随机数,判断一下 每个奖品出现的概率
*
* @return int
*
*/
public int PercentageRandom(List<RewardPrize> prizes) {
DecimalFormat df = new DecimalFormat("######0.00");
int random = -2;
try{
double sumWeight = 0;
//计算总权重
for(RewardPrize rp_1 : prizes){
sumWeight += rp_1.getPrize_weight();
}
System.out.println("总权重是:" + sumWeight);
double randomNumber;
randomNumber = Math.random();
System.out.println("randomNumber是:" + randomNumber);
double d1 = 0;
double d2 = 0;
for(int i=0;i<prizes.size();i++){
d2 += Double.parseDouble(String.valueOf(prizes.get(i).getPrize_weight()))/sumWeight;
if(i==0){
d1 = 0;
}else{
d1 +=Double.parseDouble(String.valueOf(prizes.get(i-1).getPrize_weight()))/sumWeight;
}
if(randomNumber >= d1 && randomNumber <= d2){
random = i;
System.out.println("d1是:" + d1);
System.out.println("d2是:" + d2);
break;
}
}
}catch(Exception e){
System.out.println(e.getMessage());
logger.error("生成抽奖随机数出错,出错原因:" + e.getMessage());
random = -1;
}
return random;
}
三、xml自定义与读取
上面是整个抽签过程的逻辑实现,下面还有一个逻辑就是当用户点击抽签时,会对应出现一些签语,再点解签出现对签语的解释以及签的级别,因为一共只有24组签,而且活动完成后就不再使用,所以将这24组签存入xml中,对xml进行解析。
页面设计:
这是我自定义的xml的一部分:
<?xml version="1.0" encoding="UTF-8"?>
<lots>
<lot>
<id>1</id>
<sign>上上大吉</sign>
<brief>关关雎鸠 ,在河之洲,窈窕淑女,君子好逑。</brief>
<detail>春令之鸟儿啭枝头,在河之洲,一群由冬天醒来之鸠儿歌唱,其婉转歌声如一少女之求偶之声,君子求之者多。一位淑女终得以淑配,良人得良缘。</detail>
</lot>
<lot>
<id>2</id>
<sign>上</sign>
<brief>逾东家墙而搂其处子,则得妻。不搂,则不得妻。</brief>
<detail>如在偶然之机会,或相处已久,视伊人为终身可许之者,应采取行动,不宜逸失机会。姻缘之至也,必须勇往迈进。</detail>
</lot>
<lot>
<id>3</id>
<sign>上吉</sign>
<brief>风弄竹声,只道金佩响;月移花影,疑是玉人来。</brief>
<detail>春风一动,竹叶之摇晃,沙沙作响,啻可听道金佩在响。月日一日日地去耶,花影见了,心底下,疑玉人来。繇此可知,君之好事已近。</detail>
</lot>
读取xml
//读取路径
String path=request.getRealPath("WEB-INF/peach.xml");
随机从24组签中抽签一组
/******************抽签****************************/
int i=(int)(Math.random()*24);
SAXBuilder reader = new SAXBuilder();
Document doc = null;
doc = reader.build(new File(path));
Element root = doc.getRootElement();
List list = root.getChildren();
Element book = (Element)list.get(i);
String id=book.getChildText("id");
String sign= book.getChildText("sign");
String brief= book.getChildText("brief");
String detail= book.getChildText("detail");
四、复制粘贴功能
复制到剪切板:
这块主要前端:
jsp:
<div class="h3">
<a id="link_inveteNo">${inviteLink}</a>
<i id="copy_button" class="btn01" onclick="toClipboard()" style="cursor:pointer;">复制</i>
<img class="wechatt" src="<%=path%>/resources/peaches/img/wechat.png" />
</div>
js:
function toClipboard() {
var text=document.getElementById('link_inveteNo').innerText;
text.replace("&","&");
var clip = new ZeroClipboard.Client();
ZeroClipboard.setMoviePath('/puhuilicai/views/ssl/resources/js/ZeroClipboard.swf' );
clip.setHandCursor(true);
clip.addEventListener('mouseover', function (client){
clip.setText(text);
});
clip.addEventListener('complete', function (client, text) {
//此处用到layer框架
layer.tips('复制成功,您可以粘贴发送给QQ上的好友或QQ群了^_^', '#copy_button', {
tips: [1, '#3b639e'],
time: 4000
});
});
clip.glue('copy_button');
}
五、分享到朋友圈:
这个功能主要是调用百度的一个API来生成二维码的:
public static String request(String httpUrl, String httpArg) {
BufferedReader reader = null;
String result = null;
StringBuffer sbf = new StringBuffer();
httpUrl = httpUrl + "?" + httpArg;
try {
URL url = new URL(httpUrl);
HttpURLConnection connection = (HttpURLConnection) url
.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("apikey", "自己的百度APIkey");
connection.connect();
InputStream is = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
String strRead = null;
while ((strRead = reader.readLine()) != null) {
sbf.append(strRead);
sbf.append("\r\n");
}
reader.close();
result = sbf.toString();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
@RequestMapping(value = "/reward/createWechatQRCode", method = RequestMethod.GET)
@ResponseBody
public synchronized Map<String, Object> createWechatQRCode(HttpServletRequest request,HttpSession session) {
Map<String, Object> resultMap = new HashMap<String, Object>();
CustUser custUser = (CustUser) session.getAttribute(Constants.USER);
if(custUser!=null){
String inviteLink="https://www.puhuilicai.com/ssl/toRegister.htm";
inviteLink=inviteLink+"?inveteNo="+"8"+new StringBuffer(custUser.getId().toString()).reverse().toString();
/** 调用百度API */
String httpUrl = "http://apis.baidu.com/3023/qr/qrcode";
String httpArg = "size=8&qr="+inviteLink;
String jsonResult = request(httpUrl, httpArg);
System.out.println(jsonResult);
System.out.println(jsonResult.indexOf(":")+2);
System.out.println(jsonResult.indexOf("}")-1);
jsonResult=jsonResult.substring(jsonResult.indexOf(":")+2,jsonResult.indexOf("}")-1);
System.out.println(jsonResult);
resultMap.put("path", jsonResult);
}
return resultMap;
}
js:
$(".wechatt").click(function(){
$.ajax({
type: "GET",
url: "../reward/createWechatQRCode.htm",
dataType: "json",
async: false,
success: function(data) {
if (null != data.path) {
$('#picWechatQRCode').attr('src',data.path);
$(".wechat").show();
}
}
});
})
<div class="wechat" style="display: none;">
<img class="closew" src="<%=path%>/resources/peaches/img/close.jpg" />
<img id="picWechatQRCode" src=""/>
</div>