由于最近关注的一个主播老是爱抽奖送礼品,这就成功引起我对抽奖系统的兴趣,自己简单的做了一个抽奖系统,下面简单记录一下。
开发环境:window/mac,idea(或者其他集成开发环境,本人用的是idea)
技术支持:Maven、Lombok、Spring、SpringMVC、SpringBoot、MySQL、Mybatis、Druid
项目功能:
用户操作,包括:登录,注册,注销;奖项设置,包括:增加,修改,删除;参与抽奖人员设置,包括:增加,修改,删除。抽奖设置,包括:设置每次可抽取的人数,删除某个人的获奖信息,清空某个奖的中奖名单先聊一下环境搭建,创建一个Maven项目,在pom.xml中加入SpringBoot依赖以及其它需要的依赖,创建启动类Applicant.java,创建配置文件application.properties;在写好MyBatis自动生成代码的启动类,利用MyBatis自动生成代码功能生成相应的代码(这一步的前提是你得提前准备好数据库,并在application.properties里面配置好数据库连接池,提供执行Generator时的.xml文件),执行Generator类,自动生成代码;到这里环境基本搭建好了。
下面就是设计一些统一处理逻辑,包括异常处理,返回值处理,拦截器设计,给Controller路径统一添加请求的路径前缀。这里主要说说对自定义异常的处理逻辑:@ControllerAdvice+@ExceptionHandler(BaseException.class)可处理在运行过程中抛出的BaseException及其子类的异常。将子类异常分为一下三种:
客户端请求错误时的异常:需要给定错误码,方便前端提示用户,如用户名存在不允许注册(只简单实现,不考虑具体字段的报错);业务发生错误时的异常:需要给定错误码,方便后端定位问题,一般如程序上的业务错误都可以抛(BUG);系统发生错误时的异常:需要给定错误码,方便后端定位问题,程序出错,如数据库连接获取失败都可以抛(一般是系统发生错误,如网络断了,数据库挂了等等)接着就业务逻辑了,这里聊聊部分实现逻辑。
在用户登录时,先判断数据库中有没有与这个用户名相同的用户,如果有接着判断用户名和密码校验是否正确,若不正确,用户不存在,则抛出ClientException异常,若存在,返回这个用户信息;在根据用户id来判是否有对应的setting,由于在注册用户时就需要生成setting数据,是一对一关系,如果没有生成会发生业务错误,所以需要判断。如果没有setting,抛出BusinessException,如果有在根据setting的id查询奖品列表和参加人员列表,并设置到setting属性中;最后将setting的id设置到当前User属性中,再将User对象设置到session中。
在用户注册时,先根据username判断当前User表中是否存在,若存在抛出ClientException异常,不允许继续注册,若不存在创建setting数据,由于注册用户时会提交一个头像,因此先设置User中的head属性值,表示照片的url地址,在将头像保存在本地。
抽奖设置,将中奖的人全都添加record表中,表中award_id 是奖项id,member_id是中奖人员id,一个奖项可以有一个或多个中奖人员,但是一个人只能中一个奖;在抽奖时,可以根据award_id 清空对应奖的中奖人员,还可以通过member_id删除这个人。
到这里主要的逻辑也基本聊完了,再说说我在写项目中遇到的一个让我费神的地方。在AwardMapper.xml中写查询某个奖项对应的获奖人员时,Award类中luckyMemberIds这个字段与其时一对多映射,在结果集中我不知道怎么写一对多映射,就在网上找了许多资料,最终解决了这一问题,下面附上一对多映射的实现代码以及sql实现语句:
<resultMap id="BaseResultMap" type="lingye.model.Award"> <id column="id" jdbcType="INTEGER" property="id" /> <result column="name" jdbcType="VARCHAR" property="name" /> <result column="count" jdbcType="INTEGER" property="count" /> <result column="award" jdbcType="VARCHAR" property="award" /> <result column="setting_id" jdbcType="INTEGER" property="settingId" /> <result column="create_time" jdbcType="TIMESTAMP" property="createTime" /> <collection property="luckyMemberIds" ofType="java.lang.Integer" javaType="java.util.ArrayList" > <result column="pre_r_member_id"/> </collection> </resultMap> <select id="query" parameterType="lingye.model.Award" resultMap="BaseResultMap"> select a.id, a.name, a.count, a.award, a.setting_id, a.create_time, r.id pre_r_id,r.member_id pre_r_member_id from award a left join record r on a.id = r.award_id where a.setting_id=#{settingId} </select>最后再聊聊项目中用到技术吧!这个项目是一个SpringBoot项目,之所以选择SpringBoot是因为它是自动化配置,可以简化开发(SpringBoot提供一些默认的配置,如web,jdbc等),它的自动化配置原理是扫描依赖包中MATE-INF文件夹下的Spring Boot的配置文件(如spring.factories),根据文件内容完成加载配置类,进一步完成配置类的初始化工作。用spring来管理对象,对象的创建,销毁都由IOC管理。Spring MVC是一个基于Java的实现了MVC设计模式的请求驱动类型的轻量级Web框架,通过把Model,View,Controller分离,将web层进行职责解耦,把复杂的web应用分成逻辑清晰的几部分,简化开发,减少出错,方便组内开发人员之间的配合,其流程如下:
(1)用户发送请求至前端控制器DispatcherServlet; (2) DispatcherServlet收到请求后,调用HandlerMapping处理器映射器,请求获取Handle; (3)处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet; (4)DispatcherServlet 调用 HandlerAdapter处理器适配器; (5)HandlerAdapter 经过适配调用 具体处理器(Handler,也叫后端控制器); (6)Handler执行完成返回ModelAndView; (7)HandlerAdapter将Handler执行结果ModelAndView返回给DispatcherServlet; (8)DispatcherServlet将ModelAndView传给ViewResolver视图解析器进行解析; (9)ViewResolver解析后返回具体View; (10)DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中) (11)DispatcherServlet响应用户。
好了,这次就聊到这里,有不对的地方欢迎评论区留言哦。完整代码已经提交到GitHub上,附上地址连接,有需要的小伙伴前往下载哦,希望能够帮助到你哦。源码戳这里