我在最近做了一个微服务项目,说是微服务项目,但其实核心技术还是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;
/**
* 用户账号编号(消费者);关联user主表id字段,n vs 1
*/
@JsonIgnore
private Long userInfoId;
/**
* 优惠券编号(积分兑换优惠券);关联discount_coupon主表id字段,1 vs 1
*/
@JsonIgnore
private Long discountCouponId;
/**
* 订单账号编号(积分订单抵现);关联order主表id字段,1 vs 1
*/
@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;
/**
* 逻辑删除;单选:0-未删除,1-删除,默认值:0
*/
@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;
/**
* 用户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 ;
/** 用户id */
@NotNull
private Long userInfoId ;
/** 积分数量 */
private Integer mileageCount ;
/** 过期时间 */
private Date expireTime ;
/** 创建时间 */
private Date createTime ;
/** 更新时间 */
private Date updateTime ;
/** 是否删除;0-否,1-是 */
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> {
/**
* 获取用户签到信息
*
* @param userInfoId
* @return
*/
SignIn getMessages(Long userInfoId);
/**
* * 用户签到操作
*
* @param userInfoId
* @param mileage
* @return
*/
void signIn(Long userInfoId, Integer mileage);
}
public interface IUserMileageReqService extends IService<UserMileageReq> {
/**
* 用户积分流水
*
* @param userInfoId
* @return
*/
List<UserMileageReq> mileageDetail(Long userInfoId);
/**
* 用户积分月度流水
*
* @param userInfoId
* @return
*/
List mileageMonthDetail(Long userInfoId);
/**
* 获得积分
* @param userInfoId
* @param orderInfoId
* @param mileage
*/
void mileageAdd(Long userInfoId,Long orderInfoId,Integer mileage);
/**
* 用户积分使用
* @param userInfoId
* @param mileage
*/
void mileageUse(Long userInfoId,Integer mileage);
}
public interface IUserMileageExpiredService extends IService<UserMileageExpired> {
/**
* 过期里程批量更新
*/
void updateMileageList();
}
?用户签到
@Service
public class SignInServiceImpl extends ServiceImpl<SignInDAO, SignIn> implements ISignInService {
@Autowired
private IUserMileageReqService IUserMileageReqService;
@Autowired
private UserInfoServiceImpl userInfoService;
@Autowired
private UserMileageExpiredServiceImpl expiredService;
@Autowired
private MileageUtil mileageUtil;
/**
* 用户签到信息获取
*
* @param userInfoId
* @return
*/
@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;
}
/**
* 用户签到
*
* @param userInfoId
* @param mileage
* @return
*/
@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("签到失败");
}
/**
* 保存签到信息
*
* @param userInfoId
* @param mileage
* @param duration
* @return
*/
private void signIn(Long userInfoId, Integer mileage, Integer duration) {
LambdaUpdateWrapper<SignIn> 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);
}
/**
* 更新用户积分
*
* @param userInfoId
* @param mileage
* @return
*/
private void updateMileage(Long userInfoId, Integer mileage) {
LambdaUpdateWrapper<UserInfo> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(UserInfo::getId, userInfoId)
.set(UserInfo::getMileageCount, mileage);
userInfoService.update(updateWrapper);
}
/**
* 查询用户里程数量
*
* @param userInfoId
* @return
*/
private Integer getMileage(Long userInfoId) {
return expiredService.getBaseMapper().getMileage(userInfoId);
}
/**
* 根据UserInfoId查询用户签到信息
*
* @param userInfoId
* @return SignIn
*/
private SignIn getSingnIn(Long userInfoId) {
LambdaQueryWrapper<SignIn> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SignIn::getUserInfoId, userInfoId);
return this.getOne(queryWrapper);
}
}
@Service
public class UserMileageReqServiceImpl extends ServiceImpl<UserMileageReqDAO, UserMileageReq> implements IUserMileageReqService {
@Autowired
private UserMileageExpiredServiceImpl expiredService;
@Autowired
private MileageUtil mileageUtil;
@Autowired
private UserMileageReqServiceImpl userMileageReqService;
/**
* 用户月度积分流水
*
* @param userInfoId
* @return
*/
@Override
@Transactional(readOnly = true)
public List<UserMileageReq> mileageDetail(Long userInfoId) {
LambdaQueryWrapper<UserMileageReq> 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);
}
/**
* 用户年度积分流水
*
* @param userInfoId
* @return
*/
@Override
@Transactional(rollbackFor = Exception.class)
public List mileageMonthDetail(Long userInfoId) {
List<Date> months = mileageUtil.months();
DateTime dateTime = DateUtil.offset(DateUtil.beginOfMonth(DateUtil.date()), DateField.YEAR, -1);
LambdaQueryWrapper<UserMileageReq> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(UserMileageReq::getUserInfoId, userInfoId).ge(UserMileageReq::getCreateTime, dateTime).le(UserMileageReq::getCreateTime, DateUtil.beginOfMonth(DateUtil.date()));
List<UserMileageReq> userMileageReqs = this.list(queryWrapper);
List<MonthDetailVO> 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;
}
/**
* 获得积分
*
* @param userInfoId
* @param orderInfoId
* @param mileage
*/
@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));
}
/**
* 用户积分使用
*
* @param userInfoId
* @param mileage
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void mileageUse(Long userInfoId, Integer mileage) {
LambdaQueryWrapper<UserMileageExpired> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(UserMileageExpired::getUserInfoId, userInfoId).ge(UserMileageExpired::getDeleted, 0);
List<UserMileageExpired> list = expiredService.list(queryWrapper);
//集合按日期排序
list.sort(Comparator.comparing(UserMileageExpired::getExpireTime));
List<UserMileageExpired> 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 ServiceImpl<UserMileageExpiredDAO, UserMileageExpired> implements IUserMileageExpiredService {
/**
* 过期里程批量更新
*/
@Autowired
private UserMileageReqServiceImpl userMileageReqService;
@Override
@Transactional(rollbackFor = Exception.class)
public void updateMileageList() {
List<UserMileageExpired> allList = this.list();
List<UserMileageExpired> expiredList = new ArrayList<>();
List<UserMileageReq> 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("积分更新失败");
}
}
?Controller层
@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<UserMileageReq> 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工具包来简化代码的开发。大家觉得好用可以点赞收藏一下,整理总结发布不易。
|