一、项目简介
业务范围:该系统主要为公司活动(如年会等)提供在线抽奖功能,满足奖品、抽奖人员的管理,及抽奖活动的需要.
开发环境与技术栈: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);
}
}
四、项目运行结果
注册界面
登陆界面
抽奖设置
人员设置
抽奖界面