简单的红包实现

本人按照微信的红包实现的功能,首先红包分为个人红包和群红包,群红包又分为随机红包和定额红包,红包超时24小时未领取剩余的金额会退回到发红包的人的账户。发红包的过程分为以下几步:创建红包、获取红包信息、领红包、红包领取记录、红包发送记录信息等,根据公司需求稍微有所差异:

以下是countroller层,只列出最关键的几个接口:

@RestController
@RequestMapping(method = RequestMethod.POST)
@Slf4j
@Api(value = "红包接口", tags = { "红包操作接口" })
public class RedPacketController {

	@Autowired
	private LocaleMessageSourceService msService;
	@Autowired
	private MemberService memberService;
	@Autowired
	private RedisTemplate redisTemplate;
	@Autowired
	private RedPacketService redPacketService;
	@Autowired
	private MemberWalletService memberWalletService;
	@RequestMapping(value = "/createRedPacket")
	public MessageResult createRedPacket(String name, String unit, BigDecimal quantity, BigDecimal amount,
			Integer type,Integer redPacketType, Long drawNo, String jyPassword,
			@ApiIgnore @SessionAttribute(SESSION_MEMBER) AuthMember user) throws Exception {
		//入参非空验证
		ValidateUtil.hasText(name, 500, msService.getMessage("NAME_IS_NOT_EMPTY"));
		ValidateUtil.hasText(unit, 500, msService.getMessage("UNIT_IS_NOT_EMPTY"));
		ValidateUtil.notNull(quantity, 500, msService.getMessage("QUANTITY_IS_NOT_EMPTY"));
		ValidateUtil.notNull(amount, 500, msService.getMessage("AMOUNT_IS_NOT_EMPTY"));
		ValidateUtil.notNull(redPacketType, 500, msService.getMessage("REDPACKET_TYPE_IS_NOT_EMPTY"));
		ValidateUtil.notNull(drawNo, 500, msService.getMessage("DRAW_NO_IS_NOT_EMPTY"));
		ValidateUtil.hasText(jyPassword, 500, msService.getMessage("TRANSFER_PASSWORD_IS_NOT_EMPTY"));
		//调用创建红包的方法
		return redPacketService.createRedPacket(name, unit, quantity, amount,type, redPacketType, drawNo, jyPassword, user.getId());
	}
public MessageResult getRedPacket(Long id, @ApiIgnore @SessionAttribute(SESSION_MEMBER) AuthMember user) throws BusinessValidationException {

		// 1 检查参数
		ValidateUtil.notNull(id, 500, msService.getMessage("REDPACKET_ID_IS_NOT_EMPTY"));
		// 业务处理
		RedPacket redPacket = redPacketService.findRedPacketById(id);
		RedPacketInfo info = RedPacketInfo.toRedPacketInfo(redPacket);

		Member member = memberService.findOne(user.getId());
		info.setAvatar(member.getAvatar());
		info.setJid(member.getJid());
		info.setNickname(member.getNickname());

		MessageResult result = MessageResult.success();
		result.setData(info);
		return result;

	}
@Transactional(rollbackFor = Exception.class)
	public MessageResult drawRedPacket(Long id, @ApiIgnore @SessionAttribute(SESSION_MEMBER) AuthMember user) throws BusinessValidationException {

		// 1. 检查参数
		ValidateUtil.notNull(id, 500, msService.getMessage("REDPACKET_ID_IS_NOT_EMPTY"));
		
		// 业务实现:Redis方式:
		//return redPacketService.drawRedPacketRedis(id, user.getId());
		
		// 业务实现:数据库方式:

		return redPacketService.drawRedPacketDB(id, user.getId());
	}

这是service层:

package com.spark.bitrade.service;

import static com.spark.bitrade.util.BigDecimalUtils.compare;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Random;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import com.spark.bitrade.constant.TypeEnum;
import com.spark.bitrade.constant.RedPacketTypeEnum;
import com.alibaba.fastjson.JSONObject;
import com.spark.bitrade.constant.ReceivedStatusEnum;
import com.spark.bitrade.constant.RedPacketStatusEnum;
import com.spark.bitrade.dao.CoinDao;
import com.spark.bitrade.dao.RedPacketDao;
import com.spark.bitrade.dao.RedPacketOverviewDao;
import com.spark.bitrade.dao.RedPacketRecordDao;
import com.spark.bitrade.dao.RedPacketRecordOverviewDao;
import com.spark.bitrade.entity.Coin;
import com.spark.bitrade.entity.Member;
import com.spark.bitrade.entity.MemberWallet;
import com.spark.bitrade.entity.RedPacket;
import com.spark.bitrade.entity.RedPacketOverview;
import com.spark.bitrade.entity.RedPacketRecord;
import com.spark.bitrade.entity.RedPacketRecordOverview;
import com.spark.bitrade.exception.BusinessValidationException;
import com.spark.bitrade.exception.InformationExpiredException;
import com.spark.bitrade.job.CheckRedPacketTask;
import com.spark.bitrade.system.LocaleMessageSourceService;
import com.spark.bitrade.util.BigDecimalUtils;
import com.spark.bitrade.util.HttpRequestUtil;
import com.spark.bitrade.util.Md5;
import com.spark.bitrade.util.MessageResult;
import com.spark.bitrade.util.ValidateUtil;
import com.spark.bitrade.vo.RedPacketInfo;
import com.spark.bitrade.vo.RedPacketRecordInfo;

import lombok.extern.slf4j.Slf4j;

@Service
@Slf4j
public class RedPacketService {
	@Value("${im.api.url}") 
	private String ImApiUrl;
	@Autowired
	private LocaleMessageSourceService msService;
	@Autowired
	private MemberService memberService;
	@Autowired
	private MemberWalletService memberWalletService;
	@Autowired
	private RedPacketDao redPacketDao;
	@Autowired
	private RedPacketOverviewDao redPacketOverviewDao;
	@Autowired
	private RedPacketRecordDao redPacketRecordDao;
	@Autowired
	private RedPacketRecordOverviewDao redPacketRecordOverviewDao;
	@Autowired
	private CoinDao coinDao;
	@Autowired
	private RedisTemplate redisTemplate;	
	
	@Transactional(rollbackFor = Exception.class)
	private RedPacket save(RedPacket redPacket) {
		return redPacketDao.save(redPacket);
	}
	@Transactional(rollbackFor = Exception.class)
	public MessageResult createRedPacket(String name, String unit, BigDecimal quantity, BigDecimal amount,
			Integer type,Integer redPacketType, Long drawNo, String jyPassword,
			Long memberId) throws Exception {
		// 业务前置检查:2.1交易密码必须已经设置
		Member member = memberService.findOne(memberId);
		String mbPassword = member.getJyPassword();
		ValidateUtil.hasText(mbPassword,500, msService.getMessage("NO_SET_JYPASSWORD"));
		// 业务前置检查:2.2交易密码必须相等
		ValidateUtil.isTrue(Md5.md5Digest(jyPassword +
		member.getSalt()).toLowerCase().equals(mbPassword),500,msService.getMessage("ERROR_JYPASSWORD"));

		// 业务前置检查:2.3 检查用户必须有相应币种钱包。
		Coin coin = coinDao.findByUnit(unit);
		MemberWallet memberWallet = memberWalletService.findByCoinAndMemberId(coin, member.getId());
		// 业务前置检查:2.4 检查用户必须有相应币种钱包的余额必须大于发红包总金额。
		ValidateUtil.isTrue(compare(memberWallet.getBalance(), amount),500,
				msService.getMessage("INSUFFICIENT_BALANCE"));
		
		ValidateUtil.isTrue(compare(amount, coinDao.findByUnit(unit).getMinWithdrawAmount()),500,
				msService.getMessage("REDPACKET_AMOUNT_ISLESS") + coinDao.findByUnit(unit).getMinWithdrawAmount());
		ValidateUtil.isTrue(compare(coinDao.findByUnit(unit).getMaxWithdrawAmount(),amount),500,
				msService.getMessage("REDPACKET_AMOUNT_ISMORE") + coinDao.findByUnit(unit).getMaxWithdrawAmount());
		// 业务处理:3.1 冻结相应余额
		memberWallet.setFrozenBalance(amount);
		MessageResult freezeResult = memberWalletService.freezeBalance(memberWallet, amount);
		if (freezeResult.getCode() != 0) {
			throw new InformationExpiredException("Information Expired");
	} else {
		MessageResult.success();
	}
		// 业务处理:4.1准备红包
		RedPacket redPacket = new RedPacket();	
		RedPacketRecord record = new RedPacketRecord();
		if (type.equals(TypeEnum.person.getOrdinal())) {
			redPacket.setType(TypeEnum.person);
			redPacket.setAmount(amount);
			redPacket.setQuantity(quantity);
			record.setReceivedAmount(amount);
			record.setReceivedQuantity(quantity);
		} else if (type.equals(TypeEnum.group.getOrdinal())) {
			redPacket.setType(TypeEnum.group);
			redPacket.setDrawNo(drawNo);
			redPacket.setSumAmount(BigDecimalUtils.mul(amount, quantity));
			if (redPacketType.equals(RedPacketTypeEnum.normal.getOrdinal())) {
				redPacket.setRedPacketType(RedPacketTypeEnum.normal);
				redPacket.setAmount(amount);
				redPacket.setQuantity(quantity);
			} else if (redPacketType.equals(RedPacketTypeEnum.random.getOrdinal())) {
				redPacket.setRedPacketType(RedPacketTypeEnum.random);
				redPacket.setAmount(amount);
				redPacket.setQuantity(quantity);
			} else {
				MessageResult.error(500, msService.getMessage("REDPACKET_TYPE_DOSE_NOT_EXIST"));
			}
		} else {
			MessageResult.error(msService.getMessage("REDPACKET_TYPE_DOSE_NOT_EXIST"));
		}
		redPacket.setRedPacketStatus(RedPacketStatusEnum.normal);
		redPacket.setMemberId(memberId);
		redPacket.setCreateTime(new Date());
		redPacket.setName(name);
		redPacket.setDrawNo(drawNo);
		redPacket.setTerm(24 * 60 * 60);
		redPacket.setUnit(unit);

		// 业务处理:5:保存红包
		RedPacket redPacket1 = save(redPacket);
		record.setMemberId(memberId);
		record.setRedPacketId(redPacket1.getId());
		record.setUnit(redPacket1.getUnit());
		redPacketRecordDao.save(record);
		// 业务后续处理:6:缓存红包数据到redis,数据供收红包用。如果考虑先实现功能,先不考虑redis这个实现方式
		// 业务后续处理:7:返回红包数据
		MessageResult result = MessageResult.success();
		result.setData(RedPacketInfo.toRedPacketInfo(redPacket1));
		return result;
	}
	@Transactional(rollbackFor = Exception.class)
	public MessageResult drawRedPacketDB(Long id,Long memberId) throws BusinessValidationException {
		// 业务实现:Redis方式:
		//TODO
		
		// 业务实现:数据库方式:
		// 业务前置检查 2.1 红包必须存在
		RedPacket redPacket = findRedPacketById(id);
		Member member = memberService.findOne(memberId);
		// 业务前置检查2.2 红包必须是可以用状态
		ValidateUtil.isTrue(redPacket.getRedPacketStatus().equals(RedPacketStatusEnum.normal),500, "红包不可用");
		// 业务前置检查2.3 如果红包是个人红包, 当前用户不能是发红包用户
		if(TypeEnum.person.equals(redPacket.getType())) {
			ValidateUtil.isTrue(memberId.equals(redPacket.getMemberId()), 500, "");
		}
		// 业务前置检查2.5 如果是群红包,当前用户必须没有收取过这个红包,
		if(TypeEnum.group.equals(redPacket.getType())) {
			RedPacketRecord redPacketRecord = redPacketRecordDao.findByRedPacketId(id);
			ValidateUtil.isTrue(redPacketRecord.getReceivedStatus() == null, 500, "已领取过此红包不可再领取");
		}
		// 业务处理3.1 生成红包收取记录
		RedPacketRecord record = new RedPacketRecord();
		Date date = new Date();
		//判断领取时间,领取时间不能超过24小时
		if((date.getTime() - redPacket.getCreateTime().getTime())/(24*60*60*1000) < 24) {
			record.setReceivedTime(date);
		record.setRedPacketId(id);
		record.setUnit(redPacket.getUnit());
		Coin coin = coinDao.findByUnit(redPacket.getUnit());
		MemberWallet memberWallet = memberWalletService.findByCoinAndMemberId(coin, memberId);
		// 业务处理3.2:红包收取金额: 如果是个人红包
		if(TypeEnum.person.equals(redPacket.getType())) {
			record.setMemberId(memberId);
			//record.setReceivedAmount(redPacket.getAmount());
			redPacket.setRedPacketStatus(RedPacketStatusEnum.normal);
			//将之前冻结的金额解冻
			MessageResult freezeResult = memberWalletService.thawBalance(memberWallet, redPacket.getAmount());
			if (freezeResult.getCode() != 0) {
				MessageResult.error("Information Expired");
			}else {
				MessageResult.success();
			}
			//如果是群红包
		}else if(TypeEnum.group.equals(redPacket.getType())) {
			StringBuilder params=new StringBuilder();
	        params.append("gid=");
	        params.append(redPacket.getDrawNo());
	        params.append("&uid=");
	        params.append(member.getJid());
	        String imUrl = ImApiUrl;
	        String str=HttpRequestUtil.sendPost(imUrl,params.toString(),false,false);
	        JSONObject json=JSONObject.parseObject(str);
	        Object code= json.get("code");
	        if (code.equals("1000")) {
	        	log.info("此用户可以领取!");
	        }else if(code.equals("1003")) {
	        	return MessageResult.error("此用户非群成员不可领取红包!");
	        }
	        else {
	        	redPacket.setRedPacketStatus(RedPacketStatusEnum.unspecified);
	        }
			if(RedPacketTypeEnum.normal.equals(redPacket.getRedPacketType())) {
				record.setReceivedAmount(BigDecimalUtils.div(redPacket.getAmount(), redPacket.getQuantity()));
				record.setReceivedStatus(ReceivedStatusEnum.received);
				record.setMemberId(memberId);
			}else if(RedPacketTypeEnum.random.equals(redPacket.getRedPacketType())) {
				RedPacketRecord redRecord = redPacketRecordDao.findByRedPacketId(id);
				//计算随机红包的金额
				BigDecimal am = redPacket.getAmount();
				BigDecimal no = redPacket.getQuantity();
				BigDecimal min = memberWallet.getCoin().getMinWithdrawAmount();
				BigDecimal max = BigDecimalUtils.mul(BigDecimalUtils.div(am, no), 2);
				/*Random random = new Random();
				List<Integer> list = new ArrayList<>();
				int total_random = 0;
				for(int i = 0; i < no.intValue(); i++) {
					int r = random.nextInt(); //获取一个随机数
				        total_random += r;
					list.add(r);
				}
				//获取随机金额
				List<BigDecimal> packets = new ArrayList<>();
				BigDecimal bi = BigDecimal.ZERO;
				for(int i = 0; i < list.size(); i++) {
					BigDecimal packet = BigDecimalUtils.mul((new BigDecimal(list.get(i) / total_random)), am);
					
					packet = BigDecimalUtils.compare(packet,max) ? max:packet;
					packet = BigDecimalUtils.compare(min, packet) ? min:packet;
					
					redRecord.setReceivedAmount(packet);
					packets.add(packet);
					bi = BigDecimalUtils.add(packets.get(i), bi);
				}*/
				
			List<BigDecimal> list =splitRedPacket(no.intValue(),am.intValue(),min.intValue(),max.intValue());
			
			BigDecimal check_num = BigDecimal.ZERO;

			System.out.println(Arrays.toString(list.toArray()));
			for (BigDecimal x : list) {

				check_num = BigDecimalUtils.add(check_num, x);

			}
				redRecord.setReceivedSumAmount(check_num);
				//获得收到的红包的最大金额
				BigDecimal big = Collections.max(list);
				//如果收到的金额等于最大金额,就是手气最佳
				if(BigDecimalUtils.isEqual(redRecord.getReceivedAmount(), big)) {
					record.setIsBestHand(true);
				}else {
					record.setIsBestHand(false);
				}
				redPacket.setSumAmount(check_num);
				redPacket.setMemberId(memberId);
				if(BigDecimalUtils.isEqual(redRecord.getReceivedAmount(), BigDecimal.ZERO)) {
					record.setReceivedStatus(ReceivedStatusEnum.allRobbed);
				}else {
					record.setReceivedStatus(ReceivedStatusEnum.received);
				}
				record.setMemberId(memberId);
			}
		}
		}else {
			MessageResult.error(msService.getMessage("超过24小时不能领取!"));
		}
		RedPacketRecord rpr = redPacketRecordDao.findByRedPacketId(id);
		record.setReceivedAmount(rpr.getReceivedAmount());
		RedPacketRecord record1 = redPacketRecordDao.save(record);
		// 业务后续处理3. 生成红包收取的统计数据
		RedPacketRecordInfo info = RedPacketRecordInfo.builder()
				.memberId(memberId).receivedAmount(record1.getReceivedAmount())
				.receivedTime(record1.getReceivedTime()).redPacketId(id)
				.avatar(member.getAvatar()).jid(member.getJid())
				.nickname(member.getNickname()).unit(record1.getUnit())
				.redPacketStatus(redPacket.getRedPacketStatus()).isBestHand(record1.getIsBestHand())
				.build();
				
		// 业务后续处理:返回数据
		MessageResult result = MessageResult.success();
		result.setData(info);
		return result;
	}
	
	
	public MessageResult drawRedPacketRedis(Long id,Long memberId) {

	
		// 业务实现:Redis方式:
		//TODO
		
		// 业务实现:数据库方式:
		// 业务前置检查 2.1 红包必须存在
		RedPacket redPacket = findRedPacketById(id);

		// 业务前置检查2.2 红包必须是可以用状态
		Assert.isTrue(redPacket.getRedPacketStatus()==RedPacketStatusEnum.normal, "红包不可用");
		
		// 业务前置检查2.3 如果红包是个人红包, 当前用户不能是发红包用户
		//TODO

		// 业务前置检查2.4 如果是定额红包,当前用户不能是发红包用户
		//TODO

		// 业务前置检查2.5 如果是群红包,当前用户必须没有收取过这个红包,
		//TODO
		
		// 业务处理3.1 生成红包收取记录
		//TODO
		RedPacketRecord record = new RedPacketRecord();

		record.setRedPacketId(id);
		record.setUnit(redPacket.getUnit());
		// 业务处理3.2:红包收取金额: 如果是个人红包:如果是群定额红包,如果是群随机红包
		//TODO

		//RedPacketRecord record1 = save(record);

		//RedPacketRecordInfo info = RedPacketRecordInfo.toRedPacketRecordInfo(record1);
		
		// 业务处理3.3. 修改红包状态1, 如果是个人红包,红包完毕,如果群定额红包,群随机红包,红包接受数量,接受金额,
		
		// 业务后续处理3. 生成红包收取的统计数据
		// 业务后续处理:返回数据
		MessageResult result = MessageResult.success();
		result.setData("");
		return result;
	}
	
	
	
	
	public List<RedPacket> findRedPacketByYearAndUnit(String year,String unit){
		return redPacketDao.findAllByYearAndUnit(year,unit);
		
	}
	
	
	public RedPacket findByIdAndDrawNo(Long id,Long drawNo) {
		return redPacketDao.findByIdAndDrawNo(id, drawNo);
	}

	public RedPacket findRedPacketById(Long id) {
		return redPacketDao.findById(id);
	}
	public RedPacketRecord findRedPacketRecordById(Long id) {
		return redPacketRecordDao.findById(id);
	}
	public List<RedPacketRecord> findRedPacketRecordByRedPacketId(Long id) {
		return redPacketRecordDao.findAllByRedPacketId(id);
	}
	public RedPacketOverview findRedPacketOverviewByYearAndUnit(String year, String unit) {
		return redPacketOverviewDao.findByYearAndUnit(year,unit);
	}
	public RedPacketRecordOverview findRedPacketRecordOverviewByYearAndUnit(String year, String unit) {
		return redPacketRecordOverviewDao.findByYearAndUnit(year,unit);
	}
	
	/**

	 * 

	 * @param total

	 *            总金额

	 * @param splitCount

	 *            个数

	 * @param min

	 *            最小金额

	 * @param max

	 *            最大金额

	 */

	public List<BigDecimal> splitRedPacket(int total, int splitCount, int min, int max) {

		System.out.println("总金额:	" + total);

		System.out.println("个数:	" + splitCount);

		System.out.println("最小金额:	" + min);

		System.out.println("最大金额:	" + max);

		List<BigDecimal> al = new ArrayList<BigDecimal>();

		Random random = new Random();

		if ((splitCount & 1) == 1) {// 奇数个红包,需要单独将其中一个红包先生成,以保证后续算法拆分份

			System.out.println("红包个数" + splitCount + "是奇数,单独生成一个红包");

			int num = 0;

			do {

				num = random.nextInt(max);

				// num = (total - num) % (splitCount / 2) + num; //

				// 将后面算法拆分时的余数加入到这个随机值中

				System.out.println("单个的随机红包为:" + num);

			} while (num >= max || num <= min);

			total = 40000 - num;
			
			BigDecimal number = new BigDecimal(0);
			number = BigDecimal.valueOf((int)num);

			al.add(number);

		}

		int couples = splitCount >> 1;
			
			System.out.println(Integer.toBinaryString(splitCount));
			
			System.out.println(Integer.toBinaryString(couples));
			
			System.out.println("====拆分的数量是====="+couples);

		int perCoupleSum = total / couples;

		if ((splitCount & 1) == 1) {

			System.out.println("处理后剩余的金额为:" + total);

		}

		System.out.println("将" + total + "元拆分为" + couples + "对金额,每对总额:" + perCoupleSum);
		
		for (int i = 0; i < couples; i++) {

			Boolean finish = true;

			int num1 = 0;

			int num2 = 0;

			do {

				num1 = random.nextInt(max);

				num2 = perCoupleSum - num1;
				
				System.out.println("***num1***"+num1);
				
				System.out.println("num2: "+num2);

				if (!al.contains(num1) && !al.contains(num2)) {

					if (i == 0) {

						num1 = (total - couples * perCoupleSum) + num1;
						
						System.out.println("***num1***"+num1);
						
						System.out.println("***num2: "+num2);

					}

				}

			} while (num1 < min || num1 > max || num2 < min || num2 > max);
			
			BigDecimal number1 = new BigDecimal(0);
			number1=BigDecimal.valueOf((int)num1);
			
			BigDecimal number2 = new BigDecimal(0);
			number2 = BigDecimal.valueOf((int)num2); 
			
			al.add(number1);

			al.add(number2);
			
			System.out.println("num1:  "+num1+"  num2:  "+num2);
			
			System.out.println("-----------al:"+al);

		}
		
		return al;

	}
}

这是model层:

@Entity
@Data
public class RedPacket {
		/**
		 * 主键ID
		 */
	 	@GeneratedValue(strategy = GenerationType.IDENTITY)
	    @Id
	    private Long id;
	    /**
	     * 红包名称
	     */
	    private String name;

	    /**
	     * 红包期限
	     */
	    private int term = 24*60*60;	    // 24小時
	    /**
	     * 红包发送者id
	     */
	    private long memberId;
	    /**
	     * 领取标识 群发就是群ID 一对一发送就是接收人ID
	     */
	    private Long drawNo;
	    /**
	     * 红包类型 0个人红包 1群红包
	     */
	    private TypeEnum type;
	    /**
	     * 红包类型 0定额红包 1随机红包
	     */
	    private RedPacketTypeEnum RedPacketType;
	    /**
	     * 红包状态 :
	     * 0 可正常领取 
	     * 1 未到领取时间 
	     * 2 红包已过期 
	     * 3 领取人不是发送者指定的群成员 
	     * 4 此用户已领取该红包 
	     * 5 红包已全部领取
	     */
	    private RedPacketStatusEnum redPacketStatus;
	    
	    /**
	     * 货币单位
	     */
	    private String unit; 
	    
	    @Column(columnDefinition = "decimal(18,8) comment '红包数量'")
	    private BigDecimal quantity;
	    
	    @Column(columnDefinition = "decimal(18,8) comment '红包金额'")
	    private BigDecimal amount;
	    
	    @Column(columnDefinition = "decimal(18,8) comment '红包总金额'")
	    private BigDecimal sumAmount;
	    
	    @Excel(name = "创建时间", orderNum = "1", width = 25)
	    @CreationTimestamp
	    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
	    private Date createTime;
	    
	    private String year = DateUtil.getDateY(new Date());
}

@Entity
@Data
public class RedPacketRecord {
	/**
	 * 主键ID
	 */
 	@GeneratedValue(strategy = GenerationType.IDENTITY)
    @Id
    private Long id;
 	/**
 	 * 红包ID
 	 */
 	private Long redPacketId;
 	
 	/**
 	 * 紅包收取人Id
 	 */
 	private Long memberId;
 	
 	/**
 	 * 年份
 	 */
 	private String year;
 	/**
     * 货币单位
     */
    private String unit;
    /**
     * 个人领取的状态
     */
    private ReceivedStatusEnum receivedStatus;
    
    @Excel(name = "领取时间", orderNum = "1", width = 25)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date receivedTime;
    
    @Column(columnDefinition = "decimal(18,8) comment '领取红包金额'")
    private BigDecimal receivedAmount;
    
    @Column(columnDefinition = "decimal(18,8) comment '领取红包总金额'")
    private BigDecimal receivedSumAmount;
    
    @Column(columnDefinition = "decimal(18,8) comment '领取红包数量'")
    private BigDecimal receivedQuantity;
    /**
     * 是否是手气最佳
     */
    private Boolean isBestHand;

}

这是dao层:

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.querydsl.QueryDslPredicateExecutor;

import com.spark.bitrade.entity.RedPacket;

public interface RedPacketDao extends JpaRepository<RedPacket,String>,JpaSpecificationExecutor<RedPacket>,QueryDslPredicateExecutor<RedPacket> {
	
	
	List<RedPacket> findAllByYearAndUnit(String year,String unit);
	
	List<RedPacket> findAll();
	
	public RedPacket findByIdAndDrawNo(Long id,Long drawNo);
	RedPacket findById(Long id);  

}

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.querydsl.QueryDslPredicateExecutor;

import com.spark.bitrade.entity.RedPacketRecord;



public interface RedPacketRecordDao extends JpaRepository<RedPacketRecord,String>,JpaSpecificationExecutor<RedPacketRecord>,QueryDslPredicateExecutor<RedPacketRecord> {
	
	List<RedPacketRecord> findAllByYearAndUnit(String year,String unit);
	List<RedPacketRecord> findAllByRedPacketId(Long redPacketId);
	RedPacketRecord findById(Long id); 
	List<RedPacketRecord> findByMemberId(Long memberId);
	List<RedPacketRecord> findAll();
	RedPacketRecord findByRedPacketId(Long redPacketId);

}

这是定时任务:

import java.util.Date;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import com.spark.bitrade.constant.RedPacketStatusEnum;
import com.spark.bitrade.dao.CoinDao;
import com.spark.bitrade.dao.RedPacketDao;
import com.spark.bitrade.dao.RedPacketRecordDao;
import com.spark.bitrade.entity.Coin;
import com.spark.bitrade.entity.MemberWallet;
import com.spark.bitrade.entity.RedPacket;
import com.spark.bitrade.entity.RedPacketRecord;
import com.spark.bitrade.service.MemberWalletService;
import com.spark.bitrade.util.BigDecimalUtils;
import com.spark.bitrade.util.MessageResult;
import lombok.extern.slf4j.Slf4j;

@Component
@Slf4j
public class CheckRedPacketTask {
	
	@Autowired
	RedPacketRecordDao redPacketRecordDao;
	@Autowired
	RedPacketDao redPacketDao;
	@Autowired
	private CoinDao coinDao;
	@Autowired
	private MemberWalletService memberWalletService;
	
	@Scheduled(fixedRate = 1000*60*60)
    public void checkExpireRedPacket() {
        log.info("=========开始检查24小时红包信息===========");
        //获取所有的收取红包信息
       List<RedPacketRecord> recordList = redPacketRecordDao.findAll();
       //获取所有的发出的红包信息
       List<RedPacket> redList = redPacketDao.findAll();
       for(RedPacket r : redList) {
    	   for(RedPacketRecord rr : recordList) {
    		   //判断发出的红包时间是否超过24小时
    	   if((new Date().getTime() - r.getCreateTime().getTime())/(24*60*60*1000) <24) {
    		  /* if(r.getType().equals(TypeEnum.group)) {
    			   //判断群红包里领取到的总金额和发出的总金额是否相等
    				   if(BigDecimalUtils.isEqual(rr.getReceivedSumAmount(), r.getSumAmount())) {
    					   r.setRedPacketStatus(RedPacketStatusEnum.allReceived);
    				   }else if(BigDecimalUtils.compare(r.getSumAmount(), rr.getReceivedSumAmount())) {
    					   r.setRedPacketStatus(RedPacketStatusEnum.normal);
    				   }else {
    					   log.error("");
    				   }
    			   }*/
    		   r.setRedPacketStatus(RedPacketStatusEnum.normal);
    		   }else {
    			   r.setRedPacketStatus(RedPacketStatusEnum.expired);
    			   Coin coin = coinDao.findByUnit(r.getUnit());
    				//将领取的金额充值到钱包
    				MemberWallet memberWallet = memberWalletService.findByCoinAndMemberId(coin, rr.getMemberId());
    				MessageResult freezeResult = memberWalletService.recharge(memberWallet, rr.getReceivedAmount());
    				if (freezeResult.getCode() != 0) {
    					MessageResult.error("Information Expired");
    				}else {
    					MessageResult.success();
    				}
    				//将剩余未领取的金额返回钱包
    				MemberWallet wallet = memberWalletService.findByCoinAndMemberId(coin, r.getMemberId());
    				int balance = memberWalletService.deductBalance(wallet, BigDecimalUtils.sub(r.getQuantity(), rr.getReceivedQuantity()));
    				if(balance < 0) {
    					MessageResult.error("Information Expired");
    				}else {
    					MessageResult.success();
    				}
    		   }
    	  
    	   }
       }
        log.info("=========结束检查===========");
    }

}

由于我们的项目是使用的分布式和springboot实现的,所以此项目跑不起来,但是思路是对的,其他的jar包之类的还需使用者自己下载。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值