抽奖,几乎是所有人都乐此不疲的一项活动。
小程序界,冯大的「抽奖助手」获得了巨大的成功,在上线111天时,用户超过了1000万。这件事折射出两点朴素的道理:1.产品优秀 2.用户喜欢抽奖。
在「抽奖助手」首页,用户每天都可以参与由不同的赞助商提供的抽奖,我发现无论奖品的价值高低,即使奖品价格相差比较“悬殊”,参与的人数几乎是相近的,从这点可以看出人多少还是有点小贪婪的,一言以蔽之:「我全都要」。此外,由于是发布在首页的抽奖,人人都可以参与。直至开奖截止,参与人数一般在6万-8万,暂且认为大部份奖品是一份,假设一个省的高考考生有20万,其中500人能上名校,那么中奖比上名校还要难175倍。(一个不恰当的比方)所以我当然没有中过(っ °Д °;)っ
所以抽奖的魅力在于给了人一种未知的机会,即使这个机会渺小到尘埃。有一种概率型奖励的实验:将一只很饿的小白鼠放入斯金纳箱中,多次按动按钮,概率掉落食物。结果是小白鼠学会了不停地按动按钮,随着食物掉落的概率越来越低,小白鼠的行为没有发生改变,持续了很长一段时间。这与我们人类很相似,不停地按动着手机上的那个“参与抽奖”的按钮,当然,可以写一个脚本代替,这也是人类比小白鼠高明的地方。
下面言归正传,作为狂热型小白鼠,我想自己写一个简单的抽奖程序,将它运用到之前我们自己开发的针对自己大学的一款掌上校园软件「果核」。
动机很单纯:
- 吸引用户
- 抽奖有一定趣味
- 如果能从赞助商那赚点钱就更好了
手段很单一:
- 所有用户都可以参加(用户总数不多,目前3k)
- 奖品价格最低标准50(有赞助商的情况下),没有赞助商我只能挥泪贡献一包辣条了
- 一周/月开奖一次,频率视赞助商热情程度而定。
技术很单薄:
H5
Springboot
Mysql
本人小白,估计很多地方设计得不科学,希望大家不吝赐教。
页面设计
因为拙于页面,所以暂时模仿了小程序「抽奖助手」,手撸了两个界面,如果涉及侵权,请通知我,立马就改(→_→)
- 参与界面
-
详情及开奖页面。
image.png
数据库
- 学生表。这张表之前就有,包含了用户的
学号
,生日
,学院
,专业
等信息。 - 奖品表。这张表需要新建,包含奖品
id
,数量
,名称
,图片
,奖品介绍
,赞助者
,赞助者标题
,赞助者详情
,外链
,创建时间
,中奖者id
。 - 奖品_用户表:因为是多对多的关系,必然需要一张中间表。包含以下字段
id
,奖品id
,用户id
。
目录结构
image.png服务接口
- 新增一个抽奖活动:POST方式,参数为一个Prize实体。
具体实现:
@Override
public Prize addPrize(Prize prize) {
if (prize==null){
throw new InfoPublishException(ResultEnum.NULL_OBJECT);
}
try {
prizeMapper.insertSelective(prize);
}catch (Exception e){
throw new InfoPublishException(ResultEnum.ADD_PRIZE_ERROR);
}
return prize;
}
- 参与抽奖:POST方式,参数为一个用户id。
具体实现:
@Override
public Student joinPrize(String studentId) {
Student student=null;
if(studentId==null){
throw new InfoPublishException(ResultEnum.NULL_OBJECT);
}
try {
student=studentMapper.selectByPrimaryKey(studentId);
Prize currentPrize=prizeMapper.selectCurrentPrize();
Integer currentPrizeId=currentPrize.getId();
if(student==null || currentPrizeId==null){
throw new InfoPublishException(ResultEnum.NULL_OBJECT);
}else{
PrizeUser prizeUser=new PrizeUser();
prizeUser.setPrizeId(currentPrizeId);
prizeUser.setUserId(student.getUsername());
try{
prizeUserMapper.insertSelective(prizeUser);
}catch (Exception e){
throw new InfoPublishException(ResultEnum.JOIN_PRIZE_ERROR);
}
}
}catch (Exception e){
throw new InfoPublishException(ResultEnum.FIND_STUDENT_ERROR);
}
return student;
}
- 获取当前抽奖的参与情况:GET方式,无参数。
具体实现:
public PrizeElement getCurrentData() {
Prize prize;
try {
//获取当前抽奖实体
prize=prizeMapper.selectCurrentPrize();
//根据抽奖实体id来获取参与者的总人数
Integer prizeId=prize.getId();
Integer AccountOfJoiners=prizeUserMapper.selectAccountByPrizeId(prizeId);
//根据抽奖实体id来获取参与者的学院热度
List<String> academyList=new ArrayList();
academyList=prizeUserMapper.selectAcademyOfJoiners(prizeId);
List<String> result=new ArrayList();
Map<String,Integer> resultMap=new HashMap<>();
for(String i:academyList){
boolean flag=false;
for(String j:result){
if(j.equals(i)){
flag=true;
int temp=resultMap.get(i)+1;
resultMap.put(i,temp);
break;
}
}
if(!flag){
result.add(i);
resultMap.put(i,1);
}
}
PrizeElement pe=new PrizeElement();
pe.setPrize(prize);
pe.setTotalJoiners(AccountOfJoiners+"");
pe.setRankAcademy(resultMap);
return pe;
}catch (Exception e){
throw new InfoPublishException(ResultEnum.GET_PRIZE_ERROR);
}
}
- 获取开奖信息:GET方式,无参数。
具体实现:
@Override
public Winner openPrize() {
Winner winner=new Winner();
Prize prize=prizeMapper.selectCurrentPrize();
Student student=studentMapper.selectByPrimaryKey(prize.getGmtOpen());
winner.setPrize(prize);
winner.setStudent(student);
return winner;
}
定时器
因为设计为每周/月进行开奖,那么需要一个定时器去触发任务,这里用的是Quartz
。
跨域问题
我在网上找了一个现成的写好的类用来继承。
/**
* @author zhangcunli
* 解决跨域问题
*/
@Configuration
public class Cors extends WebMvcConfigurerAdapter {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "OPTIONS", "DELETE", "PATCH")
.allowCredentials(true).maxAge(3600);
}
}
测试接口
imageimage
写到这里,基本上代码阶段已经完成。不足的地方也有很多,需要慢慢调整,也希望能给我一些宝贵意见。
诸位,人生苦短,尽情抽奖。
后面一句是:中奖是不可能的,这辈子都不可能中奖,作弊又不会,只能靠写代码才能维持得了生活这样子。
源码可在公众号后台回复:“抽奖”来获取。
image通过关注来提高中奖可能。
网友评论