HarmonyOS 实战小项目开发(一)
HarmonyOS 实战小项目开发(一)
日常逼逼叨
在经过一周多的Harmonyos 开发基础知识的学习后,自己通过对于Harmonyos基础知识的学习之后,结合自己的一些想法,独自完成了利用Arkts布局的Harmonyos 项目,在此将整个过程与各位共享出来,如有一些错误,希望观众老爷们批评指正
项目简述
练手项目名称:个人mbti性格测试
项目背景:相信各位小伙伴都比较了解前段时间很火的性格测试,在经过比较多的(大概90多道题目吧)题目测试之后,会获取到对于自己性格的一些说明,但是比较烦的是,在你自己认认真真的答完90多道题目想要进行结果的查看,这个时候突然弹出收费....王德发,这还能给你收费了?
在经过这个痛苦的过程之后,自己在网络上收取了一些关于性格测试的题目,在理解了关于性格测试的原理之后,结合自己学习的前后端知识,自己制作了一个性格测评。
性格测试原理及结果计算方法
- 首先呢,性格测试的结果是由8项(E、I、S、N、T、F、J、P)(性格指标)组成的,性格测试过程中你会拿到28(98、或者更多)的性格测试题目,每道题目分值为一分且一般会有两个选项,每一个选项对应上述8个指标中的一个,不同题目不同选项对应的指标不一定一致。
- 比如有两道测试题,测试题1选项a对应指标E,选项b对应指标I,测试题2选项a对应指标J,选项b对应指标P。同时这些指标往往是成对出现的,比如“E-I”、“S-N”、“T-F”和“J-P”,这个叫做组别。
- 在玩家完成手头的题目作答之后呢,会得到一个由上述8项指标组成的序列,在该序列中,只需要在该序列中找到并比较四个组别的得分。每个组别中,获得较高分数的那个类型,就是你的性格类型倾向。例如:你的得分是:E(外向)12分,I(内向)9分,那你的类型倾向便是E(外向)了。
- 但是在序列中,可能存在某个组别中,个数一致的情况,同分处理规则为:
假如E=I ------> I
假如S=N ------> N
假如T=F ------> F
假如J=P ------> P
项目简介:采用前后端分离的设计,前端采用Harmony os ArkTs 声明式UI 设计,后端采用Spring-Boot+mongodb(当然感兴趣的也可以试试mysql等其他数据库)
主要能学到什么:
对于Harmony os 的新手而言,通过这个项目,能够快速的帮你了解到以下知识点:
基础的一些布局以及基础的一些组件使用
页面跳转,传递参数
网络请求
父子组件传值
打包安装
<暂时想不起来了,符号占位先>
对于后端的小伙伴们而言
- spring-boot集成mongodb实现数据的增删改查
- mongodb 的一些语句操作
那话不多说,我们马上开始~
后端搭建
数据库设计
数据库选择
- 首先数据库的选择方面呢,之前一直用的mysql,这次手头有一个mongodb,想着换换口味,就暂定将mongodb作为后端数据库使用,作为数据的存储。
数据结构梳理
数据结构方面大概有两种数据需要我们进行存储
第一个呢就是题目,作为一个个人的性格测试,当然是要存在题目这一个概念的
其次呢就是测评结果对应的说明,这个也是比较重要的
目前想到的也就这两个,不够的话,我们后期再加,或者有其他想法的小伙伴也可以联系我进行一些二次开发
数据表设计
测试题目表(mbtiTopic)
_id String mongodb 对应的主键uuid name String 题干 optionA String 选项A optionB String 选项B sequence_number int 题目序号 valA String 选项A所对应的意义 valB String 选项B所对应的意义
结果对照表
_id String mongodb 对应的主键uuid ansCode String 性格测试结果字符串 ansDisc String 性格测试结果描述 ansName String 性格测试结果名称 sequence_number int 序号
Spring-Boot项目初始化
对于后端的搭建,是一个简单的Spring-Boot的项目,首先呢就是初始化一个Spring-Boot项目,经过一步一步的选择,我们便能得到一个什么都没有的Spring-Boot项目
- 不过值得注意的是,如果你的idea在初始化Spring-Boot项目的时候,只能选择java版本为17和21,但是你想使用java8时,请按照如下步骤进行操作

- 
我们只知道IDEA页面创建Spring项目,其实是访问spring initializr去创建项目。故我们可以通过阿里云国服去间接创建Spring项目。将https://start.spring.io/或者http://start.springboot.io/替换为 https://start.aliyun.com/

- 创建完成项目之后,需要在pom.xml中进行相关依赖的 引入(按需导入)
<dependencies>
<!--mongodb-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<!--springWeb-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--springdevtools-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--springtest 这个是初始化项目自带的-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.48</version>
</dependency>
<!--测试类,可以不用引入-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<!--测试用到的数据解析类,可以不用引入-->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
</dependencies>
后台项目代码编写
任务点分解
那作为一个数据的提供后台,需要完成以下几个功能:
- 对于题目的管理功能(前面想着做一个相关题目的管理界面,就写了这部分接口,但是界面真的不是很想搭建,留给爱学习的小伙伴们或者后面有时间再说)目前没啥用
- 查询题目功能
- 计算性格属性功能
既然目标比较明确了,辣么问题也就好办了起来!
Spring-Boot+mongodb CRUD
以第一点对于题目的管理功能为例子,简单讲述一下Spring-Boot集成mongodb 进行数据的CRUD
- 首先,进行spring-mongo的依赖导入,详情见上文pom.xml的依赖,按需引入即可
- 进行简单的项目目录创建,简单的对于项目目录进行如下梳理
- /conf:存放一些配置文件
- /controller: 存放接口
- /dao:存放对应的实体类
- /service:存放一些service类
- /service/serviceImpl:存放具体的service的逻辑实现类
- /utils:存放通常的工具类

进行application.yml的配置
spring:
data:
mongodb:
# 主机地址
host: 127.0.0.1
# 数据库
database: MBTI
# mongodb端口
port: 27017
main:
allow-circular-references: true
server:
port: 8899
题目实体类(Topic)
/***
*性格测试题目类
*/
@Document("mbtiTopic") //表名称
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Topic implements Serializable { @Id //主键
private String id; @Field
private String name; @Field
private String optionA; @Field
private String optionB; @Indexed(unique = true) //唯一索引
@Field("sequence_number")//对应mongo中的字段,如果不对应,需要进行标注
private Integer sequenceNumber; @Field
private String valA; @Field
private String valB;
}
接口实现
- TopicService
public interface TopicService {
//查找全部
List<Topic> findAll(); //按照id查询
Topic findById(int sequenceNumber); //按照id 修改
Topic updateById(Topic topic); //按照id删除
boolean delById(int sequenceNumber); //插入
boolean insertOne(Topic topic); }
- TopicServiceImpl
@Service
public class TopicServiceImpl implements TopicService { @Autowired
private MongoTemplate mongoTemplate; //查全部
@Override
public List<Topic> findAll() {
return mongoTemplate.findAll(Topic.class);
} //查根据id查询
@Override
public Topic findById(int sequenceNumber) {
Query query = new Query();
query.addCriteria(Criteria.where("sequence_number").is(sequenceNumber));
Topic one = mongoTemplate.findOne(query, Topic.class);
return one;
} //根据id更新
@Override
public Topic updateById(Topic topic) {
Topic save = mongoTemplate.save(topic);
return save;
}
//根据id删除
@Override
public boolean delById(int sequenceNumber) {
Query query = new Query();
query.addCriteria(Criteria.where("sequence_number").is(sequenceNumber));
DeleteResult remove = mongoTemplate.remove(query, Topic.class);
if (remove.getDeletedCount() > 0) {
return true;
}
return false;
} //插入
@Override
public boolean insertOne(Topic topic) {
Topic save = mongoTemplate.save(topic);
if (save != null) {
return true;
}
return false;
}
}
- controller
@RestController
@CrossOrigin
@RequestMapping("/manage")
public class manageController { @Autowired
private TopicService topicService;
JSONObject jsonObject = new JSONObject(); //查询全部
@GetMapping("/getAll")
public JSONObject getAll() {
jsonObject.clear();
jsonObject.put("status", 200);
jsonObject.put("data", topicService.findAll());
return jsonObject;
} //按照id查询
@GetMapping("/getById/{id}")
public JSONObject findById(@PathVariable("id") int id) {
jsonObject.clear();
Topic one = topicService.findById(id);
if (one != null) {
jsonObject.put("status", 200);
jsonObject.put("data", one);
} else {
jsonObject.put("status", 200);
jsonObject.put("data", null);
}
return jsonObject;
} //更新
@PutMapping("/update")
public JSONObject updateById(@RequestBody Topic topic) {
jsonObject.clear();
Topic one = topicService.updateById(topic);
if (one != null) {
jsonObject.put("status", 200);
jsonObject.put("msg", "更新成功~");
} else {
jsonObject.put("status", 201);
jsonObject.put("msg", "更新失败~");
}
return jsonObject;
} //删除
@GetMapping("/del/{id}")
public JSONObject delById(@PathVariable("id") int id) {
jsonObject.clear();
boolean isDel = topicService.delById(id);
if (isDel) {
jsonObject.put("status", 200);
jsonObject.put("msg", "删除成功~");
} else {
jsonObject.put("status", 201);
jsonObject.put("msg", "删除失败~");
}
return jsonObject;
} }
mongodb分页查询功能实现
serviceImpl
public static final int DEFAULT_CURR_PAGE = 1;//默认第一页
public static final int DEFAULT_PAGE_SIZE = 1;//默认每页1条 public List<Topic> getListWithCriteria(int page, int pageSize) {
Query query = new Query(); // 分页查询
int Page = page < 0 ? PageParameter.DEFAULT_CURR_PAGE : page;
int PageSize = pageSize < 0 ? PageParameter.DEFAULT_PAGE_SIZE : pageSize; //此处为第几页,从第几条开始查,公式和sql一样,根据业务自行设置
query.skip((Page - 1) * PageSize);
//每页条数
query.limit(PageSize);
//调用find(),查出符合条件的数据
List<Topic> topics = mongoTemplate.find(query, Topic.class);
return topics; }
controller
//分页查询
@GetMapping("/getByPage/{page},{size}")
public Object getByPage(@PathVariable("page") int page, @PathVariable("size") int size) {
jsonObject.clear();
List<Topic> listWithCriteria = topicService.getListWithCriteria(page, size);
int size1 = listWithCriteria.size();
if (size1 > 0) {
jsonObject.put("status", 200);
jsonObject.put("data", listWithCriteria);
jsonObject.put("endTag", false);
} else {
jsonObject.put("status", "201");
jsonObject.put("data", null);
jsonObject.put("endTag", true);
}
return jsonObject;
}
计算性格属性功能实现
思路:用户在移动端答题完成后将所有已选择题目的性格指标拼接成一个指标字符串提交给后端,后端通过遍历这个字符串,找出各个指标的数量,对应四个性格组别“E-I”、“S-N”、“T-F”和“J-P” ,按照前面所写的评分标准进行性格测试的结果计算。计算完成之后,返回给移动端进行渲染展示
serviceImpl
public AnsReturn calculateAns(String string) {
StringBuffer stringBuffer = new StringBuffer(string);
HashMap<Character, Integer> map = new HashMap<>(); for (int i = 0; i < stringBuffer.length(); i++) {
char a = stringBuffer.charAt(i);
if (map.get(a) == null) {
map.put(a, 1);
} else {
map.put(a, map.get(a) + 1);
}
}
System.out.println(map.keySet());
System.out.println(map.values()); Integer e = (map.get('E') == null ? 0 : map.get('E'));
Integer i = (map.get('I') == null ? 0 : map.get('I'));
Integer s = (map.get('S') == null ? 0 : map.get('S'));
Integer n = (map.get('N') == null ? 0 : map.get('N'));
Integer t = (map.get('T') == null ? 0 : map.get('T'));
Integer f = (map.get('F') == null ? 0 : map.get('F'));
Integer j = (map.get('J') == null ? 0 : map.get('J'));
Integer p = (map.get('P') == null ? 0 : map.get('P')); //计算比率
DecimalFormat decimalFormat = new DecimalFormat("0.00");
String eRate = decimalFormat.format(((double) e / stringBuffer.length()) * 100);
String iRate = decimalFormat.format(((double) i / stringBuffer.length()) * 100);
String sRate = decimalFormat.format(((double) s / stringBuffer.length()) * 100);
String nRate = decimalFormat.format(((double) n / stringBuffer.length()) * 100);
String tRate = decimalFormat.format(((double) t / stringBuffer.length()) * 100);
String fRate = decimalFormat.format(((double) f / stringBuffer.length()) * 100);
String jRate = decimalFormat.format(((double) j / stringBuffer.length()) * 100);
String pRate = decimalFormat.format(((double) p / stringBuffer.length()) * 100); //拼接结果
StringBuffer res = new StringBuffer();
res = e > i ? res.append("E") : res.append('I');
res = s > n ? res.append('S') : res.append('N');
res = t > f ? res.append('T') : res.append('F');
res = j > p ? res.append('J') : res.append('P'); Query query = new Query();
query.addCriteria(Criteria.where("ansCode").is(res.toString()));//从字典表中获取性格结果信息
AnsBasic one = mongoTemplate.findOne(query, AnsBasic.class); AnsReturn ans = new AnsReturn(res.toString(), eRate, iRate, sRate, nRate, tRate, fRate, jRate, pRate, one.getName(), one.getDisc()); return ans;
}
controller
@PostMapping("/submit")
public JSONObject calculateAns(@RequestBody JSONObject object) {
jsonObject.clear();
String ans = object.getString("ans");
AnsReturn ans1 = topicService.calculateAns(ans);
if (ans1 != null) {
jsonObject.put("status", 200);
jsonObject.put("data", ans1);
} else {
jsonObject.put("status", 201);
jsonObject.put("data", null);
}
return jsonObject; }
至此简单的后端代码已经全部开发完成,提供给移动端访问的接口有:查询所有的题目,提交自己的结果等待返回性格测试结果
结语
关于项目介绍以及简单的端项目搭建就先简单的介绍到这里,有关移动端的界面部署等,我们下期再聊,如果觉得up所述对你的学习等有点帮助,请务必留下你们的一键三连,谢谢各位观众老爷了。
INVITATION
主要是对于HarmonyOS 的移动端开发基础知识的巩固,所以整体结构等都比较简单,就当练手了吧,项目已经开源,有兴趣的小伙伴可以加入进行后续的开发.
后端:homp
希望有兴趣的小伙伴加入一起,我们做大做强,再创辉煌
HarmonyOS 实战小项目开发(一)的更多相关文章
- Flask框架的学习与实战(二):实战小项目
昨天写了一篇flask开发环境搭建,今天继续,进行一个实战小项目-blog系统. blog系统很简单,只有一个页面,然而麻雀虽小五脏俱全.这里目的不是为了做项目而做项目,这篇文章本意是通过这次练习传达 ...
- 【实战小项目】python开发自动化运维工具--批量操作主机
有很多开源自动化运维工具都很好用如ansible/salt stack等,完全不用重复造轮子.只不过,很多运维同学学习Python之后,苦于没小项目训练.本篇就演示用Python写一个批量操作主机的工 ...
- 实战小项目BUG纪录
果然,作为程序员最可爱的女朋友就是各种BUG,解决了你的开发能力和开发效率就会上升到一个新的层次.反之,在你面对BUG的时候,如果轻易的就放弃了,你也就失去了一次自我成长的机会.学习就是这样的,我们有 ...
- Django集成celery实战小项目
上一篇已经介绍了celery的基本知识,本篇以一个小项目为例,详细说明django框架如何集成celery进行开发. 本系列文章的开发环境: window 7 + python2.7 + pychar ...
- python网页爬虫小项目开发
这是我最近接的一个小项目,花了是整整四天多时间. 任务是将http://www.examcoo.com/index/detail/mid/7网站下所有的试卷里的试题全部提取出来,首先按照题型进行分类, ...
- ASP.NET Core 2.1 Web API + Identity Server 4 + Angular 6 + Angular Material 实战小项目视频
视频简介 ASP.NET Core Web API + Angular 6的教学视频 我是后端开发人员, 前端的Angular部分讲的比较差一些, 可以直接看代码!!!! 这是一个小项目的实战视频, ...
- springboot实战小项目-简要介绍、vue项目创建
因为菜,所以要好好学习! 一.项目介绍:这是一个后台管理系统,准备实现的功能: 1.登录.注册.个人信息查看.退出登录 2.根据关键字查询用户.新增用户.根据id或者其他字段排序.编辑用户信息.删除用 ...
- 【Vue3+Express实战】项目开发环境搭建
大家好,我是半夏,一个刚刚开始写文的沙雕程序员.如果喜欢我的文章,可以关注 点赞 加我微信:frontendpicker,一起学习交流前端,成为更优秀的工程师-关注公众号:搞前端的半夏,了解更多前端知 ...
- SSH实战 · SSH项目开发环境搭建
一:SSH整合 创建一个新的WEB项目 引入struts2.3.15.3: jar包: struts-2.3.15.3\apps\struts2-blank.war\W ...
- 实战小项目之基于yolo的目标检测web api实现
上个月,对微服务及web service有了一些想法,看了一本app后台开发及运维的书,主要是一些概念性的东西,对service有了一些基本了解.互联网最开始的构架多是cs构架,浏览器兴起以后,变成了 ...
随机推荐
- 【每日一题】7.月月查华华的手机 (枚举 or 序列自动机)
题目链接:Here 题意总结:\(N\) 次查询串 \(B\) 是否是 \(A\) 的子序列. 思路一 个人做法,枚举原字符串的每一位,如果匹配当前字符串的字符则 m++ 直到字符串枚举完毕或者 m ...
- Codeforces Round #677 (Div. 3) (A - E题题)
1433A. Boring Apartments #include <bits/stdc++.h> using namespace std; int main() { int t; cin ...
- Java 开发手册 (阿里巴巴开发手册)
Java 开发手册 (有需要pdf版本的私信我,可以邮箱发)0版本号 制定团队 更新日期 备注 1.4.0 阿里巴巴集团技术团队 2018.5.20 增加设计规约(详尽版) 一.编程规约 (一) 命名 ...
- el-table在flex布局下宽度不能自适应的解决方法
https://blog.csdn.net/Komorebi_00/article/details/127566867
- Webpack Vue瘦身,感受快到飞起的加载速度!
症结 在利用webpack脚手架搭建vue项目后,往往最终打包的.js和.css文件过于庞大,造成首次加载的时候白屏时间过长,影响用户体验,下图为未经任何优化直接npm run build之后的情况: ...
- P1765
和那道题一样,这次用的getchar,结果对了可是洛谷评测WA了,换成scanf单个字符,结果还是WA了,换成直接getline读入整个字符串就对了. 可见读入单个字符的方式有可能出现各种小错,尤其是 ...
- 如何与chatgpt共存
作为程序员,专注于创造性劳动,而把重复性劳动任务交给chatgpt,要成为 需求 和 chatgpt的桥梁. 人工智能比如chatgpt越来越强,提问能力是人类的天赋,提问能力更为重要.
- 【TouchGFX】代码结构
生成代码与用户代码 代码结构图示如下 据上图显示代码结构分为三层 引擎 这是TouchGFX提供的标准类,作为生成类的基类 生成 这是touchgfx designer生成的类,作为用户类的基类,这部 ...
- Kafka 社区KIP-382中文译文(MirrorMaker2/集群复制/高可用/灾难恢复)
译者:对于Kafka高可用的课题,我想每个公司都有自己的方案及思考,这是一个仁者见仁智者见智的命题,而社区给出了一个较大的特性,即MirrorMaker 2.0,不论是准备做高可用还是单纯的数据备份, ...
- [转帖]mysql 里 CST 时区的坑
mysql 里 CST 时区的坑 一.问题简述 mysql 里 CST 时区是个非常坑的概念,因为在 mysql 里CST既表示中国也表示美国的时区.但是在Jdk代码里,CST 这个字符串被理解为Ce ...