为了学习英语,我开发了一个单词对战系统

简介: 本系统主要由Android、服务端、数据管理端构成。客户端的页面实现通过网络与服务器REST API接口通信获取 MySQL数据。本人重点参与网上单词对战系统客户端、服务器以及数据库的设计、开发、测试工作。

一,系统介绍


随着“互联网+”的大潮兴起,移动应用受热捧。


其中,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的单词对战系统的系统管理功能。


微信图片_20221010161653.png


二,系统演示


在基于Android的单词对战系统的首页中,可以看到信息和公告。首页包括登陆窗口、信息窗口等。实现的方法是。首页主要方便管理员进行首页展示。客户端发出一个http请求给web服务器,web服务器对http请求进行解析,如果匹配DispatcherServlet的请求映射路径(在web.xml中指定),web容器将请求转交给DispatcherServlet。


后台管理系统主要用于基于Android的单词对战系统的管理员进行后台管理, 后端管理对于control的处理关键就是:DispatcherServlet的handlerMappings集合中根据请求的URL匹配每一个handlerMapping对象中的某个handler,匹配成功之后将会返回这个handler的处理连接handlerExecutionChain对象。而这个handlerExecutionChain对象中将会包含用户自定义的多个handlerInterceptor对象。


微信图片_20221010161700.png


微信图片_20221010161704.png


微信图片_20221010161709.png


微信图片_20221010161714.png


微信图片_20221010161718.png


微信图片_20221010161723.png


微信图片_20221010161727.png


微信图片_20221010161732.png


三,核心代码演示


@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进行单词对战操作。


目录
相关文章
|
8月前
|
Web App开发 数据建模 Java
|
6天前
|
人工智能 自然语言处理
【AIGC】英语小助手Lingo:基于大语言模型的学习英语小帮手
【5月更文挑战第11天】英语小助手Lingo:基于大语言模型的学习英语小帮手
41 7
|
6天前
|
存储 移动开发 安全
【C/C++ 口语】C++ 编程常见接口发音一览(不断更新)
【C/C++ 口语】C++ 编程常见接口发音一览(不断更新)
25 0
|
10月前
|
数据采集 存储 人工智能
【每周一坑】自动翻译 | 【解答】单词本
提示:翻译功能可以通过网上的翻译 API 实现,你所要了解的就是如何发起网络请求,以及如果对返回结果进行处理。这也算是基本的爬虫操作。
|
10月前
|
人工智能 自然语言处理 数据处理
【每周一坑】单词本 +【解答】三国演义中谁的存在感最强
今天本系列打算做个小小的尝试,不再是一个单独的题目,而是一个连环坑!我希望通过之后的三四期,逐步引导大家做出一个功能较完整的小工具。不过我现在没有底,不知道到最后能有多少人把坑给填完。愿意接受挑战的,现在就开始了!
|
自然语言处理 搜索推荐
4款「ChatGPT搜索」全面对比!斯坦福华人博士纯手工标注:新必应流畅度最低,近一半句子都没引用
4款「ChatGPT搜索」全面对比!斯坦福华人博士纯手工标注:新必应流畅度最低,近一半句子都没引用
217 0
|
自然语言处理 程序员
程序员英语高效学习法
大多数程序员的英语是软肋,包括我在内。自己也曾经试过多种方法来学习英语,但最后都是不了了之,现在回想起来,
程序员英语高效学习法
|
机器学习/深度学习 自然语言处理 文字识别
英语学习利器:一款词典笔的模型创新与工程实践
机器学习怎样帮助英语学习?查词、翻译、标准发音都少不了:OCR(光学字符识别)实时识别单词与句子,NMT(神经网络翻译)自动翻译语句,TTS(语音合成)合成最真实的标准读音。那么这些是不是能集成到一个硬件中,成为智能的英语学习利器,这就是网易有道词典笔 2.0。
319 0
英语学习利器:一款词典笔的模型创新与工程实践
|
机器学习/深度学习 人工智能 自然语言处理
在语音识别这件事上,汉语比英语早一年超越人类水平(附论文)
几天前,微软语音识别实现了历史性突破,英语的语音转录达到专业速录员水平,机器之心也独家专访了专访微软首席语音科学家黄学东 ,了解到词错率仅 5.9% 背后的「秘密武器」——CNTK。但微软的成果是在英语水平上的,从部分读者留言中我们了解到对汉语语音识别的前沿成果不太了解,这篇文章将向大家介绍国内几家公司在汉语识别上取得的成果。
275 0
在语音识别这件事上,汉语比英语早一年超越人类水平(附论文)