基于SpringBoot的抽奖系统

一、项目简介

业务范围:该系统主要为公司活动(如年会等)提供在线抽奖功能,满足奖品、抽奖人员的管理,及抽奖活动的需要.
开发环境与技术栈:Windows、Maven、Lombok、Spring、SpringMVC、SpringBoot MySQL、Mybatis、Druid.
主要功能:用户注册、用户登录、奖项设置(增删改查)、抽奖人员设置(增删改查)、抽奖、删除获奖人员.

二、数据库设计

分析具体业务后数据库表设计如下

drop database if exists lucky_draw;
create database lucky_draw character set utf8mb4;

use lucky_draw;

drop table if exists user;
create table user(
    id int primary key auto_increment,
    username varchar(20) not null unique comment '用户账号',
    password varchar(20) not null comment '密码',
    nickname varchar(20) comment '用户昵称',
    email varchar(50) comment '邮箱',
    age int comment '年龄',
    head varchar(255) comment '头像url',
    create_time timestamp default NOW() comment '创建时间'
) comment '用户表';

drop table if exists setting;
create table setting(
    id int primary key auto_increment,
    user_id int not null comment '用户id',
    batch_number int not null comment '每次抽奖人数',
    create_time timestamp default NOW() comment '创建时间',
    foreign key (user_id) references user(id)
) comment '抽奖设置';

drop table if exists award;
create table award(
    id int primary key auto_increment,
    name varchar(20) not null comment '奖项名称',
    count int not null comment '奖项人数',
    award varchar(20) not null comment '奖品',
    setting_id int not null comment '抽奖设置id',
    create_time timestamp default NOW() comment '创建时间',
    foreign key (setting_id) references setting(id)
) comment '奖项';

drop table if exists member;
create table member(
    id int primary key auto_increment,
    name varchar(20) not null comment '姓名',
    no varchar(20) not null comment '工号',
    setting_id int not null comment '抽奖设置id',
    create_time timestamp default NOW() comment '创建时间',
    foreign key (setting_id) references setting(id)
) comment '抽奖人员';

drop table if exists record;
create table record(
    id int primary key auto_increment,
    member_id int not null comment '中奖人员id',
    award_id int not null comment '中奖奖项id',
    create_time timestamp default NOW() comment '创建时间',
    foreign key (member_id) references member(id),
    foreign key (award_id) references award(id)
) comment '中奖记录';

三、后端实现

五段代码只包含五个实体类从controller层到service层的调用
完整项目代码链接:Github

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    @PostMapping("/register")
    public Object register(User user, MultipartFile headFile){
		//保存上传的用户头像到服务端本地
        if(headFile != null) {
            String head = userService.saveHead(headFile);
            //上传的路径映射为http服务路径
            //用户头像的http路径设置到user.head,把user插入数据库
            user.setHead(head);
        }
        userService.register(user);
        return null;
    }
    @PostMapping("/login")
    public Object login(@RequestBody User user, HttpServletRequest req){//username, password
        //根据账号查用户
        User exist = userService.queryByUsername(user.getUsername());
        //用户不存在
        if(exist == null) throw new AppException("LOG001", "用户不存在");
        //用户存在,校验密码
        if(!user.getPassword().equals(exist.getPassword()))
            throw new AppException("LOG002", "账号或密码错误");
        //校验通过,保存数据库的用户(包含所有字段)到session
        HttpSession session = req.getSession();//先创建session
        session.setAttribute("user", exist);
        return null;//登录成功
    }
    @GetMapping("/logout")
    public Object logout(HttpSession session){
        session.removeAttribute("user");
        return null;
    }
}


@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private SettingMapper settingMapper;

    private static final DateFormat DF = new SimpleDateFormat("yyyyMMdd");

    @Value("${user.head.local-path}")
    private String headLocalPath;

    @Value("${user.head.remote-path}")
    private String headRemotePath;

    public String saveHead(MultipartFile headFile) {
    	//保存在本地路径
        //文件夹为当天:文件路径的间隔符和操作系统相关,可以使用File.separator,但是java也会根据操作系统自行设置
        Date now = new Date();
        String dirUri = "/"+DF.format(now);//20210203
        File dir = new File(headLocalPath+dirUri);
        if(!dir.exists()) dir.mkdirs();
        //保存在本地以天为单位的文件夹,保证文件唯一:随机字符串作为文件名,但是后缀还需要保留
        String suffix = headFile.getOriginalFilename()
                .substring(headFile.getOriginalFilename().lastIndexOf("."));
        String headName = UUID.randomUUID().toString()+suffix;
        String uri = dirUri+"/"+headName;
        try {
            headFile.transferTo(new File(headLocalPath+uri));
        } catch (IOException e) {
            throw new AppException("REG001", "上传用户头像出错");
        }
        return headRemotePath+uri;
    }

    //事务处理:多个更新必须,有部分查询+更新有时候也需要
    //内部实现:aop,方法前加入开启事务逻辑,方法执行后,抛异常rollback,没有异常commit
    //禁止使用try catch吃异常
    @Transactional//可以手动指定隔离级别和传播特性
    public void register(User user) {
        //数据库校验:校验用户名不能重复,省略,自行扩展
        //插入user数据:插入后自增主键会按照useGeneratedKeys=true设置到对象属性
        int n = userMapper.insertSelective(user);

        //插入setting数据:登录后,进入设置页面,添加奖项和抽奖人员,需要setting_id
        Setting setting = new Setting();
        setting.setUserId(user.getId());
        setting.setBatchNumber(8);//每次抽奖的数量:设置一个默认值(业务决定)
        settingMapper.insertSelective(setting);
    }

    public User queryByUsername(String username) {

        return userMapper.selectByUsername(username);
    }
}


@RestController
@RequestMapping("/setting")
public class SettingController {

    @Autowired
    private SettingService settingService;

    @Autowired
    private AwardService awardService;

    @Autowired
    private MemberService memberService;
    /**
     * 进入抽奖设置页面,初始化的接口,返回页面所有需要的数据:
     * setting对象中的属性:batchNumber
     * setting对象目前没有的属性:
     * (1)user(用户信息)
     * (2)awards(奖项列表:根据setting_id查)
     * (3)members(抽奖人员列表:根据setting_id查)
     */
    @GetMapping("/query")
    public Object query(HttpSession session){//已经登录,所以可以直接使用HttpSession
        //获取session中的user
        User user = (User) session.getAttribute("user");
        //根据userid查setting信息
        Setting setting = settingService.queryByUserId(user.getId());
        //把user设置到setting新增属性user中
        setting.setUser(user);
        //根据setting_id查award列表,设置到setting新增属性awards中
        List<Award> awards = awardService.queryBySettingId(setting.getId());
        setting.setAwards(awards);
        //根据setting_id查member列表,设置到setting新增属性members中
        List<Member> members = memberService.queryBySettingId(setting.getId());
        setting.setMembers(members);
        return setting;
    }

    @GetMapping("/update")
    public Object update(Integer batchNumber, HttpSession session){
        User user = (User) session.getAttribute("user");
        int n = settingService.update(batchNumber, user.getId());
        return null;
    }
}

@Service
public class SettingService {

    @Autowired
    private SettingMapper settingMapper;

    public Setting queryByUserId(Integer id) {
        return settingMapper.selectByUserId(id);
    }

    public int update(Integer batchNumber, Integer userId) {
        return settingMapper.update(batchNumber, userId);
    }
}

@RestController
@RequestMapping("/award")
public class AwardController {

    @Autowired
    private AwardService awardService;

    @PostMapping("/add")
    public Object add(@RequestBody Award award, HttpSession session){
        User user = (User) session.getAttribute("user");
        int n = awardService.add(award, user.getId());
        return award.getId();//插入后,返回给前端自增主键id
    }

    @PostMapping("/update")
    public Object update(@RequestBody Award award){
        int n = awardService.update(award);
        return null;
    }

    @GetMapping("/delete/{id}")
    public Object delete(@PathVariable Integer id){
        int n = awardService.delete(id);
        return null;
    }
}

@Service
public class AwardService {

    @Autowired
    private AwardMapper awardMapper;
    @Autowired
    private SettingMapper settingMapper;

    public List<Award> queryBySettingId(Integer id) {
        return awardMapper.selectBySettingId(id);
    }

    public int add(Award award, Integer userId) {
        //通过userId找settingId: 可以调用已有的selectByUserId
        Integer settingId = settingMapper.queryIdByUserId(userId);
        //设置award中settingId属性
        award.setSettingId(settingId);
        //插入一条award数据/对象
        return awardMapper.insertSelective(award);
    }

    public int update(Award award) {
        return awardMapper.updateByPrimaryKeySelective(award);
    }

    public int delete(Integer id) {
        return awardMapper.deleteByPrimaryKey(id);
    }
}

@RestController
@RequestMapping("/member")
public class MemberController {

    @Autowired
    private MemberService memberService;

    @PostMapping("/add")
    public Object add(@RequestBody Member member, HttpSession session){
        User user = (User) session.getAttribute("user");
        int n = memberService.add(member, user.getId());
        return member.getId();
    }

    @PostMapping("/update")
    public Object update(@RequestBody Member member){
        int n = memberService.update(member);
        return null;
    }

    @GetMapping("/delete/{id}")
    public Object delete(@PathVariable Integer id){
        int n = memberService.delete(id);
        return null;
    }
}

@Service
public class MemberService {

    @Autowired
    private MemberMapper memberMapper;
    @Autowired
    private SettingMapper settingMapper;

    public List<Member> queryBySettingId(Integer id) {
        return memberMapper.selectBySettingId(id);
    }

    public int add(Member member, Integer userId) {
        Integer settingId = settingMapper.queryIdByUserId(userId);
        member.setSettingId(settingId);
        return memberMapper.insertSelective(member);
    }

    public int update(Member member) {
        return memberMapper.updateByPrimaryKeySelective(member);
    }

    public int delete(Integer id) {
        return memberMapper.deleteByPrimaryKey(id);
    }
}

@RestController
@RequestMapping("/record")
public class RecordController {

    @Autowired
    private RecordService recordService;

    //抽奖:某个奖项下抽奖,一次抽多个人(插入多条抽奖记录)
    @PostMapping("/add/{awardId}")
    public Object add(@RequestBody List<Integer> memberIds, @PathVariable Integer awardId){
        int n = recordService.add(memberIds, awardId);
        return null;
    }

    @GetMapping("/delete/member")
    public Object deleteByMemberId(Integer id){
        int n = recordService.deleteByMemberId(id);
        return null;
    }

    @GetMapping("/delete/award")
    public Object deleteByAwardId(Integer id){
        int n = recordService.deleteByAwardId(id);
        return null;
    }

    @GetMapping("/delete/setting")
    public Object deleteBySetting(HttpSession session){
        User user = (User) session.getAttribute("user");
        //获取userid--->关联setting_id---->关联member_id, award_id
        //--->删除关联record
        int n = recordService.deleteByUserId(user.getId());
        return null;
    }
}

@Service
public class RecordService {

    @Autowired
    private RecordMapper recordMapper;

    //批量插入抽奖记录
    public int add(List<Integer> memberIds, Integer awardId) {
        return recordMapper.batchInsert(memberIds, awardId);
    }

    public int deleteByMemberId(Integer memberId) {
        return recordMapper.deleteByMemberId(memberId);
    }

    public int deleteByAwardId(Integer id) {
        return recordMapper.deleteByAwardId(id);
    }

    public int deleteByUserId(Integer id) {
        return recordMapper.deleteByUserId(id);
    }
}

四、项目运行结果

注册界面
在这里插入图片描述
登陆界面
在这里插入图片描述
抽奖设置
在这里插入图片描述
人员设置
在这里插入图片描述
抽奖界面
在这里插入图片描述

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值