实现一个在线抽奖系统,就算是个小白看了也能做出来(附源码)

2023-11-19

1、项目介绍:

(1)功能介绍:

主要业务:为公司活动(如年会等)提供在线抽奖功能,满足奖品、抽奖人员的管理,及抽奖活动的需要。

  • 用户注册
  • 用户登录、会话管理
  • 抽奖设置:奖品管理,抽奖人员管理
  • 人员抽奖

(2)开发环境与技术栈:

  • windows
  • Maven
  • Lombok
  • Spring、SpringMVC、SpringBoot
  • MySQL、Mybatis、Druid

(3)项目演示:

用户登录:

在这里插入图片描述

用户注册:

在这里插入图片描述

奖项设置:

在这里插入图片描述

抽奖人员设置:

在这里插入图片描述

抽奖:

在这里插入图片描述

2、项目准备:

(1)代码框架:(源码)

在这里插入图片描述

全部代码源码 Github链接:

https://github.com/JACK-QBS/Project

(2)数据库设计:

数据库表关系图:
在这里插入图片描述
(业务上一对一)

为什么要有设置表?

  • 1对1关联的表,其实可以只使用1张表保存所有字段;但是在一些可能出现的业务扩展,方便系统扩展使用,所以设计表时,考虑1对1设计。
  • 拓展业务 ,一个用户进来设置,当多个用户进来设置的时候(多个用户属于同一公司),如果是只有用户表的话,及无法支撑业务,用户表关联公司,设置表在关联公司

3、后端对前端接口的实现:

要实现功能,需要先明确前后端约定好的接口。需要说明的是,接口的定义一般是前后端约定好的,所以也和前端代码息息相关,前端需要什么数据,需要什么格式的数据,也会在接口中体现。

接口主要体现在:

  • 请求需要的信息:请求方法,请求路径,请求数据
  • 响应数据

(1)用户的登录、注册、注销

用户登录:

在这里插入图片描述

前端请求:

POST api/user/login (请求路径)
Content-Type: application/json
{username: “qbs”, password: “123”}

响应:

{ “success” : true }

后端实现接口:

在这里插入图片描述

用户注册:

在这里插入图片描述

前端请求:

POST api/user/register (请求路径)
Content-Type: multipart/form-data; boundary=----
WebKitFormBoundarypOUwkGIMUyL0aOZT

username: qbs
password: 123
nickname: 帅哥
email: 666@163.com
age: 18
headFile: (binary)

响应:

{ “success” : true }

后端实现:

在这里插入图片描述

用户注销:

在这里插入图片描述

前端请求:

POST api/user/login (请求路径)

后端实现:

在这里插入图片描述

(2)查询奖项设置、修改抽奖人数:

查询奖项设置:

在这里插入图片描述
前端请求:

GET api/setting/query(请求路径)

后端实现:

在这里插入图片描述

修改抽奖人数:

在这里插入图片描述

前端请求:

GET api/setting/update?batchNumber=5(请求路径)
(接口对应抽奖设置页面中,点每次抽奖人数下拉菜单切换时修改)

后端实现:
在这里插入图片描述

(3)新增、修改、删除奖项:

在这里插入图片描述

新增奖项:

前端请求:

POST api/award/add (请求路径)
Content-Type: application/json

{name: “特等奖”, count: 1, award: “全球旅行7日游”}

后端实现:

在这里插入图片描述

修改奖项:

前端请求:

POST api/award/update (请求路径)
Content-Type: application/json

后端响应:
在这里插入图片描述

删除奖项:

前端请求:

GET api/award/delete/4(请求路径)

最后的数字4,对应奖项的id

后端实现:

在这里插入图片描述

(4)新增、修改、删除抽奖人员:

在这里插入图片描述

新增抽奖人员:

前端请求:

POST api/member/add (请求路径)
Content-Type: application/json

后端实现:

在这里插入图片描述

修改抽奖人员

前端请求:

POST api/member/update
Content-Type: application/json

后端实现:
在这里插入图片描述

删除抽奖人员

前端请求:

GET api/member/delete/97
(最后的数字为抽奖人员的id)

后端实现:
在这里插入图片描述

(5)抽奖、删除获奖人员:

抽奖:

在这里插入图片描述
前端请求:

POST api/record/add/3
Content-Type: application/json
(以上路径中最后的数字代表奖项id,请求数据为抽奖人员id组成的数组)

后端实现:

抽奖后端只是插入记录(人员id、奖项id),具体的抽奖是前端实现的,而且也是简单的实现方式,没有任何算法。(只是在当前奖项剩余名额中,每次抽奖人数,在所有未中奖的人员列表中,随机抽取)
在这里插入图片描述

删除获奖人员:

在这里插入图片描述
前端请求:

GET api/record/delete/member?id=22
(根据 人员id 删除对应的获奖记录)

GET api/record/delete/award?id=3
(根据 奖项id 删除对应所有获奖人员记录)

后端实现:
在这里插入图片描述

4、代码设计:

(1)设计数据库的实体类:

通过 mybatis 生成工具(tool包):生成 mapper、数据库表实体类(model包)、xml 文件

(2)设计统一响应类:

主要是为了返回数据的统一字段设计

/**
 * 统一响应的数据格式
 */
public class JSONResponse {
    private boolean success;
    private String code;
    private String message;
    private Object data;
}
/**
 * 统一数据封装
 */
public class RequestResponseBodyMethodProcessorWrapper implements HandlerMethodReturnValueHandler {

    private final HandlerMethodReturnValueHandler delegate;

    public RequestResponseBodyMethodProcessorWrapper(HandlerMethodReturnValueHandler delegate) {
        this.delegate = delegate;
    }

    @Override
    public boolean supportsReturnType(MethodParameter returnType) {
        return delegate.supportsReturnType(returnType);
    }

    @Override
    public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
        //returnValue是Controller请求方法执行完,返回值
        if(!(returnValue instanceof JSONResponse)){//返回值本身就是需要的类型,不进行处理
            JSONResponse json = new JSONResponse();
            json.setSuccess(true);
            json.setData(returnValue);
            returnValue = json;
        }
        delegate.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
    }
}

(3)设计自定义异常:

主要针对不同的场景,需要抛异常来处理时,能定位业务含义。

主要分为:

  • 1、 客户端请求错误时的异常:需要给定错误码,方便前端提示用户,如用户名存在不允许注册
  • 2、 业务发生错误时的异常:需要给定错误码,方便后端定位问题,一般如程序上的业务错误都可以抛(BUG)
  • 3、 系统发生错误时的异常:需要给定错误码,方便后端定位问题,程序出错,如数据库连接获取失败都可以抛(一般是系统发生错误,如网络断了,数据库挂了等等)自定义异常前端需要显示错误码和错误消息,用户可以根据提示信息判断原因。
  • 4、非自定义异常,异常信息一般是框架或JDK抛出的英文,是给开发人员描述错误的,无法给用户提示,所以错误信息提示为未知异常。
/**
 * 自定义异常:保存错误码和错误消息
 */
@Getter
@Setter
public class AppException extends RuntimeException {

    private String code;

    public AppException( String code, String message) {
        super(message);
        this.code = code;
    }

    public AppException( String code, String message, Throwable cause) {
        super(message, cause);
        this.code = code;
    }
}
//统一异常处理
@ControllerAdvice
@Slf4j//使用lombok日志日志注解,之后使用log属性来完成日志打印
public class ExceptionAdvice {

    //自定义异常报错错误码和错误消息
    @ExceptionHandler(AppException.class)
    @ResponseBody
    public Object handle1(AppException e){
        JSONResponse json = new JSONResponse();
        json.setCode(e.getCode());
        json.setMessage(e.getMessage());
        log.debug("自定义异常", e);
        return json;
    }

    //非自定义异常(英文错误信息,堆栈信息,不能给用户看):
    // 指定一个错误码,错误消息(未知错误,请联系管理员)
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Object handle2(Exception e){
        JSONResponse json = new JSONResponse();
        json.setCode("ERR000");
        json.setMessage("未知错误,请联系管理员");
        log.error("未知错误", e);
        return json;
    }
}

(4)设计统一会话管理的拦截器

public class LoginInterceptor implements HandlerInterceptor {

    private ObjectMapper objectMapper;

    public LoginInterceptor(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HttpSession session = request.getSession(false);
        if(session != null){//获取登录时设置的用户信息
            User user = (User) session.getAttribute("user");
            if(user != null){//登录了,允许访问
                return true;
            }
        }
        //登录失败,不允许访问的业务:区分前后端
        //TODO:前端跳转登录页面,后端返回json
//        new ObjectMapper().writeValueAsString(object);//序列化对象为json字符串
        //请求的服务路径
        String servletPath = request.getServletPath();//   /apiXXX.html
        if(servletPath.startsWith("/api/")){//后端逻辑:返回json
            response.setCharacterEncoding("UTF-8");
            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
            JSONResponse json = new JSONResponse();
            json.setCode("USR000");
            json.setMessage("用户没有登录,不允许访问");
            String s = objectMapper.writeValueAsString(json);
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            PrintWriter pw = response.getWriter();
            pw.println(s);
            pw.flush();
        }else{//前端逻辑:跳转到登录页面 /views/index.html
            //相对路径的写法,一定是请求路径作为相对位置的参照点
            //使用绝对路径来重定向,不建议使用相对路径和转发
            String schema = request.getScheme();//http
            String host = request.getServerName();//ip
            int port = request.getServerPort();//port
            String contextPath = request.getContextPath();//application Context path应用上下文路径
            String basePath = schema+"://"+host+":"+port+contextPath;
            //重定向到登录页面
            response.sendRedirect(basePath+"/index.html");
        }
        return false;
    }
}

(5)设计Mybatis中Mapper的基类:

使用Mybatis的接口方法,所有接口方法都是类似,只是传入参数和返回值不同,可以考虑设计统一的基类,以泛型的方式定义出不同的参数类型、返回类型

/**
 * 所有 mapper 父接口
 */
public interface BaseMapper<T> {

    int deleteByPrimaryKey(Integer id);

    int insert(T record);

    int insertSelective(T record);

    T selectByPrimaryKey(Integer id);//通过主键查询

    int updateByPrimaryKeySelective(T record);//根据主键修改其他非主键字段

    int updateByPrimaryKey(T record);
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

实现一个在线抽奖系统,就算是个小白看了也能做出来(附源码) 的相关文章

随机推荐

  • python摔倒检测,跌倒检测openpose站立行为检测

    python摔倒检测 跌倒检测openpose站立行为检测 import cv2 import numpy as np from torch import from numpy jit from modules keypoints impo
  • 利用fsck修复/dev/mapper/VolGroup-lv_root: unexpected inconsistency; run fsck manually

    fsck file system check 用来检查和维护不一致的文件系统 若系统掉电或磁盘发生问题 可利用fsck命令对文件系统进行检查 如果系统启动的时候提示 dev mapper VolGroup lv root unexpecte
  • 【已解决】mysql报错error: Found option without preceding group in config file: D:\mysql-5.7.25-win32\my.ini

    之前mysql数据库出现问题 因此卸载重安顺便写个教程 顺便给大家一个小建议 如果软件出现什么莫名其妙的错误 半个小时都没有解决 不如直接重装 因为你不知道哪里出了问题 重装比找出问题简单多了 mysql从官网下载安装包直接解压即可 注意最
  • MySQL - 新增数据时想要得到新增数据的自增ID,怎么办???

    我们在实际逻辑编写时 往往会有 想要使用我们刚刚插入数据的自增ID 来做另外一件事情 这时候我们是可以通过查询刚才插入数据的某个字段作为条件 来查出这条数据的ID 但是总感觉太麻烦效率不高 当然 我们通过SQL层面也是有类似的办法 例如 S
  • Spring有哪些注入方式呢?

    转自 Spring有哪些注入方式呢 下文笔者讲述Spring注入方式分享 如下所示 Spring中有以下注入方式 1 setter属性注入 2 构造方法注入 3 lombok注入 例 1 setter属性注入 Controller publ
  • SLAM练习题(十一)—— G2O实战

    SLAM 学习笔记 写在前面的话 算是一点小小的感悟吧 估计位姿的方法有线性方法和非线性方法 线性方法就是特征点法中的2D 2D的对极约束 3D 2D的PnP问题 非线性方法有BA优化 它将位姿的估计问题转换成了一个误差关于优化量的最小二乘
  • SpringMVC关于get请求传参的问题

    在SpringMVC中 请求GetMapping注解的控制器方法 传参数时 如果直接使用get传递一个body参数过去 后端是不能正确接收的 这儿有一个篇为什么get请求不能正确接收body的解释 HTTP GET 请求可以有 body 吗
  • ROS通信机制~服务通信(server&client)·笔记3

    系列文章目录 ROS开发 ubuntu 笔记 1 嘻 嘻的博客 CSDN博客 ROS通信机制 话题通信 Publisher Subscriber 笔记2 嘻 嘻的博客 CSDN博客 服务通信 概念 以请求响应的方式实现不同节点之间数据交互的
  • MySQL基本SQL语句2(DML)

    目录 前言 一 添加数据 INSERT 1 给指定的字段添加数据 2 给所有的字段添加数据 3 添加多条数据 二 修改数据 UPDATE 修改数据语法 三 删除数据 DELETE 删除数据语法 总结 前言 DML英文全称是Data Mani
  • vue导出Excel和包含echarts的页面导出pdf

    目录 Vue用Export2Excel导出excel单表头和多表头 vue json excel插件实现导出 前端将Blob流文件转为文件导出 vue 导出HTML页面 包含echarts 为PDF Vue用Export2Excel导出ex
  • vmware fusion个人版

    个人免费版虚拟机 不要访问中文网站 以下链接都是英文网站 如果之前将该网站的国家设置成中国 请将其设置回美国后再打开链接 首先注册VMware Fusion Player 账号 并激活 https my vmware com web vmw
  • 目录以及目录下的重要文件

    第1章 mv mv move 移动 remove 移除 类似于windows的剪切 语法格式 mv 参数选项 源文件 目标文件 mv 源文件 新的文件名 root oldboyedu lnb 移动 oldboy下的oldboy txt文件
  • css line-height

    项目中看到 line height 1 所以来总结一下 line height 属性 line height 定义 line height 属性设置行间的距离 行高 line height 不允许使用负值 属性可能的值 值 描述 norma
  • RT-Thread操作系统 AT组件源码分析(以 EC20 为例)

    文章目录 1 AT 组件 1 1 AT 组件调试信息级别设置 1 2 AT 命令打印使能设置 1 3 GPRS 网络注册状态检查 1 4 EC200x 是否能连接外网日志输出 1 5 AT 设备注册过程 1 6 AT 设备类注册过程 1 7
  • win10java jdk安装

    配置环境变量 右击我的电脑 属性 点击Path 新建 添加最后两行到自己的Path环境中 转载链接 https www cnblogs com suni p 8279672 html
  • 求二叉树中两个指定节点的最短距离

    给定一个二叉树 找到该树中两个指定节点间的最短距离 思路 求最近公共祖先节点 然后再求最近公共祖先节点到两个指定节点的路径 再求两个节点的路径之和 const shortestDistance function root p q let l
  • Vue练习题(带解析)

    Vue基础入门 一 填空题 Vue是一套构建 用户界面 的渐进式框架 MVVM主要包含3个部分 分别是Model View和 ViewModel Vue中通过 refs 属性获取相应DOM元素 在进行Vue调试时 通常使用 vue devt
  • Qt实现隐藏按钮功能

    在Qt design界面中添加pushbutton 按钮 选中pushbutton 在右下角有按钮属性相关的修改内容 选中flat 按钮外围边框已消失 此时还差一步 需要修改一下 找到stylesheet 输入以下内容 输入 backgro
  • Go并发异步请求秀动抢票

    继上次python请求秀动接口 这次我将采用性能最佳的Go语言重构 tips 因分享了太多人 有人以此向外获利 所以停止分享 之前采用python异步请求 三次请求购票接口的思路 鉴于秀动app的防护措施愈来愈强 我将采用发挥go语言的协程
  • 实现一个在线抽奖系统,就算是个小白看了也能做出来(附源码)

    在线抽奖系统 1 项目介绍 1 功能介绍 2 开发环境与技术栈 3 项目演示 2 项目准备 1 代码框架 源码 2 数据库设计 3 后端对前端接口的实现 1 用户的登录 注册 注销 2 查询奖项设置 修改抽奖人数 3 新增 修改 删除奖项