我在最近做了一个微服务项目,说是微服务项目,但其实核心技术还是SpringBoot那一套核心技术,对于我们初学者把前面那些基础学好是非常的有必要的。我们先来看看这个小模块,因为我负责个人中心的一些小功能的实现,就把其中一个比较有代表性的签到功能拿出来分享给大家。刚开始我做这个功能的时候也是一脸懵逼、无从下手,在博客上面逛了好久也没有想到比较好的思路,本人新手,其中如果有什么不对的地方还麻烦路过的大神请多指教。
先来看这个数据库表的设计我们数据库表几经更改,最后都是按照最新的阿里开发规约黄山版设计。
首先是用户签到表,这个存储的用户信息id,并且通过这个外键来查询具体记录,我们这前端只传给一个userInfoId,从这个我们可以得到用户的持续登录天数,后期也比较好的去判断用户每天是否签到,有助于业务的处理。
再就是用户签到积分里程明细表,用户签到之后积分会有相应的增加,我们就通过这张表记录详细的用户签到的积分里程信息。因为前端传来的也是userInfoId,并且积分在下单过程中是能够消费的,可以用来抵扣一部分的现金,涉及订单的东西就会比较麻烦,因为得确定订单状态,之后还有可能涉及失败回滚,积分退回这一操作。还有一个功能就是绑定消费券,用一定的积分换取消费券也是一个需要实现的,所以就在这个表中加了消费券的相关外键。再就是需要确定积分的来源与去向,通过一个type就能较好地实现,从而避免既创建积分消费表又创建积分增加表的繁琐,在具体业务查询也是比较方便,可以自己直接判断或者使用一个枚举类都是不错的选择。当然这个积分里程数是这里的核心,是必不可少的。第三是这个过期积分的处理,我们因为之前经验不足,而直接使用xxl-job这个分布式定时任务中间件,我在之前的博客也有整理一些xxl-job的相关知识,大家想深入了解一下可以看下这篇文章
http://t.csdn.cn/wN1e6
当然其中有一些东西也是我们忽略的,最后师哥说如果直接使用这个那定时任务设置的更新时间就有很大的问题,如果设计的是1s更新一次那就对系统是很大的性能消耗,设计1min那时效性又会比较差;过期积分放在Rocket延时队列或者Redis延迟队列中,比如优惠券过期时间,就是到了那个时间之后,才把消息发给你,这样就能保证数据的实时性。这个表也是后来做业务新增需求之后新增的,这样也方便业务的处理。
接口测试接口测试用的国产软件ApiPost,挺适合团队协作开发的,大部分都是中文,可以较好替代Postman这个工具,推荐大家有时间可以去GitHub上下载使用一段时间试试。
当然还有很多功能是后续优化的时候还需要再添加到里面去的。
相关实体类@Data
@TableName("user_mileage_req")
public class UserMileageReq implements Serializable {
@TableId
@JsonIgnore
private Long id;
@JsonIgnore
private Long userInfoId;
@JsonIgnore
private Long discountCouponId;
@JsonIgnore
private Long orderInfoId;
private Integer type;
private Integer mileageCount;
public UserMileageReq(Long id, Long userInfoId, Long discountCouponId, Long orderInfoId, Integer type, Integer mileageCount, Date createTime, Date updateTime, Integer deleted) {
this.id = id;
this.userInfoId = userInfoId;
this.discountCouponId = discountCouponId;
this.orderInfoId = orderInfoId;
this.type = type;
this.mileageCount = mileageCount;
this.createTime = createTime;
this.updateTime = updateTime;
this.deleted = deleted;
}
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")
private Date createTime;
@JsonIgnore
private Date updateTime;
@JsonIgnore
private Integer deleted;
public UserMileageReq(Long id, Long userInfoId, Long orderInfoId, Integer type, Integer mileageCount) {
this.id = id;
this.userInfoId = userInfoId;
this.orderInfoId = orderInfoId;
this.type = type;
this.mileageCount = mileageCount;
}
public UserMileageReq(Long userInfoId, Integer type, Integer mileageCount) {
this.userInfoId = userInfoId;
this.type = type;
this.mileageCount = mileageCount;
}
}
@Data
@TableName("user_sign_in")
public class SignIn implements Serializable {
@TableId
@JsonIgnore
private Long id;
@JsonIgnore
@NotNull
private Long userInfoId;
private int duration;
@JsonIgnore
private Date createTime;
@JsonIgnore
private Date updateTime;
@JsonIgnore
private Integer deleted;
@TableField(exist = false)
private Integer mileageCount;
public SignIn(Long id, Long userInfoId, int duration, Date createTime, Date updateTime, Integer deleted) {
this.id = id;
this.userInfoId = userInfoId;
this.duration = duration;
this.createTime = createTime;
this.updateTime = updateTime;
this.deleted = deleted;
}
public SignIn(int duration, Integer mileageCount, Integer signed) {
this.duration = duration;
this.mileageCount = mileageCount;
this.signed = signed;
}
@TableField(exist = false)
private Integer memberLevel;
@TableField(exist = false)
private Integer signed;
}
@Data
@TableName("user_mileage_expired")
public class UserMileageExpired implements Serializable {
@TableId
private Long id ;
@NotNull
private Long userInfoId ;
private Integer mileageCount ;
private Date expireTime ;
private Date createTime ;
private Date updateTime ;
private Integer deleted ;
public UserMileageExpired(Long id, Long userInfoId, Integer mileageCount, Date expireTime) {
this.id = id;
this.userInfoId = userInfoId;
this.mileageCount = mileageCount;
this.expireTime = expireTime;
}
}
接口和具体实现类
public interface ISignInService extends IService{ SignIn getMessages(Long userInfoId); void signIn(Long userInfoId, Integer mileage); } public interface IUserMileageReqService extends IService { List mileageDetail(Long userInfoId); List mileageMonthDetail(Long userInfoId); void mileageAdd(Long userInfoId,Long orderInfoId,Integer mileage); void mileageUse(Long userInfoId,Integer mileage); } public interface IUserMileageExpiredService extends IService { void updateMileageList(); }
用户签到
@Service public class SignInServiceImpl extends ServiceImplimplements ISignInService { @Autowired private IUserMileageReqService IUserMileageReqService; @Autowired private UserInfoServiceImpl userInfoService; @Autowired private UserMileageExpiredServiceImpl expiredService; @Autowired private MileageUtil mileageUtil; @Override public SignIn getMessages(Long userInfoId) { SignIn signIn = getSingnIn(userInfoId); if (Objects.isNull(signIn)) { return new SignIn(0, getMileage(userInfoId), 0); } if (mileageUtil.isNowDay(signIn.getUpdateTime())) { signIn.setSigned(0); } signIn.setSigned(1); signIn.setMileageCount(getMileage(userInfoId)); return signIn; } @Override @Transactional(rollbackFor = Exception.class) public void signIn(Long userInfoId, Integer mileage) { SignIn signIn = getSingnIn(userInfoId); if (Objects.isNull(signIn)) { this.save(new SignIn(null, userInfoId, 1, DateUtil.date(), DateUtil.date(), 0)); signIn(userInfoId, mileage, 1); return; } if (!mileageUtil.isNowDay(signIn.getUpdateTime())) { if (mileageUtil.isYesterday(signIn.getUpdateTime())) { signIn(userInfoId, mileage, signIn.getDuration() + 1); return; } signIn(userInfoId, mileage, 1); return; } Asserts.fail("签到失败"); } private void signIn(Long userInfoId, Integer mileage, Integer duration) { LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(); updateWrapper.eq(SignIn::getUserInfoId, userInfoId) .set(SignIn::getCreateTime, DateUtil.date()) .set(SignIn::getDuration, duration); this.update(updateWrapper); expiredService.save(new UserMileageExpired(null, userInfoId, mileage, DateUtil.offset(DateUtil.date(), DateField.YEAR, 1))); IUserMileageReqService.save(new UserMileageReq(null, userInfoId, 0L, 0L, 1, mileage, DateUtil.date(), DateUtil.date(), 0)); updateMileage(userInfoId, getMileage(userInfoId) + mileage); } private void updateMileage(Long userInfoId, Integer mileage) { LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(); updateWrapper.eq(UserInfo::getId, userInfoId) .set(UserInfo::getMileageCount, mileage); userInfoService.update(updateWrapper); } private Integer getMileage(Long userInfoId) { return expiredService.getBaseMapper().getMileage(userInfoId); } private SignIn getSingnIn(Long userInfoId) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(SignIn::getUserInfoId, userInfoId); return this.getOne(queryWrapper); } }
@Service public class UserMileageReqServiceImpl extends ServiceImplimplements IUserMileageReqService { @Autowired private UserMileageExpiredServiceImpl expiredService; @Autowired private MileageUtil mileageUtil; @Autowired private UserMileageReqServiceImpl userMileageReqService; @Override @Transactional(readOnly = true) public List mileageDetail(Long userInfoId) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.ge(UserMileageReq::getCreateTime, DateUtil.beginOfMonth(DateUtil.date())).le(UserMileageReq::getCreateTime, DateUtil.endOfMonth(DateUtil.date())).eq(UserMileageReq::getUserInfoId, userInfoId); return this.list(queryWrapper); } @Override @Transactional(rollbackFor = Exception.class) public List mileageMonthDetail(Long userInfoId) { List months = mileageUtil.months(); DateTime dateTime = DateUtil.offset(DateUtil.beginOfMonth(DateUtil.date()), DateField.YEAR, -1); LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(UserMileageReq::getUserInfoId, userInfoId).ge(UserMileageReq::getCreateTime, dateTime).le(UserMileageReq::getCreateTime, DateUtil.beginOfMonth(DateUtil.date())); List userMileageReqs = this.list(queryWrapper); List list = new ArrayList<>(); for (Date month : months) { MonthDetailVO monthDetail = new MonthDetailVO(month, 0, 0, 0); //创建List集合存储每月信息 for (UserMileageReq userMileageReq : userMileageReqs) { if (DateTime.of(month).month() == DateTime.of(userMileageReq.getCreateTime()).month()) { if (userMileageReq.getType() < 3) { monthDetail.setInputMileage(monthDetail.getInputMileage() + userMileageReq.getMileageCount()); } if (userMileageReq.getType() == 3) { monthDetail.setExpiredMileage(monthDetail.getExpiredMileage() + userMileageReq.getMileageCount()); } if (userMileageReq.getType() == 4) { monthDetail.setOutputMileage(monthDetail.getOutputMileage() + userMileageReq.getMileageCount()); } } } list.add(monthDetail); } return list; } @Override @Transactional(rollbackFor = Exception.class) public void mileageAdd(Long userInfoId, Long orderInfoId, Integer mileage) { expiredService.save(new UserMileageExpired(null, userInfoId, mileage, DateUtil.offset(DateUtil.date(), DateField.YEAR, 1))); userMileageReqService.save(new UserMileageReq(null, userInfoId, orderInfoId, 2, mileage)); } @Override @Transactional(rollbackFor = Exception.class) public void mileageUse(Long userInfoId, Integer mileage) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(UserMileageExpired::getUserInfoId, userInfoId).ge(UserMileageExpired::getDeleted, 0); List list = expiredService.list(queryWrapper); //集合按日期排序 list.sort(Comparator.comparing(UserMileageExpired::getExpireTime)); List expiredList = new ArrayList<>(); Integer mileages = 0; for (UserMileageExpired userMileage : list) { mileages += userMileage.getMileageCount(); userMileage.setDeleted(1); expiredList.add(userMileage); if (mileages == mileage) { expiredService.updateBatchById(expiredList); this.save(new UserMileageReq(userInfoId,4,mileage)); return; } if (mileages > mileage) { expiredService.save(new UserMileageExpired(null, userInfoId, mileages - mileage, userMileage.getExpireTime())); expiredService.updateBatchById(expiredList); this.save(new UserMileageReq(userInfoId,4,mileage)); return; } } Asserts.fail("积分余额不足"); } }
@Service public class UserMileageExpiredServiceImpl extends ServiceImplController层implements IUserMileageExpiredService { @Autowired private UserMileageReqServiceImpl userMileageReqService; @Override @Transactional(rollbackFor = Exception.class) public void updateMileageList() { List allList = this.list(); List expiredList = new ArrayList<>(); List reqList = new ArrayList<>(); for (UserMileageExpired userMileageExpired : allList) { if (userMileageExpired.getExpireTime().before(DateUtil.date())) { userMileageExpired.setDeleted(1); UserMileageReq userMileageReq = new UserMileageReq(userMileageExpired.getUserInfoId(),5,userMileageExpired.getMileageCount()); reqList.add(userMileageReq); expiredList.add(userMileageExpired); } } if (ObjectUtil.isNotNull(expiredList)) { this.updateBatchById(expiredList); userMileageReqService.saveBatch(reqList); return; } Asserts.fail("积分更新失败"); } }
@RestController
@RequestMapping("/user/sign-in")
public class SignInController {
@Autowired
private SignInServiceImpl signInService;
@RequestMapping("/messages")
public CommonResult getMessages(@RequestParam("userInfoId") @NotNull Long userInfoId) {
SignIn signIn = signInService.getMessages(userInfoId);
return CommonResult.success(signIn);
}
@RequestMapping("save")
public CommonResult signIn(@RequestParam("userInfoId") @NotNull Long userInfoId,
@RequestParam("mileage") Integer mileage) {
signInService.signIn(userInfoId, mileage);
return CommonResult.success("签到成功");
}
}
@RestController
@RequestMapping("/user/intergral")
public class MileageController {
@Autowired
private UserMileageReqServiceImpl userMileageReqService;
@Autowired
private UserMileageExpiredServiceImpl userMileageExpiredService;
@RequestMapping("/detail")
public CommonResult mileageDetail(@RequestParam("userInfoId") @NotNull Long userInfoId) {
List userMileageReqs = userMileageReqService.mileageDetail(userInfoId);
return CommonResult.success(userMileageReqs);
}
@RequestMapping("/monthly-summary")
public CommonResult mileageMonthDetail(@RequestParam("userInfoId") @NotNull Long userInfoId) {
List userMileageReqs = userMileageReqService.mileageMonthDetail(userInfoId);
return CommonResult.success(userMileageReqs);
}
@RequestMapping("/mileage-order")
public CommonResult mileageAdd(@RequestParam("orderInfoId") @NotNull Long orderInfoId,
@RequestParam("userInfoId") @NotNull Long userInfoId,
@RequestParam("mileage") Integer mileage) {
userMileageReqService.mileageAdd(userInfoId,orderInfoId,mileage);
return CommonResult.success("积分获取成功");
}
@RequestMapping("/mileage-use")
public CommonResult mileageUse(
@RequestParam("userInfoId") @NotNull Long userInfoId,
@RequestParam("mileage") Integer mileage) {
userMileageReqService.mileageUse(userInfoId,mileage);
return CommonResult.success("积分使用成功");
}
}
其中用的主要是Springboot+MybatisPlus核心技术,然后引用hutool工具包来简化代码的开发。大家觉得好用可以点赞收藏一下,整理总结发布不易。



