一,系统介绍
随着“互联网+”的大潮兴起,移动应用受热捧。
其中,Android应用借其强大的用户基础及其应用时的便捷而深受欢迎。在此基础上,以Android为载体的单词对战平台,可以满足复习单词的需求。因此,结合以上优势设计并实现基于Android的单词对战APP,符合我国互联网精准化问答和个性化服务的趋势。现如今随着消费方式的升级,学习单词的方式也变得多种多样,随着计算机与信息技术的发展,学习单词也由线下发展到了线上管理,越来越多的人选择利用计算机以及网络信息技术进行线上的单词学习,线上管理的好处在于可以实时统计以及查看信息,并且可以持久化到硬件设备中,数据管理方便,成本低,是如今信息管理的首选,本文就以Android为基础,设计并开发自己的系统,一个基于Android的单词对战系统。
本系统主要由Android、服务端、数据管理端构成。客户端的页面实现通过网络与服务器REST API接口通信获取 MySQL数据。本人重点参与网上单词对战系统客户端、服务器以及数据库的设计、开发、测试工作。
基于Android的单词对战系统主要实现了以下功能:
(1)用户管理。主要实现了基于Android的单词对战系统的用户管理功能。
(2)对战管理。主要实现了基于Android的单词对战系统的对战管理功能。
(3)单词管理。主要实现了基于Android的单词对战系统的单词管理功能。
(4)好友管理。主要实现了基于Android的单词对战系统的好友管理功能。
(5)故事管理。主要实现了基于Android的单词对战系统的故事管理功能。(6)类型管理。主要实现了基于Android的单词对战系统的类型管理功能。
(7)系统管理。主要实现了基于Android的单词对战系统的系统管理功能。
二,系统演示
在基于Android的单词对战系统的首页中,可以看到信息和公告。首页包括登陆窗口、信息窗口等。实现的方法是。首页主要方便管理员进行首页展示。客户端发出一个http请求给web服务器,web服务器对http请求进行解析,如果匹配DispatcherServlet的请求映射路径(在web.xml中指定),web容器将请求转交给DispatcherServlet。
后台管理系统主要用于基于Android的单词对战系统的管理员进行后台管理, 后端管理对于control的处理关键就是:DispatcherServlet的handlerMappings集合中根据请求的URL匹配每一个handlerMapping对象中的某个handler,匹配成功之后将会返回这个handler的处理连接handlerExecutionChain对象。而这个handlerExecutionChain对象中将会包含用户自定义的多个handlerInterceptor对象。
三,核心代码演示
@Aspect @Component public class OperLogAspect { private ThreadLocal<Long> startTime = new ThreadLocal<>(); @Autowired private OperRecordService operRecordService; @Pointcut("@annotation(com.egao.common.core.annotation.OperLog)") public void operLog() { } @Before("operLog()") public void doBefore(JoinPoint joinPoint) throws Throwable { startTime.set(System.currentTimeMillis()); } @AfterReturning(pointcut = "operLog()", returning = "result") public void doAfterReturning(JoinPoint joinPoint, Object result) { saveLog(joinPoint, result, null); } @AfterThrowing(value = "operLog()", throwing = "e") public void doAfterThrowing(JoinPoint joinPoint, Exception e) { saveLog(joinPoint, null, e); } private void saveLog(JoinPoint joinPoint, Object result, Exception e) { // 获取reques对象 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = (attributes == null ? null : attributes.getRequest()); // 构建操作日志 OperRecord operRecord = new OperRecord(); operRecord.setUserId(getLoginUserId()); if (startTime.get() != null) operRecord.setSpendTime(System.currentTimeMillis() - startTime.get()); if (request != null) { operRecord.setRequestMethod(request.getMethod()); operRecord.setUrl(request.getRequestURI()); operRecord.setIp(UserAgentGetter.getIp(request)); } // 记录异常信息 if (e != null) { operRecord.setState(1); operRecord.setComments(StrUtil.sub(e.toString(), 0, 2000)); } // 记录模块名、操作功能、请求方法、请求参数、返回结果 MethodSignature signature = (MethodSignature) joinPoint.getSignature(); operRecord.setOperMethod(joinPoint.getTarget().getClass().getName() + "." + signature.getName()); Method method = signature.getMethod(); if (method != null) { OperLog operLog = method.getAnnotation(OperLog.class); if (operLog != null) { operRecord.setModel(operLog.value()); operRecord.setDescription(operLog.desc()); if (operLog.param() && request != null) { operRecord.setParam(StrUtil.sub(JSON.toJSONString(request.getParameterMap()), 0, 2000)); } if (operLog.result() && result != null) { operRecord.setResult(StrUtil.sub(JSON.toJSONString(result), 0, 2000)); } } } operRecordService.saveAsync(operRecord); } /** * 获取当前登录的userId */ private Integer getLoginUserId() { Subject subject = SecurityUtils.getSubject(); if (subject == null) return null; Object object = subject.getPrincipal(); if (object instanceof User) return ((User) object).getUserId(); return null; } }
/** * 业务异常 * Created by xiaomeng */ public class BusinessException extends IException { private static final long serialVersionUID = 5450935008012318697L; public BusinessException() { super(); } public BusinessException(String message) { super(message); } public BusinessException(Integer code, String message) { super(code, message); } @Override public Integer getCode() { Integer code = super.getCode(); if (code == null) { code = 500; } return code; } @Override public String getMessage() { String message = super.getMessage(); if (message == null) { message = "系统错误"; } return message; } }
public class ParameterException extends IException { private static final long serialVersionUID = 7993671808524980055L; public ParameterException() { super(); } public ParameterException(String message) { super(message); } public ParameterException(Integer code, String message) { super(code, message); } @Override public Integer getCode() { Integer code = super.getCode(); if (code == null) { code = 400; } return code; } @Override public String getMessage() { String message = super.getMessage(); if (message == null) { message = "参数错误"; } return message; } }
@Controller @RequestMapping("/sys/dict") public class DictionaryController extends BaseController { @Autowired private DictionaryService dictionaryService; @RequiresPermissions("sys:dict:view") @RequestMapping() public String view() { return "system/dictionary.html"; } /** * 分页查询字典 */ @OperLog(value = "字典管理", desc = "分页查询") @RequiresPermissions("sys:dict:list") @ResponseBody @RequestMapping("/page") public PageResult<Dictionary> page(HttpServletRequest request) { PageParam<Dictionary> pageParam = new PageParam<>(request); return new PageResult<>(dictionaryService.page(pageParam, pageParam.getWrapper()).getRecords(), pageParam.getTotal()); } /** * 查询全部字典 */ @OperLog(value = "字典管理", desc = "查询全部") @RequiresPermissions("sys:dict:list") @ResponseBody @RequestMapping("/list") public JsonResult list(HttpServletRequest request) { PageParam<Dictionary> pageParam = new PageParam<>(request); return JsonResult.ok().setData(dictionaryService.list(pageParam.getOrderWrapper())); } /** * 根据id查询字典 */ @OperLog(value = "字典管理", desc = "根据id查询") @RequiresPermissions("sys:dict:list") @ResponseBody @RequestMapping("/get") public JsonResult get(Integer id) { return JsonResult.ok().setData(dictionaryService.getById(id)); } /** * 添加字典 */ @OperLog(value = "字典管理", desc = "添加", param = false, result = true) @RequiresPermissions("sys:dict:save") @ResponseBody @RequestMapping("/save") public JsonResult save(Dictionary dictionary) { if (dictionaryService.count(new QueryWrapper<Dictionary>().eq("dict_code", dictionary.getDictCode())) > 0) { return JsonResult.error("字典标识已存在"); } if (dictionaryService.count(new QueryWrapper<Dictionary>().eq("dict_name", dictionary.getDictName())) > 0) { return JsonResult.error("字典名称已存在"); } if (dictionaryService.save(dictionary)) { return JsonResult.ok("添加成功"); } return JsonResult.error("添加失败"); } /** * 修改字典 */ @OperLog(value = "字典管理", desc = "修改", param = false, result = true) @RequiresPermissions("sys:dict:update") @ResponseBody @RequestMapping("/update") public JsonResult update(Dictionary dictionary) { if (dictionaryService.count(new QueryWrapper<Dictionary>().eq("dict_code", dictionary.getDictCode()) .ne("dict_id", dictionary.getDictId())) > 0) { return JsonResult.error("字典代码已存在"); } if (dictionaryService.count(new QueryWrapper<Dictionary>().eq("dict_name", dictionary.getDictName()) .ne("dict_id", dictionary.getDictId())) > 0) { return JsonResult.error("字典名称已存在"); } if (dictionaryService.updateById(dictionary)) { return JsonResult.ok("修改成功"); } return JsonResult.error("修改失败"); } /** * 删除字典 */ @OperLog(value = "字典管理", desc = "删除", result = true) @RequiresPermissions("sys:dict:remove") @ResponseBody @RequestMapping("/remove") public JsonResult remove(Integer id) { if (dictionaryService.removeById(id)) { return JsonResult.ok("删除成功"); } return JsonResult.error("删除失败"); } /** * 批量添加字典 */ @OperLog(value = "字典管理", desc = "批量添加", param = false, result = true) @RequiresPermissions("sys:dict:save") @ResponseBody @RequestMapping("/saveBatch") public JsonResult saveBatch(@RequestBody List<Dictionary> list) { // 对集合本身进行非空和重复校验 StringBuilder sb = new StringBuilder(); sb.append(CoreUtil.listCheckBlank(list, "dictCode", "字典标识")); sb.append(CoreUtil.listCheckBlank(list, "dictName", "字典名称")); sb.append(CoreUtil.listCheckRepeat(list, "dictCode", "字典标识")); sb.append(CoreUtil.listCheckRepeat(list, "dictName", "字典名称")); if (sb.length() != 0) return JsonResult.error(sb.toString()); // 数据库层面校验 if (dictionaryService.count(new QueryWrapper<Dictionary>().in("dict_code", list.stream().map(Dictionary::getDictCode).collect(Collectors.toList()))) > 0) { return JsonResult.error("字典标识已存在"); } if (dictionaryService.count(new QueryWrapper<Dictionary>().in("dict_name", list.stream().map(Dictionary::getDictName).collect(Collectors.toList()))) > 0) { return JsonResult.error("字典名称已存在"); } if (dictionaryService.saveBatch(list)) { return JsonResult.ok("添加成功"); } return JsonResult.error("添加失败"); } /** * 批量删除字典 */ @OperLog(value = "字典管理", desc = "批量删除", result = true) @RequiresPermissions("sys:dict:remove") @ResponseBody @RequestMapping("/removeBatch") public JsonResult removeBatch(@RequestBody List<Integer> ids) { if (dictionaryService.removeByIds(ids)) { return JsonResult.ok("删除成功"); } return JsonResult.error("删除失败"); } }
四,数据库演示
数据库采用的mysql,具体的数据表设计如下:
SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for danci -- ---------------------------- DROP TABLE IF EXISTS `danci`; CREATE TABLE `danci` ( `id` int(0) NOT NULL AUTO_INCREMENT COMMENT 'id', `danci` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '单词', `fanyi` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '中文翻译', `ciyi` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '词义', `liju` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '例句', `image` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '图片', `leixing` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '类型', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of danci -- ---------------------------- INSERT INTO `danci` VALUES (1, 'apple', '苹果', '一种水果名字叫苹果', 'This is a apple', 'http://localhost:8081/getFileURL/file/20210513/home_bg.jpg', '水果'); INSERT INTO `danci` VALUES (2, 'banner', '香蕉', '一种黄色长条状的水果', 'This is a banner', 'http://localhost:8081/getFileURL/file/20210513/ic_bg_one.jpg', '类型1'); -- ---------------------------- -- Table structure for duizhan -- ---------------------------- DROP TABLE IF EXISTS `duizhan`; CREATE TABLE `duizhan` ( `id` int(0) NOT NULL AUTO_INCREMENT COMMENT 'id', `yaoqingren` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '邀请人', `beiyaoqingren` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '被邀请人', `shifoutongyidz` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '是否同意对战', `yqrchuci` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '邀请人出词', `byqrshiyi` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '被邀请人解释', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of duizhan -- ---------------------------- INSERT INTO `duizhan` VALUES (3, '123', '1234', '0', '', ''); -- ---------------------------- -- Table structure for gushi -- ---------------------------- DROP TABLE IF EXISTS `gushi`; CREATE TABLE `gushi` ( `id` int(0) NOT NULL AUTO_INCREMENT COMMENT 'id', `title` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '标题', `content` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '内容', `zuozhe` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '作者', `createtime` datetime(0) NULL DEFAULT NULL COMMENT '创建时间', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of gushi -- ---------------------------- INSERT INTO `gushi` VALUES (1, '邀请好友', ' B是生活中最常见的液体 D物质俗称苏打', '阿瑟东', '2020-01-01 00:00:00'); INSERT INTO `gushi` VALUES (2, '山核桃仁 ', ' B是生活中最常见的液体 D物质俗称苏打', '作者', '2020-01-01 00:00:00'); -- ---------------------------- -- Table structure for haoyou -- ---------------------------- DROP TABLE IF EXISTS `haoyou`; CREATE TABLE `haoyou` ( `id` int(0) NOT NULL AUTO_INCREMENT COMMENT 'id', `yhid` int(0) NULL DEFAULT NULL COMMENT '用户id', `yonghuname` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户名', `haoyouming` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '好友名', `haoyouid` int(0) NULL DEFAULT NULL COMMENT '好友id', `shifouty` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '是否同意', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of haoyou -- ---------------------------- INSERT INTO `haoyou` VALUES (1, 123, '123', '1234', 3, '1'); INSERT INTO `haoyou` VALUES (2, 123, '567', '123', 3, '1'); -- ---------------------------- -- Table structure for leixing -- ---------------------------- DROP TABLE IF EXISTS `leixing`; CREATE TABLE `leixing` ( `id` int(0) NOT NULL AUTO_INCREMENT COMMENT 'id', `leixing` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '类型', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of leixing -- ---------------------------- INSERT INTO `leixing` VALUES (1, '类型1'); INSERT INTO `leixing` VALUES (2, '水果'); -- ---------------------------- -- Table structure for sys_dictionary -- ---------------------------- DROP TABLE IF EXISTS `sys_dictionary`; CREATE TABLE `sys_dictionary` ( `dict_id` int(0) NOT NULL AUTO_INCREMENT COMMENT '字典id', `dict_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '字典标识', `dict_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '字典名称', `sort_number` int(0) NOT NULL DEFAULT 1 COMMENT '排序号', `comments` varchar(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注', `deleted` int(0) NOT NULL DEFAULT 0 COMMENT '是否删除,0否,1是', `create_time` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) COMMENT '创建时间', `update_time` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '修改时间', PRIMARY KEY (`dict_id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '字典' ROW_FORMAT = Dynamic;
根据模块图,基于Android的单词对战系统一共有一下七个模块:
用户管理模块:在基于Android的单词对战系统中,首次登陆的用户选择普通用户或管理员,输入自己的姓名及密码方可登陆。管理员可以实现修改用户和删除用户,查看用户增加用户等功能。管理员可以通过后台管理系统进行后台管理,普通用户可以操作APP进行单词对战操作。