Commit 17e1a095 authored by tangtuo's avatar tangtuo

后台管理系统新增用户统计概览 用户列表等接口

门户系统新增生成nft编号 文件md5值等接口
parent 0a3f1b93
**乐映影视:**
项目主要采用的框架是spring-boot mybatis-plus sa-token 等, 数据库采用的是mysql,缓存用的是redis
项目主要分为三个模块:
----joying-admin 后台管理系统
----joying-portal 门户系统
----joying-common 公共模块
1、变成规范
......@@ -47,7 +47,10 @@
<groupId>com.spring4all</groupId>
<artifactId>swagger-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
</dependency>
</dependencies>
<build>
......
package com.fzm.admin;
import com.spring4all.swagger.EnableSwagger2Doc;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
@SpringBootApplication
@EnableSwagger2Doc
@EnableCaching
@SpringBootApplication(scanBasePackages = {"com.fzm.admin", "com.fzm.common"})
@MapperScan(value = "com.fzm.common.mapper")
public class JoyingAdminApplication {
public static void main(String[] args) {
......
package com.fzm.admin.controller;
import io.swagger.annotations.Api;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author tangtuo
* @date 2021/7/5 9:48
*/
@RestController
@RequestMapping("/admin")
@Api(tags = "后台用户管理")
public class AdminController {
}
package com.fzm.admin.controller;
import com.fzm.common.entity.vo.UserListVo;
import com.fzm.common.entity.vo.UserStatisticVo;
import com.fzm.common.model.ResponseModel;
import com.fzm.common.service.UserService;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
/**
* @author tangtuo
* @date 2021/7/5 10:01
*/
@RestController
@RequestMapping("/admin")
@Api(tags = "用户管理")
public class UserController {
@Resource
private UserService userService;
@GetMapping("statistic")
@ApiOperation(value = "用户概览", notes = "获取已注册用户、已实名用户等统计信息")
public ResponseModel<UserStatisticVo> getStatistic() {
UserStatisticVo statisticVo = userService.getStatistic();
return ResponseModel.success(statisticVo);
}
@GetMapping("/list")
@ApiOperation(value = "用户列表")
public ResponseModel<PageInfo<UserListVo>> list(@ApiParam(value = "页码", required = true) @RequestParam Integer pageNum,
@ApiParam(value = "每页记录数", required = true) @RequestParam Integer pageSize,
@ApiParam(value = "手机号") @RequestParam(required = false) String telephone,
@ApiParam(value = "昵称") @RequestParam(required = false) String nickname,
@ApiParam(value = "认证类型 0-个人认证 1-企业认证") @RequestParam(required = false) Integer authType,
@ApiParam(value = "注册开始日期,yyyy-MM-dd格式") @RequestParam(required = false) String start,
@ApiParam(value = "注册截止日期,yyyy-MM-dd格式") @RequestParam(required = false) String end) {
PageHelper.startPage(pageNum, pageSize);
List<UserListVo> list = userService.list(telephone, nickname, authType, start, end);
return ResponseModel.success(new PageInfo<>(list));
}
}
server:
port: 8001
port: 8002
spring:
application:
name: joying-portal
name: joying-admin
main:
allow-bean-definition-overriding: true #当遇到同样名字的时候,是否允许覆盖注册
datasource:
......@@ -45,6 +45,9 @@ spring:
cache:
# 整合SpringCache,redis作为缓存类型
type: redis
redis:
# 缓存失效时间
time-to-live: 86400000
# sa-token配置
sa-token:
# token名称 (同时也是cookie名称)
......@@ -65,9 +68,9 @@ spring:
swagger:
title: 乐映影视
description: 乐映影视门户系统RESTFUL API
description: 乐映影视后台管理系统RESTFUL API
version: 1.0.0
base-package: com.fzm.portal.controller
base-package: com.fzm.admin.controller
base-path: /**
enabled: true
globalOperationParameters:
......@@ -80,11 +83,14 @@ swagger:
name: tangtuo
email: ttuo@33.com
sms:
app-key: Yiru
app-secret: mx5oaR^RY8!(ziHn
message-login-codetype: quick
email-login-codetype: quick
voice-login-codetype: quick
send-sms-url: http://118.31.52.32/send/sms2
validate-code-url: http://118.31.52.32/validate/code
chain:
para:
rpc-url: http://172.16.101.133:8801
withhold-addr: 1Ae6FfgdYJn6LLaqDoRjwga3j4TTmMq3t7
withhold-key: a4c49dcb35e0032dc8db5891dc81481943b68fc558ce93ce74d0382c1d104934
title: user.p.joying.
admin: 16naUoLwjNUgMhGVRmL3xTVpCso2DJp8JZ
admin-key: 8cd19e9bf39055f95e3e33cc1e08b9f9fc2e9be48a5b3a4d401e64041c97aec7
contract-name: user.evm.0xd996a3a866c577596df260844a045a068ec5accd8d71ccaa3d578c9617ec5490
contract-address: 1iDWTHZQxPES4hLveZRcwJH6AMaMfZfZZ
......@@ -5,6 +5,7 @@ spring:
name: ly-portal
jackson:
time-zone: GMT+8
date-format: yyyy-MM-dd HH:mm:ss
mybatis-plus:
......
package com.fzm.common.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.cache.CacheProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
@EnableConfigurationProperties(value = CacheProperties.class)
public class RedisCacheConfig {
@Autowired
private CacheProperties cacheProperties;
@Bean
public RedisCacheConfiguration redisCacheConfiguration() {
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
redisCacheConfiguration = redisCacheConfiguration.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()));
redisCacheConfiguration = redisCacheConfiguration.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
if (cacheProperties.getRedis().getTimeToLive() != null) {
redisCacheConfiguration = redisCacheConfiguration.entryTtl(cacheProperties.getRedis().getTimeToLive());
}
return redisCacheConfiguration;
}
}
\ No newline at end of file
......@@ -53,6 +53,9 @@ public class User extends AbstractUser {
@ApiModelProperty("实名认证状态 0-未认证 1-认证成功 2-认证失败 3-认证中")
private Integer authStatus;
@ApiModelProperty("是否发行过nft作品 0-否 1-是")
private Integer isPublish;
@ApiModelProperty("创建时间")
private Date createDate;
......
package com.fzm.common.entity.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
/**
* @author tangtuo
* @date 2021/7/5 11:33
*/
@Data
public class UserListVo {
@ApiModelProperty(value = "主键")
private Integer id;
@ApiModelProperty("手机号码(用户名)")
private String telephone;
@ApiModelProperty("昵称")
private String nickname;
@ApiModelProperty("实名认证状态 0-未认证 1-认证成功 2-认证失败 3-认证中")
private Integer authStatus;
@ApiModelProperty("已发行nft数")
private Integer publishCount;
@JsonFormat(pattern = "yyyy-MM-dd")
@ApiModelProperty("注册日期")
private Date registerDate;
}
package com.fzm.common.entity.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author tangtuo
* @date 2021/7/5 10:14
*/
@Data
@Accessors(chain = true)
public class UserStatisticVo {
@ApiModelProperty("已注册用户数")
private Integer registerUserCount;
@ApiModelProperty("已实名用户数")
private Integer authUserCount;
@ApiModelProperty("已发行nft用户数")
private Integer publishUserCount;
@ApiModelProperty("个人实名数")
private Integer personAuthCount;
@ApiModelProperty("企业实名数")
private Integer enterpriseAuthCount;
}
......@@ -10,7 +10,7 @@ import lombok.Getter;
public enum AuthTypeEnum {
PERSON(0,"个人认证"),
ENTERPRISE(0,"企业认证")
ENTERPRISE(1,"企业认证")
;
private Integer type;
......
package com.fzm.common.mapper;
import cn.hutool.core.date.DateTime;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.fzm.common.entity.User;
import com.fzm.common.entity.vo.UserListVo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* @author tangtuo
......@@ -10,4 +15,15 @@ import org.apache.ibatis.annotations.Mapper;
*/
@Mapper
public interface UserMapper extends BaseMapper<User> {
/**
* 查询用户列表
*
* @param telephone
* @param nickname
* @param authType
* @param startDate
* @param endDate
* @return
*/
List<UserListVo> list(@Param("telephone") String telephone, @Param("nickname") String nickname, @Param("authType") Integer authType, @Param("startDate") DateTime startDate, @Param("endDate") DateTime endDate);
}
......@@ -52,4 +52,12 @@ public interface NftService extends IService<Nft> {
* @return
*/
List<Nft> listCurrent(Integer categoryId, Integer userId);
/**
* 生成nft编号
*
* @param categoryId
* @return
*/
String generateNftId(Integer categoryId);
}
......@@ -3,8 +3,12 @@ package com.fzm.common.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.fzm.common.entity.AuthPerson;
import com.fzm.common.entity.User;
import com.fzm.common.entity.vo.UserListVo;
import com.fzm.common.entity.vo.UserStatisticVo;
import com.fzm.common.params.LoginParam;
import java.util.List;
/**
* @author tangtuo
* @date 2021/6/23 15:14
......@@ -48,4 +52,22 @@ public interface UserService extends IService<User> {
* @return
*/
User uploadAvatar(String avatar);
/**
* 查询用户统计概览信息
*
* @return
*/
UserStatisticVo getStatistic();
/**
*
* @param telephone
* @param nickname
* @param authType
* @param start
* @param end
* @return
*/
List<UserListVo> list(String telephone, String nickname, Integer authType, String start, String end);
}
......@@ -3,10 +3,12 @@ package com.fzm.common.service.impl;
import cn.dev33.satoken.stp.StpUtil;
import cn.fzm.chain.simplesdk.client.ParaChainClient;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fzm.common.constant.RedisConstant;
import com.fzm.common.constant.SystemConstant;
import com.fzm.common.entity.Category;
import com.fzm.common.entity.Nft;
import com.fzm.common.entity.User;
import com.fzm.common.entity.vo.CollectionNftVo;
......@@ -21,12 +23,10 @@ import com.fzm.common.utils.RedisUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.*;
import java.util.stream.Collectors;
/**
......@@ -34,6 +34,7 @@ import java.util.stream.Collectors;
* @date 2021/6/30 15:55
*/
@Service
@Transactional(rollbackFor = RuntimeException.class)
public class NftServiceImpl extends ServiceImpl<NftMapper, Nft> implements NftService {
@Resource
......@@ -57,6 +58,11 @@ public class NftServiceImpl extends ServiceImpl<NftMapper, Nft> implements NftSe
@Override
public Nft publish(Nft nft) {
User user = userService.getById(StpUtil.getLoginIdAsInt());
// 如果用户是第一次发行作品,把用户的isPublish修改成1
if (SystemConstant.BOOLEAN_DATA_FALSE.equals(user.getIsPublish())) {
User u = new User().setId(user.getId()).setIsPublish(SystemConstant.BOOLEAN_DATA_TRUE);
userService.updateById(u);
}
// 获取用户的私钥
String wallet = user.getWallet();
String privkey = paraChainClient.walletDumpPrivkey(wallet);
......@@ -110,4 +116,19 @@ public class NftServiceImpl extends ServiceImpl<NftMapper, Nft> implements NftSe
queryWrapper.orderByDesc("is_top", "publish_time");
return nftMapper.selectList(queryWrapper);
}
@Override
public String generateNftId(Integer categoryId) {
Category category = categoryService.getCategoryById(categoryId);
if (category == null) {
throw GlobalException.newException(ResultCode.DATA_ERROR, "没找到此类目");
}
int code = RandomUtil.randomInt(1000, 10000);
return String.format("JOYING-%s-%s%s", category.getEnglishName(), System.currentTimeMillis(), code);
}
public static void main(String[] args) {
int code = RandomUtil.randomInt(1000, 10000);
System.out.println(String.format("JOYING-%s-%s%s", "SCRIPT", System.currentTimeMillis(), code));
}
}
......@@ -3,10 +3,15 @@ package com.fzm.common.service.impl;
import cn.dev33.satoken.stp.StpUtil;
import cn.fzm.chain.simplesdk.client.ParaChainClient;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fzm.common.constant.SystemConstant;
import com.fzm.common.entity.AuthPerson;
import com.fzm.common.entity.User;
import com.fzm.common.entity.vo.UserListVo;
import com.fzm.common.entity.vo.UserStatisticVo;
import com.fzm.common.enums.AuthStatusEnum;
import com.fzm.common.enums.AuthTypeEnum;
import com.fzm.common.enums.ResultCode;
......@@ -16,13 +21,17 @@ import com.fzm.common.params.LoginParam;
import com.fzm.common.properties.SmsProperties;
import com.fzm.common.service.AuthPersonService;
import com.fzm.common.service.UserService;
import com.fzm.common.utils.RedisUtil;
import com.fzm.common.utils.SmsUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author tangtuo
......@@ -33,6 +42,9 @@ import javax.annotation.Resource;
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
@Resource
private UserMapper userMapper;
@Resource
private PasswordEncoder passwordEncoder;
@Resource
......@@ -42,6 +54,9 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
private SmsUtil smsUtil;
@Resource
private RedisUtil redisUtil;
@Resource
private AuthPersonService authPersonService;
@Resource
......@@ -82,6 +97,8 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
User u = new User().setId(registerUser.getId()).setWallet(wallet);
updateById(u);
}
// 用户注册后,需要删除用户概览的缓存
redisUtil.delete("user::statistic");
return getById(registerUser.getId());
} else {
// 登录逻辑
......@@ -145,4 +162,43 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
updateById(user);
return getById(loginId);
}
@Override
@Cacheable(value = "user", key = "'statistic'")
public UserStatisticVo getStatistic() {
UserStatisticVo statisticVo = new UserStatisticVo();
List<User> list = list();
// 已注册用户数
statisticVo.setRegisterUserCount(list.size());
// 已发行NFT用户数
long publishUserCount = list.stream().filter(user -> SystemConstant.BOOLEAN_DATA_TRUE.equals(user.getIsPublish())).count();
statisticVo.setPublishUserCount((int) publishUserCount);
// 已实名用户数
long authUserCount = list.stream().filter(user -> AuthStatusEnum.SUCCESS.getStatus().equals(user.getAuthStatus())).count();
statisticVo.setAuthUserCount((int) authUserCount);
// 个人实名用户数
long personAuthCount = list.stream().
filter(user -> AuthTypeEnum.PERSON.getType().equals(user.getAuthType()) && AuthStatusEnum.SUCCESS.getStatus().equals(user.getAuthStatus())).
count();
statisticVo.setPersonAuthCount((int) personAuthCount);
// 企业实名用户数
long enterpriseAuthCount = list.stream().
filter(user -> AuthTypeEnum.ENTERPRISE.getType().equals(user.getAuthType()) && AuthStatusEnum.SUCCESS.getStatus().equals(user.getAuthStatus())).
count();
statisticVo.setEnterpriseAuthCount((int) enterpriseAuthCount);
return statisticVo;
}
@Override
public List<UserListVo> list(String telephone, String nickname, Integer authType, String start, String end) {
DateTime startDate = null;
DateTime endDate = null;
if (StringUtils.isNotBlank(start)) {
startDate = DateUtil.parse(start + " 00:00:00", "yyyy-MM-dd HH:mm:ss");
}
if (StringUtils.isNotBlank(end)) {
endDate = DateUtil.parse(end + " 23:59:59", "yyyy-MM-dd HH:mm:ss");
}
return userMapper.list(telephone, nickname, authType, startDate, endDate);
}
}
<?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="com.fzm.common.mapper.UserMapper">
<select id="list" resultType="com.fzm.common.entity.vo.UserListVo">
SELECT u.id,
u.telephone,
u.nickname,
u.auth_status,
u.create_date AS registerDate,
(select count(0) from tb_nft n where u.id = n.user_id) as publishCount
FROM tb_user u
where 1=1
<if test="telephone != null and telephone != ''">
and u.telephone = #{telephone}
</if>
<if test="nickname != null and nickname != ''">
and u.nickname = #{nickname}
</if>
<if test="authType != null">
and u.auth_type = #{authType}
</if>
<if test="startDate != null">
and u.create_date >= #{startDate}
</if>
<if test="endDate != null">
and u.create_date &lt;= #{endDate}
</if>
</select>
</mapper>
\ No newline at end of file
......@@ -16,3 +16,4 @@ RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo '$TZ' > /etc/timezone
#配置容器启动后执行的命令,并指定使用项目外部的配置文件
ENTRYPOINT ["java","-Xms512m","-Xmx4096m","-Djava.security.egd=file:/dev/./urandom","-Dspring.profiles.active=dev","-jar","/home/joying/portal/app.jar"]
......@@ -2,6 +2,7 @@ package com.fzm.portal.controller;
import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.crypto.SecureUtil;
import com.fzm.common.constant.SystemConstant;
import com.fzm.common.entity.Category;
import com.fzm.common.entity.Nft;
......@@ -123,5 +124,21 @@ public class NftController {
return ResponseModel.success(result);
}
@SaCheckLogin
@GetMapping("/generateNftId")
@ApiOperation(value = "生成nft编号")
public ResponseModel<String> generateNftId(@ApiParam(value = "类目id", required = true) @RequestParam Integer categoryId) {
String nftId = nftService.generateNftId(categoryId);
return ResponseModel.success(nftId);
}
@SaCheckLogin
@PostMapping("/file/md5")
@ApiOperation(value = "获取文件的md5值")
public ResponseModel<String> getFileMd5Value(MultipartFile file) throws IOException {
String md5 = SecureUtil.md5(file.getInputStream());
return ResponseModel.success(md5);
}
}
package com.fzm.portal.listener;
import cn.fzm.chain.simplesdk.client.ParaChainClient;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import java.io.IOException;
/**
* @author tangtuo
* @date 2021/6/30 10:53
*/
//@Component
//@RabbitListener(queues = "nft.hash.queue")
public class HashListener {
/* ParaChainClient paraChainClient;
@RabbitHandler
public void listener(Integer id, Message message, Channel channel) throws IOException {
System.out.println(id);
long deliveryTag = message.getMessageProperties().getDeliveryTag();
if (id % 2 == 0) {
channel.basicAck(deliveryTag, false);
} else {
channel.basicReject(deliveryTag, true);
}
}*/
}
......@@ -88,6 +88,11 @@
<artifactId>sa-token-dao-redis-jackson</artifactId>
<version>1.20.0</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.3.0</version>
</dependency>
</dependencies>
</dependencyManagement>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment