欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 汽车 > 时评 > Spring项目-抽奖系统(实操项目-用户管理接口)(THREE)

Spring项目-抽奖系统(实操项目-用户管理接口)(THREE)

2025/7/5 12:38:07 来源:https://blog.csdn.net/m0_75235246/article/details/145810725  浏览:    关键词:Spring项目-抽奖系统(实操项目-用户管理接口)(THREE)

  ^__^
 (oo)\______

 (__)\      )\/\
     ||----w |
     ||     ||  

一、:前言:

        登录接口博客链接:Spring项目-抽奖系统(实操项目-登录接口)(TWO)-CSDN博客

        写完注册和登录接口后,接下来就做抽奖奖品、抽奖活动相应的创建展示过程。

        UI页面如下:
        

接下俩将一一完成下列这些接口。

二:用户管理:

2.1:人员列表展示:

        我们在参与抽奖的人员列表中,必须能够做到展示所有抽奖人员,时序图如下:


2.1.1:Controller层:

        该层需要注意:
        1.参数identity(表示具体要展示什么身份),当不传时,依旧可以访问,只要JWT令牌通过!!

        2.当传入参数时,需要判断传入的身份是否在预知范围内,用UserIdentityEnum进行简单判断

@RequestMapping("/base-user/find-list")public CommonResult<List<UserBaseInfoResult>> findUserBaseInfoList(String identity) {log.info("findUserBaseInfoList FindUsersParam:{}",identity);List<UserDTO> userDTOList = null;if(!StringUtils.hasText(identity)) {userDTOList = userService.findUserList(null);}else if(UserIdentityEnum.forname(identity) != null) {userDTOList = userService.findUserList(identity);}return CommonResult.succcess(covertToFindUserListResult(userDTOList));}private List<UserBaseInfoResult> covertToFindUserListResult(List<UserDTO> userDTOList) {if(CollectionUtil.isEmpty(userDTOList)) {return Arrays.asList();}return userDTOList.stream().map(userDTO -> {UserBaseInfoResult userBaseInfoResult = new UserBaseInfoResult();userBaseInfoResult.setUserName(userDTO.getUserName());userBaseInfoResult.setIdentity(userDTO.getIdentity());userBaseInfoResult.setUserId(userDTO.getUserId());return userBaseInfoResult;}).collect(Collectors.toList());}

2.1.2:Service层:

    
@Service
public interface UserService {/*** 查找用户列表* */List<UserDTO> findUserList(String identity);
}
ServiceImpl层: 
    @Overridepublic List<UserDTO> findUserList(String identity) {/*  if(param == null) {throw new ServiceException(ServiceErrorCodeConstatns.IDENTITY_ERROR);}*/List<UserDO> userDOList = userMapper.selectUserListByIdentity(identity);return userDOList.stream().map(userDO -> {UserDTO userDTO = new UserDTO();userDTO.setUserId(userDO.getId());userDTO.setUserName(userDO.getUserName());userDTO.setIdentity(userDO.getIdentity());userDTO.setEmail(userDO.getEmail());userDTO.setPhoneNumber(userDO.getPhoneNumber().getPhoneNumber());return userDTO;}).collect(Collectors.toList());}

2.1.3:Dao层:

        由于identity不是必传项,因此此次需要用到动态sql,选用mybaits的xml形式实现动态sql:

        具体的实现方法如下:

步骤一:

          设置配置项:

# 配置 mybatis xml 的⽂件路径,在 resources/mapper 创建所有表的 xml ⽂件
mybatis.mapper-locations=classpath:mapper/**Mapper.xml

步骤二:

        创建mapper文件与xxxMapper.xml文件;

                   

步骤三:

填写xml文件中基础代码:

<?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.example.lotterysystemplus.dao.mapper.UserMapper"><select id="selectUserListByIdentity"  resultType="com.example.lotterysystemplus.dao.dataobject.UserDO">select * from user<if test="identity != null">where identity = #{identity}</if>order by id desc</select>
</mapper>

步骤五:

        编写UserMapper包中的相关代码:

   List<UserDO> selectUserListByIdentity(@Param("identity") String identity);

三:奖品模块:

        写完人员管理模块之后,就开始写奖品模块,

奖品模块分为两个板块:

1.设置奖品模块

2.奖品展示模块

UI界面如下:

        


首先编写创建奖品模块:

3.1:创建奖品:

首先写保存图片相关接口:

         添加配置项:

## 图⽚服务 ##
pic.local-path=D:/PIC
# spring boot3 升级配置名
spring.web.resources.static-locations=classpath:/static/,file:${pic.local-path}
3.1.1:controller层:
    @RequestMapping("/pic/upload")public String upLodePic(MultipartFile file) {return pictureService.savePicture(file);}
3.1.2:Service层:

存放图片的服务是为了后期创建奖品时发挥作用!!
创建PictureService:

public interface PictureService {/*** 保存图片* @param pic* @return*/String savePicture(MultipartFile pic);
}
3.1.3:创建PictureServiceImpl:        
@Service
public class PictureServiceImpl implements PictureService {/*** 设置图片存放路径*/@Value("${pic.local-path}")private String picLocalPath;@Overridepublic String savePicture(MultipartFile pic) {File dir = new File(picLocalPath);if(!dir.exists()) {dir.mkdirs();}//获取文件名String fileName = pic.getOriginalFilename();assert fileName != null;//获取文件后缀名String suffixName = fileName.substring(fileName.lastIndexOf("."));//生成随机数防止图片重名fileName = UUID.randomUUID()+suffixName;try {//设置图片路径pic.transferTo(new File(picLocalPath+"/"+fileName));} catch (IOException e) {throw new RuntimeException(e);}return fileName;}
}

3.2:创建奖品相关接口:

3.2.1:controller层:
        
    /*** RequestPart:用于接收表单数据 multipart/form-data* 创建奖品* @param param* @param picFile* @return*/@RequestMapping("/prize/create")public CommonResult<Integer> createPrize(@RequestPart("param") @Valid CreatePrizeParam param,@RequestPart("prizePic") MultipartFile picFile) {log.info("createPrize CreatePrizeParam:{} MultipartFile:{}",JacksonUtil.writeValueAsString(param),picFile);return CommonResult.succcess(prizeService.createPrize(param,picFile));}

 注意:

        @RequestPart注解用于form-data格式的发送,但是对于文件的上传只有一个@RequestPart是远远不够的,还需要加一个序列化与发序列化的转化器:
        如果没有这个转换器,当我们在前端测试时,就会报此类错误:

        大概意思就是:

        前端给我们传过来的是数据类型是application/octet-stream,但是由于我们写了@RequestPart注解,希望接收到的是form-data表单格式数据,因此报错!!

        所以对于文件的传输前端传过来的默认是octet-stream格式,我们需要手动写一个转换器,代码如下:

/*** 实现二进制到对象的转换*/
@Component
public class MultipartJackson2HttpMessageConverter extends AbstractJackson2HttpMessageConverter {protected MultipartJackson2HttpMessageConverter(ObjectMapper objectMapper){// MediaType.APPLICATION_OCTET_STREAM 表⽰这个转换器⽤于处理⼆进制流数据,通常⽤于⽂件上传。super(objectMapper, MediaType.APPLICATION_OCTET_STREAM);}@Overridepublic boolean canWrite(Class<?> clazz, MediaType mediaType) {return false;}@Overridepublic boolean canWrite(Type type, Class<?> clazz, MediaType mediaType) {return false;}@Overrideprotected boolean canWrite(MediaType mediaType) {return false;}
}
3.2.2:service层:
@Service
public interface PrizeService {Integer createPrize(CreatePrizeParam param, MultipartFile file);
}
3.2.3:serviceimpl层:

        service层的具体实现。

@Service
public class PrizeServiceImpl implements PrizeService {@Autowiredprivate PrizeMapper prizeMapper;@Autowiredprivate PictureService pictureService;@Overridepublic Integer createPrize(CreatePrizeParam param, MultipartFile file) {String fileName = pictureService.savePicture(file);PrizeDO prizeDO = new PrizeDO();prizeDO.setName(param.getPrizeName());prizeDO.setDescription(param.getDescription());prizeDO.setPrice(param.getPrice());prizeDO.setImageUrl(fileName);prizeMapper.insert(prizeDO);return prizeDO.getId();}
}

3.3:展示奖品+翻页功能:

        将创建好的奖品进行展示,从数据库获取信息,发送给前端进行展示,并且带有翻页功能:

        翻页功能我们通过sql中的limit语句进行操作。需要传入两个参数:offset、pagesize完相应的功能。

3.3.1:controller层:   
    @RequestMapping("/prize/find-list")public CommonResult<PrizeFindListResult> prizeFindList(@Valid PageListParam param) {log.info("prizeFindList PageListParam:{}",JacksonUtil.writeValueAsString(param));PrizeListDTO<PrizeDTO> prizeDTOList = prizeService.findPrizeList(param);return CommonResult.succcess(convertToPrizeList(prizeDTOList));}
3.3.2:service层:
@Service
public interface PrizeService {Integer createPrize(CreatePrizeParam param, MultipartFile file);PrizeListDTO<PrizeDTO> findPrizeList(PageListParam param);
}
3.3.3:  serviceImpl层:

        service具体实现:

    @Overridepublic PrizeListDTO<PrizeDTO> findPrizeList(PageListParam param) {int count = prizeMapper.count();List<PrizeDO> prizeDOList = prizeMapper.queryPrizeByPage(param.offset(), param.getPageSize());List<PrizeDTO> prizeDTOList = new ArrayList<>();for (PrizeDO prizeDO:prizeDOList) {PrizeDTO prizeDTO = new PrizeDTO();prizeDTO.setId(prizeDO.getId());prizeDTO.setName(prizeDO.getName());prizeDTO.setDescription(prizeDO.getDescription());prizeDTO.setPrice(prizeDO.getPrice());prizeDTO.setImageUrl(prizeDO.getImageUrl());prizeDTOList.add(prizeDTO);}return new PrizeListDTO<>(count,prizeDTOList);}
3.3.4:Dao层:
    @Select("select count(1) from prize")int count();@Select("select * from prize order by id desc limit #{offset} , #{pageSize}")List<PrizeDO> queryPrizeByPage(@Param("offset") Integer offset,@Param("pageSize") Integer pageSize);

四:活动模块:

        创建完奖品之后,接下俩就需要设置好活动内容,最后开始仅从抽奖:

 

4.1:创建活动:

        前后端约定:   

[ 请求 ] /activity/create POST
{
"activityName": " 抽奖测试 ",
"description": " 年会抽奖活动 ",
"activityPrizeList": [
{
"prizeId": 13,
"prizeAmount": 1,
"prizeTiers": "FIRST_PRIZE"
},
"prizeId": 12,
"prizeAmount": 1,
"prizeTiers": "SECOND_PRIZE"
}
],
"activityUserList": [
{
"userId": 25,
"userName": " 郭靖 "
},
{
"userId": 23,
"userName": " 杨康 "
}
]
}
[ 响应 ]
{
"code": 200,
"data": {
"activityId": 23
},
"msg": ""
}

4.1.1:controller层:

        有了前后端约定,就可以直接定义后端controller接口,接收类型、返回类型都表达的非常清楚:

public class ActivityController {private static final Logger logger = LoggerFactory.getLogger(ActivityController.class);@Resourceprivate ActivityService createActivityService;/*** 创建活动* @param param* @return*/@RequestMapping("/activity/create")public CommonResult<Long> createActivity(@Valid @RequestBody CreateActivityParam param) {logger.info("createActivity CreateActivityParam: " +JacksonUtil.writeValueAsString(param));CreateActivityDTO createActivit = createActivityService.createActivity(param);return CommonResult.succcess(createActivit.getActivityid());}
}

注:大家也可以根据自己的喜好可以对返回值在进行一层封装和判断!!

4.1.2: service层:


@Service
public interface ActivityService {public CreateActivityDTO createActivity(CreateActivityParam param);
}

serviceImpl:

        需要注意一个非常重要的一点:

        我们需要将创建好的数据放入redis缓存当中,提高后期抽奖后活动奖品展示的效率!!

        service层接口的具体实现:

 @Overridepublic CreateActivityDTO createActivity(CreateActivityParam param) {//校验活动信息checkActivityInfo(param);//创建活动,并保存至数据库ActivityDO activityDO = new ActivityDO();activityDO.setActivityName(param.getActivityName());activityDO.setDescription(param.getDescription());activityDO.setStatus(ActivityStatusEnum.RUNNING.name());activityMapper.insert(activityDO);//关联奖品信息,并保存至数据库List<CreateActivityParam.CreatePrizeByActivityParam> createActivityParams = param.getActivityPrizeList();List<ActivityPrizeDO> activityPrizeDOList = new ArrayList<>();createActivityParams.forEach(item->{ActivityPrizeDO activityPrizeDO = new ActivityPrizeDO();activityPrizeDO.setActivityId(activityDO.getId());activityPrizeDO.setPrizeId(item.getPrizeId());activityPrizeDO.setPrizeAmount(item.getPrizeAmount());activityPrizeDO.setPrizeTiers(item.getPrizeTiers());activityPrizeDO.setStatus(ActivityPrizeStatusEnum.INIT.name());activityPrizeDOList.add(activityPrizeDO);});activityPrizeMapper.batchInsert(activityPrizeDOList);//关联人员信息,并保存至数据库List<CreateActivityParam.CreateUserByActivityParam> createUserByActivityParams = param.getActivityUserList();List<ActivityUserDO> activityUserDOList = new ArrayList<>();createUserByActivityParams.forEach(item->{ActivityUserDO activityUserDO = new ActivityUserDO();activityUserDO.setActivityId(activityDO.getId());activityUserDO.setUserId(item.getUserId());activityUserDO.setUserName(item.getUserName());activityUserDO.setStatus(ActivityUserStatusEnum.INIT.name());activityUserDOList.add(activityUserDO);});activityUserMapper.batchInsert(activityUserDOList);//查询奖品信息列表//使用stream中的map方法映射:提取ActivityPrizeDO类型中的每个prizeid映射,并且使用distinct方法去重List<Long> prizeIds = activityPrizeDOList.stream().map(ActivityPrizeDO::getPrizeId).distinct().toList();List<PrizeDO> prizeDOList = prizeMapper.batchSelectByIds(prizeIds);//将活动以及关联的奖品缓存至rediscacheActivity(convertToActivityDetilDTO(activityDO,activityPrizeDOList,activityUserDOList,prizeDOList));//返回活动idCreateActivityDTO createActivityDTO = new CreateActivityDTO();createActivityDTO.setActivityid(activityDO.getId());return createActivityDTO;}//校验活动信息private void checkActivityInfo(CreateActivityParam param) {//判断创建的活动是否为空if(param == null) {throw new ServiceException(ServiceErrorCodeConstatns.CREATE_ACTIVITY_IS_EMPTY);}//校验所选人员id是否存在List<Long> userIds = param.getActivityUserList().stream().map(CreateActivityParam.CreateUserByActivityParam::getUserId).distinct().toList();List<Long> existUserIds = userMapper.selectByIdsList(userIds);if(existUserIds == null) {throw new ServiceException(ServiceErrorCodeConstatns.ACTIVITY_USER_ERROR);}userIds.forEach(id->{if (!existUserIds.contains(id)) {throw new ServiceException(ServiceErrorCodeConstatns.ACTIVITY_USER_ERROR);}});//奖品id在奖品表中是否存在List<Long> prizeIds = param.getActivityPrizeList().stream().map(CreateActivityParam.CreatePrizeByActivityParam::getPrizeId).distinct().toList();List<Long> existPrizeIds = prizeMapper.selectByIdsList(prizeIds);if(existPrizeIds == null) {throw new ServiceException(ServiceErrorCodeConstatns.ACTIVITY_PRIZE_ERROR);}prizeIds.forEach(id->{if (!existPrizeIds.contains(id)) {throw new ServiceException(ServiceErrorCodeConstatns.ACTIVITY_PRIZE_ERROR);}});//人员数量大于等于奖品数量int userAmount = param.getActivityUserList().size();long prizeAmount = param.getActivityPrizeList().stream().mapToLong(CreateActivityParam.CreatePrizeByActivityParam::getPrizeAmount).sum();if (userAmount < prizeAmount) {throw new ServiceException(ServiceErrorCodeConstatns.USER_PRIZE_AMOUNT_ERROR);}//活动奖品等级有效性param.getActivityPrizeList().forEach(prize->{if(null == ActivityPrizeTiersEnum.forName(prize.getPrizeTiers())) {throw new ServiceException(ServiceErrorCodeConstatns.ACTIVITY_PRIZE_TIERS_ERROR);}});}/*** 将所获取的详细信息存放至redis缓存* @param detailDTO*/private void cacheActivity(ActivityDetailDTO detailDTO) {// key: ACTIVITY_+// value: ActivityDetailDTO(json)if(detailDTO == null || detailDTO.getActivityId() == null) {log.error("要缓存的活动信息不存在");return;}try {redisUtil.set(ACTIVITY_PREFIX + detailDTO.getActivityId(),JacksonUtil.writeValueAsString(detailDTO),ACTIVITY_TIMEOUT);}catch (Exception e) {logger.error("缓存活动异常,ActivityDetailDTO={}",JacksonUtil.writeValueAsString(detailDTO), e);}}
}

4.1.3:dao层:

        与数据库进行直接接触的层:

mapper层代码实现:

@Mapper
public interface ActivityMapper {@Insert("insert into activity (activity_name, description, status)" +" values (#{activityName}, #{description}, #{status})")@Options(useGeneratedKeys = true, keyProperty ="id", keyColumn ="id")Integer insert( ActivityDO activityDO);@Select("select count(1) from activity")long count();@Select("select * from activity order by id desc limit #{offset} , #{pageSize}")List<ActivityDO> queryActivitiesByPage(@Param("offset") Long offset,@Param("pageSize") Long pageSize);
}

4.2:展示活动:

        

前后端交互约定:      

[ 请求 ] /activity/find-list?currentPage=1&pageSize=10 GET
[ 响应 ]
{
"code": 200,
"data": {
"total": 10,
"records": [
{
"activityId": 23,
"activityName": " 抽奖测试 ",
"description": " 年会抽奖活动 ",
"valid": true
},
{
"activityId": 22,
"activityName": " 抽奖测试 ",
"description": " 年会抽奖活动 ",
"valid": true
},
{
"activityId": 21,
"activityName": " 节⽇抽奖 ",
"description": " ⽐特年会抽奖活动 ",
"valid": true
}
]
},
"msg": ""
}

    4.2.1:controller层:

@RequestMapping("/activity/find-list")public CommonResult<FindActivityListResult> findActivityList(@Valid PageListParam param) {logger.info("findActivityList :{}",JacksonUtil.writeValueAsString(param));PageListDTO<ActivityDTO> pageListDTO = createActivityService.findActivityList(param);return CommonResult.succcess(covertToFindActivityList(pageListDTO));}private FindActivityListResult covertToFindActivityList(PageListDTO<ActivityDTO> pageListDTO) {if(pageListDTO == null) {throw new ControllerException(ControllerErrorCodeConstants.FIND_ACITVITY_LIST_ERROR);}FindActivityListResult activityListResult = new FindActivityListResult();activityListResult.setTotal(pageListDTO.getTotal());activityListResult.setRecords(pageListDTO.getRecords().stream().map(item->{FindActivityListResult.FindActivityInfo findActivityInfo = new FindActivityListResult.FindActivityInfo();findActivityInfo.setActivityId(item.getActivityId());findActivityInfo.setActivityName(item.getActivityName());findActivityInfo.setDescription(item.getDescription());findActivityInfo.setValid(item.valid());return findActivityInfo;}).collect(Collectors.toList()));return activityListResult;}
}

4.2.2:service层:

        需要注意的是,展示活动列表,获取活动信息还是从数据库中去获取,因为redis中的信息有设置过期时间,所以为了稳定去数据库直接拿!

        当后期设计抽奖后展示详细信息时可以从redis中去快速拿!

@Service
public interface ActivityService {PageListDTO<ActivityDTO> findActivityList(PageListParam param);
}

serviceimpl层:

/*** 活动列表展示* @return*/@Overridepublic PageListDTO<ActivityDTO> findActivityList(PageListParam param) {//total总数long count = activityMapper.count();//获取活动列表List<ActivityDO> activityDOList = activityMapper.queryActivitiesByPage(param.offset(),param.getPageSize());List<ActivityDTO> activityDTOList = new ArrayList<>();activityDOList.forEach(activityDO -> {ActivityDTO activityDTO = new ActivityDTO();activityDTO.setActivityId(activityDO.getId());activityDTO.setActivityName(activityDO.getActivityName());activityDTO.setDescription(activityDO.getDescription());activityDTO.setStatus(ActivityStatusEnum.fromName(activityDO.getStatus()));activityDTOList.add(activityDTO);});return new PageListDTO<>(count,activityDTOList);}

4.2.3:dao层:

@Mapper
public interface ActivityMapper {@Insert("insert into activity (activity_name, description, status)" +" values (#{activityName}, #{description}, #{status})")@Options(useGeneratedKeys = true, keyProperty ="id", keyColumn ="id")Integer insert( ActivityDO activityDO);@Select("select count(1) from activity")long count();@Select("select * from activity order by id desc limit #{offset} , #{pageSize}")List<ActivityDO> queryActivitiesByPage(@Param("offset") Long offset,@Param("pageSize") Long pageSize);@Select("select * from activity where id = #{activityId}")ActivityDO selectByActivityId(@Param("activityId") Long activityId);
}

接下来就是重头戏了,对于整个抽奖的设计!!     
                            

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词