Compare commits
3 Commits
5129b79a3f
...
24cbd183de
Author | SHA1 | Date | |
---|---|---|---|
24cbd183de | |||
28bb3fd5d5 | |||
7eba424661 |
12
api/pom.xml
12
api/pom.xml
@ -82,6 +82,18 @@
|
||||
<artifactId>bcprov-jdk15on</artifactId>
|
||||
<version>1.57</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-spring-boot-starter</artifactId>
|
||||
<version>1.33.0</version>
|
||||
</dependency>
|
||||
<!-- Sa-Token 整合 Redis (使用 jackson 序列化方式) -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-dao-redis-jackson</artifactId>
|
||||
<version>1.33.0</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
@ -0,0 +1,22 @@
|
||||
package me.xiaoyan.point.api.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
@Configuration
|
||||
public class ApplicationConfig implements WebMvcConfigurer {
|
||||
|
||||
// 跨域 目前小程序不需要,暂时不用考虑
|
||||
// @Override
|
||||
// public void addCorsMappings(CorsRegistry registry) {
|
||||
// registry.addMapping("/**").allowedOrigins("*");
|
||||
// }
|
||||
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
|
||||
}
|
||||
}
|
@ -10,6 +10,7 @@ public class MybatisPlusConfig {
|
||||
@Bean
|
||||
public MybatisPlusInterceptor paginationInterceptor() {
|
||||
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
|
||||
// 添加分页插件
|
||||
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
|
||||
return interceptor;
|
||||
}
|
||||
|
104
api/src/main/java/me/xiaoyan/point/api/config/RedisConfig.java
Normal file
104
api/src/main/java/me/xiaoyan/point/api/config/RedisConfig.java
Normal file
@ -0,0 +1,104 @@
|
||||
package me.xiaoyan.point.api.config;
|
||||
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.*;
|
||||
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
|
||||
//redis配置类
|
||||
@Configuration
|
||||
public class RedisConfig {
|
||||
@Bean
|
||||
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
|
||||
|
||||
RedisTemplate<String, Object> template = new RedisTemplate<>();
|
||||
// 配置连接工厂
|
||||
template.setConnectionFactory(factory);
|
||||
|
||||
//使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
|
||||
Jackson2JsonRedisSerializer jackson = new Jackson2JsonRedisSerializer(Object.class);
|
||||
|
||||
ObjectMapper om = new ObjectMapper();
|
||||
// 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
|
||||
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
|
||||
// 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
|
||||
//om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
|
||||
om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
|
||||
jackson.setObjectMapper(om);
|
||||
|
||||
// 值采用json序列化
|
||||
template.setValueSerializer(jackson);
|
||||
//使用StringRedisSerializer来序列化和反序列化redis的key值
|
||||
template.setKeySerializer(new StringRedisSerializer());
|
||||
|
||||
// 设置hash key 和value序列化模式
|
||||
template.setHashKeySerializer(new StringRedisSerializer());
|
||||
template.setHashValueSerializer(jackson);
|
||||
template.afterPropertiesSet();
|
||||
|
||||
return template;
|
||||
}
|
||||
|
||||
/**
|
||||
* 对hash类型的数据操作
|
||||
*
|
||||
* @param redisTemplate
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {
|
||||
return redisTemplate.opsForHash();
|
||||
}
|
||||
|
||||
/**
|
||||
* 对redis字符串类型数据操作
|
||||
*
|
||||
* @param redisTemplate
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public ValueOperations<String, Object> valueOperations(RedisTemplate<String, Object> redisTemplate) {
|
||||
return redisTemplate.opsForValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 对链表类型的数据操作
|
||||
*
|
||||
* @param redisTemplate
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {
|
||||
return redisTemplate.opsForList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 对无序集合类型的数据操作
|
||||
*
|
||||
* @param redisTemplate
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {
|
||||
return redisTemplate.opsForSet();
|
||||
}
|
||||
|
||||
/**
|
||||
* 对有序集合类型的数据操作
|
||||
*
|
||||
* @param redisTemplate
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) {
|
||||
return redisTemplate.opsForZSet();
|
||||
}
|
||||
|
||||
}
|
@ -27,7 +27,7 @@ public class SwaggerConfiguration {
|
||||
// 创建api文档信息
|
||||
@Bean
|
||||
public Docket createRestApi() {
|
||||
return new Docket(DocumentationType.SWAGGER_2)
|
||||
return new Docket(DocumentationType.OAS_30)
|
||||
.apiInfo(apiInfo())
|
||||
.select()
|
||||
.apis(RequestHandlerSelectors.basePackage("me.xiaoyan.point.api.controller"))
|
||||
|
@ -0,0 +1,23 @@
|
||||
package me.xiaoyan.point.api.controller;
|
||||
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import me.xiaoyan.point.api.pojo.PointRecord;
|
||||
import me.xiaoyan.point.api.pojo.vo.PageParam;
|
||||
import me.xiaoyan.point.api.service.PointRecordService;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("point")
|
||||
public class PointController {
|
||||
@Resource
|
||||
private PointRecordService pointRecordService;
|
||||
public IPage<PointRecord> list(@RequestBody PageParam param){
|
||||
return pointRecordService.histories(StpUtil.getLoginIdAsInt(),param);
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package me.xiaoyan.point.api.controller;
|
||||
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import me.xiaoyan.point.api.pojo.vo.SignResult;
|
||||
import me.xiaoyan.point.api.service.SignRecordService;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("sign")
|
||||
public class SignController {
|
||||
|
||||
@Resource
|
||||
private SignRecordService signRecordService;
|
||||
|
||||
@ApiOperation("今日签到")
|
||||
@RequestMapping("today")
|
||||
public SignResult signToday() {
|
||||
return signRecordService.signToday(StpUtil.getLoginIdAsInt());
|
||||
}
|
||||
|
||||
@ApiOperation("签到信息")
|
||||
@RequestMapping("info")
|
||||
public SignResult signInfo() {
|
||||
return signRecordService.info(StpUtil.getLoginIdAsInt());
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
package me.xiaoyan.point.api.controller;
|
||||
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.SneakyThrows;
|
||||
import me.xiaoyan.point.api.pojo.UserInfo;
|
||||
import me.xiaoyan.point.api.pojo.vo.SignResult;
|
||||
import me.xiaoyan.point.api.pojo.vo.UserLoginData;
|
||||
import me.xiaoyan.point.api.service.UserInfoService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("user")
|
||||
public class UserinfoController {
|
||||
@Resource
|
||||
private UserInfoService userInfoService;
|
||||
|
||||
// code => openid等信息
|
||||
// 使用wx.login获取到的code进行登录,完成登录后下发用户登录凭证
|
||||
@ApiOperation("登录")
|
||||
@PostMapping("login")
|
||||
@SneakyThrows
|
||||
public String login(@Validated @RequestBody UserLoginData data) {
|
||||
//@NotNull(message = "登录code不能为空")
|
||||
UserInfo info = userInfoService.login(data);
|
||||
// 完成登录
|
||||
StpUtil.login(info.getId());
|
||||
// 可以考虑将用户信息保存到sa-token
|
||||
// StpUtil.getSession().set("userinfo",info);
|
||||
return StpUtil.getTokenInfo().getTokenValue();
|
||||
}
|
||||
|
||||
@ApiOperation("获取登录用户的基本信息")
|
||||
@RequestMapping("info")
|
||||
public UserInfo getInfo() {
|
||||
int uid = StpUtil.getLoginIdAsInt();
|
||||
return userInfoService.getInfoById(uid);
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
package me.xiaoyan.point.api.controller;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import me.xiaoyan.point.api.pojo.UserInfo;
|
||||
import me.xiaoyan.point.api.pojo.vo.UserLoginData;
|
||||
import me.xiaoyan.point.api.service.UserInfoService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@RestController
|
||||
public class WechatController {
|
||||
@Resource
|
||||
private UserInfoService userInfoService;
|
||||
|
||||
// code => openid等信息
|
||||
// 使用wx.login获取到的code进行登录,完成登录后下发用户登录凭证
|
||||
@RequestMapping("/wechat/login")
|
||||
@SneakyThrows
|
||||
public UserInfo login(@Validated @RequestBody UserLoginData data) {
|
||||
//@NotNull(message = "登录code不能为空")
|
||||
|
||||
return userInfoService.login(data);
|
||||
}
|
||||
}
|
@ -1,10 +1,14 @@
|
||||
package me.xiaoyan.point.api.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import me.xiaoyan.point.api.pojo.Point;
|
||||
import me.xiaoyan.point.api.pojo.SignRecord;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface SignRecordMapper extends BaseMapper<SignRecord> {
|
||||
public int signCountByDate(@Param("uid") int uid, @Param("date") String date);
|
||||
public List<SignRecord> selectRecentDaysRecord(@Param("uid") int uid,@Param("limit")int limit);
|
||||
}
|
||||
|
@ -2,21 +2,26 @@ package me.xiaoyan.point.api.pojo;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class Point implements Serializable {
|
||||
@TableId(type = IdType.NONE)
|
||||
private Integer uid;
|
||||
private Integer totalPoint;
|
||||
private Integer validPoint;
|
||||
private Integer expirePoint;
|
||||
private Integer expireTime;
|
||||
private Integer updateTime;
|
||||
private Date expireTime;
|
||||
private Date updateTime;
|
||||
}
|
||||
|
@ -3,8 +3,10 @@ package me.xiaoyan.point.api.pojo;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
@ -13,6 +15,8 @@ import java.util.Date;
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@TableName("point_record")
|
||||
public class PointRecord implements Serializable {
|
||||
@TableId(type = IdType.AUTO)
|
||||
|
@ -2,8 +2,10 @@ package me.xiaoyan.point.api.pojo;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
@ -11,7 +13,9 @@ import java.util.Date;
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Builder
|
||||
@Builder // 如果有builder就需要设置 @NoArgsConstructor @AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class SignRecord implements Serializable {
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Integer id;
|
||||
|
@ -1,10 +1,13 @@
|
||||
package me.xiaoyan.point.api.pojo;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
@ -13,6 +16,8 @@ import java.util.Date;
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@TableName("userinfo")
|
||||
public class UserInfo implements Serializable {
|
||||
/**
|
||||
@ -57,4 +62,6 @@ public class UserInfo implements Serializable {
|
||||
* 状态
|
||||
*/
|
||||
private Integer status;
|
||||
@TableField(exist = false)
|
||||
private Point pointInfo;
|
||||
}
|
||||
|
@ -0,0 +1,22 @@
|
||||
package me.xiaoyan.point.api.pojo.vo;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Accessors(chain = true)
|
||||
@Builder
|
||||
public class PageParam {
|
||||
private Integer page;
|
||||
private Integer pageSize = 20;
|
||||
|
||||
public Page getPage(){
|
||||
return new Page().setCurrent(page).setSize(pageSize);
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package me.xiaoyan.point.api.pojo.vo;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@Accessors(chain = true)
|
||||
public class SignResult {
|
||||
/**
|
||||
* 今日是否已经签到
|
||||
*/
|
||||
private boolean signToday;
|
||||
/**
|
||||
* 连续签到天数
|
||||
*/
|
||||
private int continuousDays;
|
||||
}
|
@ -3,6 +3,7 @@ package me.xiaoyan.point.api.pojo.vo;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@ -13,4 +14,8 @@ public class UserLoginData implements Serializable {
|
||||
private String iv;
|
||||
@NotEmpty(message = "code参数不能为空")
|
||||
private String code;
|
||||
/**
|
||||
* 推荐用户id
|
||||
*/
|
||||
private int recommend;
|
||||
}
|
||||
|
@ -1,8 +1,12 @@
|
||||
package me.xiaoyan.point.api.service;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import me.xiaoyan.point.api.pojo.PointRecord;
|
||||
import me.xiaoyan.point.api.pojo.UserInfo;
|
||||
import me.xiaoyan.point.api.pojo.vo.PageParam;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface PointRecordService extends IService<PointRecord> {
|
||||
/**
|
||||
@ -13,4 +17,8 @@ public interface PointRecordService extends IService<PointRecord> {
|
||||
* @return
|
||||
*/
|
||||
public PointRecord record(Integer uid,Integer point,String reason);
|
||||
|
||||
IPage<PointRecord> histories(Integer uid, PageParam param);
|
||||
IPage<PointRecord> exchangeHistories(Integer uid, PageParam param);
|
||||
|
||||
}
|
||||
|
@ -3,7 +3,20 @@ package me.xiaoyan.point.api.service;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import me.xiaoyan.point.api.pojo.SignRecord;
|
||||
import me.xiaoyan.point.api.pojo.UserInfo;
|
||||
import me.xiaoyan.point.api.pojo.vo.SignResult;
|
||||
|
||||
public interface SignRecordService extends IService<SignRecord> {
|
||||
/**
|
||||
* 今日是否签到
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public SignResult signToday(int uid);
|
||||
|
||||
/**
|
||||
* 签到信息
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public SignResult info(int uid);
|
||||
}
|
||||
|
@ -12,4 +12,6 @@ public interface UserInfoService extends IService<UserInfo> {
|
||||
* @return
|
||||
*/
|
||||
public UserInfo login(UserLoginData data);
|
||||
|
||||
UserInfo getInfoById(Integer uid);
|
||||
}
|
||||
|
@ -1,16 +1,20 @@
|
||||
package me.xiaoyan.point.api.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import me.xiaoyan.point.api.error.BizException;
|
||||
import me.xiaoyan.point.api.mapper.PointRecordMapper;
|
||||
import me.xiaoyan.point.api.pojo.Point;
|
||||
import me.xiaoyan.point.api.pojo.PointRecord;
|
||||
import me.xiaoyan.point.api.pojo.vo.PageParam;
|
||||
import me.xiaoyan.point.api.service.PointRecordService;
|
||||
import me.xiaoyan.point.api.service.PointService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class PointRecordServiceImpl extends ServiceImpl<PointRecordMapper, PointRecord>
|
||||
@ -43,4 +47,20 @@ public class PointRecordServiceImpl extends ServiceImpl<PointRecordMapper, Point
|
||||
this.save(record);
|
||||
return record;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPage<PointRecord> histories(Integer uid, PageParam param) {
|
||||
QueryWrapper<PointRecord> q = new QueryWrapper();
|
||||
q.eq("uid",uid);
|
||||
this.getBaseMapper().selectPage(param.getPage(), q);
|
||||
return null;
|
||||
}
|
||||
|
||||
public IPage<PointRecord> exchangeHistories(Integer uid, PageParam param) {
|
||||
QueryWrapper<PointRecord> q = new QueryWrapper();
|
||||
q.eq("uid",uid);
|
||||
q.lt("point",0);
|
||||
this.getBaseMapper().selectPage(param.getPage(), q);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,77 @@
|
||||
package me.xiaoyan.point.api.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import me.xiaoyan.point.api.error.BizException;
|
||||
import me.xiaoyan.point.api.mapper.SignRecordMapper;
|
||||
import me.xiaoyan.point.api.pojo.SignRecord;
|
||||
import me.xiaoyan.point.api.pojo.vo.SignResult;
|
||||
import me.xiaoyan.point.api.service.PointRecordService;
|
||||
import me.xiaoyan.point.api.service.SignRecordService;
|
||||
import me.xiaoyan.point.api.util.DateUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.*;
|
||||
|
||||
@Service
|
||||
public class SignRecordServiceImpl extends ServiceImpl<SignRecordMapper, SignRecord>
|
||||
implements SignRecordService {
|
||||
|
||||
@Resource
|
||||
private PointRecordService pointRecordService;
|
||||
|
||||
public boolean todayIsSign(int uid) {
|
||||
return this.getBaseMapper().signCountByDate(uid, DateUtils.today()) > 0;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public SignResult signToday(int uid) {
|
||||
if (todayIsSign(uid)) throw BizException.create("今日已经签过了");
|
||||
// 计算连续的签到天数 连续签到积分的公式 = 天数 * 5
|
||||
int days = continuousDays(uid, true);
|
||||
// TODO 完成签到
|
||||
SignRecord record = SignRecord.builder()
|
||||
.uid(uid)
|
||||
.point(5 * days)
|
||||
.build();
|
||||
pointRecordService.record(uid, 5 * days, "签到" + days + "天,获得积分");
|
||||
save(record);
|
||||
// 封装签到信息
|
||||
return SignResult.builder()
|
||||
.signToday(true)
|
||||
.continuousDays(days)
|
||||
.build();
|
||||
}
|
||||
|
||||
public int continuousDays(int uid, boolean isSign) {
|
||||
// 如果是签到数据则只查6天,否则查询7天
|
||||
final List<SignRecord> signRecords = this.getBaseMapper().selectRecentDaysRecord(uid, isSign ? 6 : 7);
|
||||
List<Date> dates = new ArrayList<>();
|
||||
if (isSign) {
|
||||
dates.add(new Date());
|
||||
}else{
|
||||
// 没有记录直接返回0
|
||||
if(signRecords.size() == 0) return 0;
|
||||
Date firstDate = signRecords.get(0).getCreateTime();
|
||||
// 第一个记录是否是今天
|
||||
if(!DateUtils.isToday(firstDate) && !DateUtils.isYesterday(firstDate)){
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
signRecords.forEach(it -> dates.add(it.getCreateTime()));
|
||||
Date[] dateArr = new Date[dates.size()];
|
||||
return DateUtils.continuousDays(dates.toArray(dateArr));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignResult info(int uid) {
|
||||
return SignResult.builder()
|
||||
.signToday(todayIsSign(uid)) // 今天是否签到
|
||||
.continuousDays(continuousDays(uid, false))
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.Serializable;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
@ -53,7 +54,20 @@ public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo>
|
||||
@Resource
|
||||
private PointRecordService pointRecordService;
|
||||
|
||||
public void firstLogin(UserInfo info) {
|
||||
public void firstLogin(UserInfo info, int recommendUid) {
|
||||
if (recommendUid > 0) {
|
||||
// 判断推荐者是否存在
|
||||
if (this.getById(recommendUid) != null) {
|
||||
// 存在则设置后续操作
|
||||
info.setParentId(recommendUid);
|
||||
// 增加推荐积分
|
||||
pointRecordService.record(
|
||||
recommendUid,
|
||||
recommendPoint,
|
||||
"推荐新用户"
|
||||
);
|
||||
}
|
||||
}
|
||||
// 先新增用户基本信息
|
||||
save(info);
|
||||
// 新增积分信息
|
||||
@ -90,7 +104,7 @@ public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo>
|
||||
userInfo = wechatUserInfo.getUserinfo().setOpenId(sessionData.getOpenid());
|
||||
//
|
||||
// 不存在走 第一次登录流程
|
||||
firstLogin(userInfo);
|
||||
firstLogin(userInfo, data.getRecommend());
|
||||
}
|
||||
// 首先
|
||||
return userInfo;
|
||||
@ -126,4 +140,12 @@ public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo>
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
public UserInfo getInfoById(Integer id) {
|
||||
final UserInfo userinfo = getById(id);
|
||||
if (userinfo != null) {
|
||||
userinfo.setPointInfo(pointService.getById(userinfo.getId()));
|
||||
}
|
||||
return userinfo;
|
||||
}
|
||||
}
|
||||
|
77
api/src/main/java/me/xiaoyan/point/api/util/DateUtils.java
Normal file
77
api/src/main/java/me/xiaoyan/point/api/util/DateUtils.java
Normal file
@ -0,0 +1,77 @@
|
||||
package me.xiaoyan.point.api.util;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
public class DateUtils {
|
||||
private final static SimpleDateFormat full = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
private final static SimpleDateFormat date = new SimpleDateFormat("yyyy-MM-dd");
|
||||
|
||||
public static String today() {
|
||||
return date.format(new Date());
|
||||
}
|
||||
|
||||
public static String now() {
|
||||
return full.format(new Date());
|
||||
}
|
||||
|
||||
public static String formatDate(Date d) {
|
||||
return date.format(d);
|
||||
}
|
||||
|
||||
public static String formatDatetime(Date d) {
|
||||
return full.format(d);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public static Date parse(String str) {
|
||||
return full.parse(str);
|
||||
}
|
||||
|
||||
public static int continuousDays(Date[] dates) {
|
||||
if(dates.length == 0){
|
||||
return 0;
|
||||
}
|
||||
int totalDays = 1;
|
||||
for (int i = 1;i < dates.length; i ++){
|
||||
Date d1 = dates[i-1];
|
||||
Date d2 = dates[i];
|
||||
if(!isBetween(d1,d2)){
|
||||
break;
|
||||
}
|
||||
totalDays ++;
|
||||
}
|
||||
return totalDays;
|
||||
}
|
||||
|
||||
public static boolean isToday(String d){
|
||||
try {
|
||||
return isToday(full.parse(d));
|
||||
} catch (ParseException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public static boolean isToday(Date d){
|
||||
if(d == null) return false;
|
||||
return today().equalsIgnoreCase(formatDate(d));
|
||||
}
|
||||
|
||||
public static boolean isYesterday(Date d){
|
||||
if(d == null) return false;
|
||||
Date today = new Date(); // 今天
|
||||
if(today.getTime() < d.getTime()) return false;
|
||||
return isBetween(today,d);
|
||||
}
|
||||
|
||||
public static boolean isBetween(Date d1,Date d2){
|
||||
// 直接获取两个日期之间的毫秒,计算
|
||||
Date date1 = parse(formatDate(d1) + " 00:00:00");
|
||||
Date date2 = parse(formatDate(d2) + " 00:00:00");
|
||||
// 两个日期之间相差的毫秒数
|
||||
long diffTimes = Math.abs(date1.getTime() - date2.getTime());
|
||||
return diffTimes <= 24 * 3600 * 1000;
|
||||
}
|
||||
}
|
@ -8,6 +8,8 @@ application:
|
||||
first_login: 200
|
||||
recommend: 100
|
||||
spring:
|
||||
profiles:
|
||||
active: dev
|
||||
application:
|
||||
name: point_api
|
||||
datasource:
|
||||
@ -51,4 +53,21 @@ mybatis-plus:
|
||||
configuration:
|
||||
# 日志接口
|
||||
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
||||
cache-enabled: true
|
||||
cache-enabled: true
|
||||
|
||||
############## Sa-Token 配置 (文档: https://sa-token.cc) ##############
|
||||
sa-token:
|
||||
# token名称 (同时也是cookie名称)
|
||||
token-name: token
|
||||
# token有效期,单位s 默认30天, -1代表永不过期
|
||||
timeout: -1
|
||||
# token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒
|
||||
activity-timeout: -1
|
||||
# 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
|
||||
is-concurrent: true
|
||||
# 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
|
||||
is-share: false
|
||||
# token风格
|
||||
token-style: uuid
|
||||
# 是否输出操作日志
|
||||
is-log: true
|
BIN
api/src/main/resources/docs/每日签到.jpg
Normal file
BIN
api/src/main/resources/docs/每日签到.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 230 KiB |
18
api/src/main/resources/mapper/SignRecordMapper.xml
Normal file
18
api/src/main/resources/mapper/SignRecordMapper.xml
Normal file
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||
<mapper namespace="me.xiaoyan.point.api.mapper.SignRecordMapper">
|
||||
<select id="signCountByDate" resultType="java.lang.Integer">
|
||||
select count(*)
|
||||
from points_sys.sign_record
|
||||
where date(create_time) = #{date}
|
||||
and uid = #{uid}
|
||||
</select>
|
||||
<select id="selectRecentDaysRecord" resultType="me.xiaoyan.point.api.pojo.SignRecord">
|
||||
select *
|
||||
from points_sys.sign_record
|
||||
where date(create_time) >= date_sub(curdate(), interval 7 day)
|
||||
and uid = #{uid}
|
||||
order by create_time desc
|
||||
limit #{limit};
|
||||
</select>
|
||||
</mapper>
|
38
api/src/test/java/me/xiaoyan/point/api/DateTests.java
Normal file
38
api/src/test/java/me/xiaoyan/point/api/DateTests.java
Normal file
@ -0,0 +1,38 @@
|
||||
package me.xiaoyan.point.api;
|
||||
|
||||
import me.xiaoyan.point.api.util.DateUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class DateTests {
|
||||
@Test
|
||||
void testBetween() {
|
||||
Date d1 = DateUtils.parse("2022-11-21 12:12:12");
|
||||
Date d2 = DateUtils.parse("2022-11-20 11:11:11");
|
||||
Date d3 = DateUtils.parse("2022-11-22 11:11:11");
|
||||
Assert.isTrue(
|
||||
DateUtils.isBetween(d1, d2), "不是相邻的"
|
||||
);
|
||||
Assert.isTrue(
|
||||
!DateUtils.isBetween(d3, d2), "是相邻的"
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testContinuousDays() {
|
||||
Date d1 = DateUtils.parse("2022-11-22 12:12:12");
|
||||
Date d2 = DateUtils.parse("2022-11-21 11:11:11");
|
||||
Date d3 = DateUtils.parse("2022-11-20 11:11:11");
|
||||
Date d4 = DateUtils.parse("2022-11-18 11:11:11");
|
||||
Date d5 = DateUtils.parse("2022-11-17 11:11:11");
|
||||
// 连续天数
|
||||
int days = DateUtils.continuousDays(
|
||||
new Date[]{d1, d2, d3, d4, d5}
|
||||
);
|
||||
System.out.println("连续天数" + days);
|
||||
Assert.isTrue(days == 3, "连续天数不正确");
|
||||
|
||||
}
|
||||
}
|
@ -11,16 +11,21 @@ public class WechatTests {
|
||||
@DisplayName("解密用户信息")
|
||||
@Test
|
||||
void testDecode(){
|
||||
String encryptedData = "Ezl1S3BHjBeg/HP0Nim/c9eLLYP5L1kgvqSpR+RQYFG6c3Qx0K5U6btEY5IByCw1OsnZ0hKDccNJn3VA/ZgpkxjDODt+XLcph3KqEL6LDU9BLDRFxCI7u+eHBorz5HWYzGITXiuyPb9NWmGAPXwwp0abFqqaycb5u4oii7I/tnh7NIRIcMxAft1YfbVdzQDjraRHFH5hg6Eh4RGSjy6rg1bG/sMecw4+XWM1psTjKBYNwtsG5oxBWja6DniPhmWU6ZwjVMfgJX5Z7wcw2vtmuDPOMCEE1SEcwmTcQ5YKLlPsPBAJhrF3Lxg9oTD1/IlZ";
|
||||
String iv = "ckSRPBLA61WONzUDINIWMg==";
|
||||
|
||||
// String encryptedData = "Ezl1S3BHjBeg/HP0Nim/c9eLLYP5L1kgvqSpR+RQYFG6c3Qx0K5U6btEY5IByCw1OsnZ0hKDccNJn3VA/ZgpkxjDODt+XLcph3KqEL6LDU9BLDRFxCI7u+eHBorz5HWYzGITXiuyPb9NWmGAPXwwp0abFqqaycb5u4oii7I/tnh7NIRIcMxAft1YfbVdzQDjraRHFH5hg6Eh4RGSjy6rg1bG/sMecw4+XWM1psTjKBYNwtsG5oxBWja6DniPhmWU6ZwjVMfgJX5Z7wcw2vtmuDPOMCEE1SEcwmTcQ5YKLlPsPBAJhrF3Lxg9oTD1/IlZ";
|
||||
// String iv = "ckSRPBLA61WONzUDINIWMg==";
|
||||
String sessionKey= "091WPNkl23zoha4xbpnl2cev9l4WPNk7";
|
||||
String encryptedData = "3mmRZjsqy3Tpgw78jm7HNB3n6/pb8nX9jS1GgngV4tHGSe+yhKIXy7u7kxXz7nKS5lwNqt+UQCXF3EHHd1PQJowtpYWNhLBjNZcGjEdIi6a5pxntmwmFsjTX+SjPNmq5Th4iKSwSyMjLIByZqJt7N3hB5OyT5YAo54lsJrln8DJoPE1m6kddHcLqnJy+g12QQTP1u3tFvCEostrCpb109Bhe889wAxm55ekPHTQ+JWYCsPy0TsjmyvqZCQZyB+RNtlW/ohCpLe4oCOF0Nz9Id6N+Kj6bXvgDcEMBf3vwMXSnbWHuqJAuLUWwbsspB/2T";
|
||||
String iv = "qfrpHwHjjqPQVlzzxE9D1A==";
|
||||
// sessionKey= "PKX9EeH6y+pzz8qYrga2jQ==";
|
||||
// encryptedData = "SCK0Ik7THl+USkwTRqTQ9BYGe6rWlXosQ8fWA3I3AsFHTCuPnjbsjFooIEZVcS6mq911XeP5BJJBpPU6A1O3aNuC9L7ebXqTMQX83bVBtaDQySvCIlyyq26xhm8AbWWexl5994NJDpKkNml9ilbYia99bF8bXzXvLCksQQkz82EpZTqztzmCrTdFBZOIrJ+lDnl7rSBWJvVVtoagzgSq2Ux59LcJtxCukIUoZ8fz54//Hm4GhrLucO4zPKTi087f77Pd9K9Rz3LLJ79NMQHHQLtZ38Ws79IKoHBZ7xHXbl3O8xPeTBrrWeHbNfNs1CbOyoe0RwXVjs/fMR9451PeLVM5jg4fj3IDyTFjpx5aUzQRaIrSY/BjVFJoxU/viwQC6LsCBOyXl5uV5h+qIPC5suFbmhl5Q56eU07wbOjNxktEIJsIgbrT+GWRZVPba3dUo+6RoZySxCMA16TRKfuTwjXceV3oNueFdTNyw05s9N43OkrLeKcz1dFeNnpA9DHEVngB1J7MY4RkazdKaWzrld1DjxW6+rk01GgtAr3+H88=";
|
||||
// iv = "Ql/m+Ksll5ziCCZj+07J6g==";
|
||||
|
||||
WechatUserInfo wechatUserInfo = WechatDecryptDataUtil.decryptData(
|
||||
"SCK0Ik7THl+USkwTRqTQ9BYGe6rWlXosQ8fWA3I3AsFHTCuPnjbsjFooIEZVcS6mq911XeP5BJJBpPU6A1O3aNuC9L7ebXqTMQX83bVBtaDQySvCIlyyq26xhm8AbWWexl5994NJDpKkNml9ilbYia99bF8bXzXvLCksQQkz82EpZTqztzmCrTdFBZOIrJ+lDnl7rSBWJvVVtoagzgSq2Ux59LcJtxCukIUoZ8fz54//Hm4GhrLucO4zPKTi087f77Pd9K9Rz3LLJ79NMQHHQLtZ38Ws79IKoHBZ7xHXbl3O8xPeTBrrWeHbNfNs1CbOyoe0RwXVjs/fMR9451PeLVM5jg4fj3IDyTFjpx5aUzQRaIrSY/BjVFJoxU/viwQC6LsCBOyXl5uV5h+qIPC5suFbmhl5Q56eU07wbOjNxktEIJsIgbrT+GWRZVPba3dUo+6RoZySxCMA16TRKfuTwjXceV3oNueFdTNyw05s9N43OkrLeKcz1dFeNnpA9DHEVngB1J7MY4RkazdKaWzrld1DjxW6+rk01GgtAr3+H88=",
|
||||
"PKX9EeH6y+pzz8qYrga2jQ==",
|
||||
"Ql/m+Ksll5ziCCZj+07J6g=="
|
||||
encryptedData,
|
||||
sessionKey,
|
||||
iv
|
||||
|
||||
);
|
||||
System.out.println(wechatUserInfo);
|
||||
// System.out.println(wechatUserInfo);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user