目录
(1)项目可行性分析
(一)技术可行性:
(二)经济可行性:
(三)社会可行性:
(2)需求描述
功能模块图
用例图:
(3)界面原型
1.登录:
2.注册:
3.我的:
4.分类:
5.记录:
6.主页:
(4)数据库设计
(1)User表:
(2)Notes表:
(3)Type表:
E-r图如下:
数据库的sql文件:
(5)后端工程
common包:
R.java
config包:
CorsConfig.java
domain包:
Notes.java
Type.java
User.java
utils包:
PathUtils.java
controller包:
NotesController.java
TypeController.java
UploadController.java
UserController.java
service包:
NotesService
OssUploadService
TypeService
UserService
Impl包:
NotesServiceImpl.java
OssUploadServiceImpl.java
TypeServiceImpl.java
UserServiceImpl.java
(6)前端工程
index.js
pages.json
addNote.vue
catNote.vue
Login.vue
Main.vue
mine.vue
Register.vue
接下来我们使用uniapp+springboot实现一个简单的前后端分离的小项目----个人备忘录系统,适合初学者学习,全文大约5w字,全部免费,以下是详细步骤:
(1)项目可行性分析
(一)技术可行性:
1.uniapp是一个基于Vue.js框架的跨平台开发工具,可以在多个平台上实现一次开发多端运行。它提供了丰富的组件和插件,使得开发变得更加高效。
2.uniapp支持多个主流的移动端平台,如iOS和Android,以及微信小程序、H5等。这意味着你可以通过uniapp开发一个备忘录系统,并在多个平台上发布和使用。
3.Vue.js作为uniapp的底层框架,拥有活跃的开发社区和丰富的生态系统,可以提供大量的资源和支持。
(二)经济可行性:
1.uniapp的开发成本相对较低,因为它使用了一套代码可以覆盖多个平台的开发方式,减少了重复的工作量和开发时间。
2.由于uniapp支持多个主流平台,你可以在不同的平台上发布你的备忘录系统,扩大用户群体,增加潜在的收入来源。
3.uniapp的跨平台特性可以降低维护成本,因为你只需要维护一套代码,而不是针对每个平台都进行独立的开发和维护。
(三)社会可行性:
1.备忘录系统是一个常见且实用的应用,它可以帮助个人记录重要事项、提醒任务等。这种类型的应用在社会中有广泛的需求。
2.通过使用uniapp开发备忘录系统,你可以满足不同用户使用不同平台的需求,提高用户体验和满意度。
3.在移动互联网时代,人们越来越依赖手机和移动应用程序进行工作和生活管理。开发备忘录系统可以满足人们随时随地记录和查看备忘录的需求,符合社会的发展趋势。
(2)需求描述
个人备忘录系统主要有登录、注册、查看所有备忘录、创建新的备忘录、删除备忘录、修改备忘录、根据分类查询已完成或未完成的备忘录。
功能模块图
用例图:
(3)界面原型
主要界面如下:
1.登录:
2.注册:
3.我的:
4.分类:
5.记录:
6.主页:
(4)数据库设计
数据库主要有三个表:
(1)User表:
表名 | 类型 | 长度 | 注释 |
id | int | 255 | id |
username | varchar | 255 | 用户名 |
password | varchar | 255 | 密码 |
avatar | varchar | 255 | 头像 |
(2)Notes表:
表名 | 类型 | 长度 | 注释 |
id | int | 255 | id |
rid | int | 255 | 用户id |
detail | varchar | 255 | 内容 |
time | datetime | 255 | 截止时间 |
type | int | 255 | 类型 |
finish | int | 255 | 任务是否完成 |
(3)Type表:
表名 | 类型 | 长度 | 注释 |
typeid | int | 255 | 主键 |
type | varchar | 255 | 是什么类型 |
E-r图如下:
数据库的sql文件:
/* Navicat Premium Data Transfer Source Server : mySQL Source Server Type : MySQL Source Server Version : 80019 Source Host : localhost:3305 Source Schema : memo Target Server Type : MySQL Target Server Version : 80019 File Encoding : 65001 Date: 25/12/2023 11:06:46 */ SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for notes -- ---------------------------- DROP TABLE IF EXISTS `notes`; CREATE TABLE `notes` ( `id` int(0) NOT NULL AUTO_INCREMENT COMMENT 'note表的id', `rid` int(0) NOT NULL COMMENT '这个笔记是哪个人的', `detail` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '笔记的内容', `photo` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '用户上传的图片,null或者0表示无', `time` datetime(0) NOT NULL COMMENT '笔记的创建时间', `type` int(0) NOT NULL COMMENT '笔记的类型', `finish` int(0) NOT NULL COMMENT '任务是否完成', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 57 CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of notes -- ---------------------------- INSERT INTO `notes` VALUES (31, 13, '软件设计师考试', 'http://s6422okdy.hn-bkt.clouddn.com/2023/12/23/e7bbeaecf4984a72af03d6d623a4f96c.jpg', '2023-11-04 00:04:28', 2, 1); INSERT INTO `notes` VALUES (32, 13, '国奖答辩', NULL, '2023-10-16 20:26:27', 2, 1); INSERT INTO `notes` VALUES (33, 13, 'hehang-blog数据库项目', NULL, '2024-01-07 20:26:56', 2, 1); INSERT INTO `notes` VALUES (34, 13, '数据库详细设计报告', NULL, '2023-11-08 20:27:24', 2, 1); INSERT INTO `notes` VALUES (35, 13, '数据库课设验收', NULL, '2023-11-22 20:28:02', 2, 1); INSERT INTO `notes` VALUES (36, 13, '计算机组成原理期中考试', NULL, '2023-11-24 20:28:44', 2, 1); INSERT INTO `notes` VALUES (37, 13, '计算机能力挑战赛C语言', NULL, '2023-11-25 08:00:00', 2, 1); INSERT INTO `notes` VALUES (38, 13, '学生代表大会', '0', '2023-12-07 13:15:00', 3, 1); INSERT INTO `notes` VALUES (39, 13, '闪聚支付springclound项目', NULL, '2023-12-19 18:30:21', 2, 1); INSERT INTO `notes` VALUES (40, 13, '英语四级考试', NULL, '2023-12-16 09:00:00', 2, 1); INSERT INTO `notes` VALUES (41, 13, '数据库课设详细设计文档', '0', '2024-01-07 23:59:59', 2, 0); INSERT INTO `notes` VALUES (43, 13, '完成代码细节的修改', NULL, '2023-12-18 12:00:00', 2, 1); INSERT INTO `notes` VALUES (44, 14, '记得吃药', '0', '2023-12-24 14:57:57', 8, 0); INSERT INTO `notes` VALUES (45, 14, '写完uniapp期末课设的报告', '', '2023-12-24 14:08:58', 2, 1); INSERT INTO `notes` VALUES (47, 13, '计算机能力挑战赛决赛\n地点:武汉纺织大学阳光校区', 'http://s6422okdy.hn-bkt.clouddn.com/2023/12/23/daa53bce645146d08531649be4308db4.jpg', '2023-12-09 09:00:00', 2, 1); -- ---------------------------- -- Table structure for type -- ---------------------------- DROP TABLE IF EXISTS `type`; CREATE TABLE `type` ( `typeid` int(0) NOT NULL COMMENT '主键', `type` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '是什么类型', PRIMARY KEY (`typeid`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of type -- ---------------------------- INSERT INTO `type` VALUES (1, '日常'); INSERT INTO `type` VALUES (2, '学习'); INSERT INTO `type` VALUES (3, '工作'); INSERT INTO `type` VALUES (4, '娱乐'); INSERT INTO `type` VALUES (5, '社交'); INSERT INTO `type` VALUES (6, '家庭'); INSERT INTO `type` VALUES (7, '个人'); INSERT INTO `type` VALUES (8, '健康'); INSERT INTO `type` VALUES (9, '财务'); -- ---------------------------- -- Table structure for user -- ---------------------------- DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `id` int(0) NOT NULL AUTO_INCREMENT COMMENT '用户的id', `username` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '用户名字', `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '用户密码', `avatar` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '用户的头像', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 16 CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of user -- ---------------------------- INSERT INTO `user` VALUES (13, 'hehang', '123456', 'https://img2.baidu.com/it/u=3841326637,2519425910&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=501'); INSERT INTO `user` VALUES (14, 'abcd', '123456', 'https://pic2.zhimg.com/v2-fc348d5e926116782149d2151dc09834.jpg'); INSERT INTO `user` VALUES (15, 'mynote', '123456', 'https://img2.baidu.com/it/u=3841326637,2519425910&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=501'); INSERT INTO `user` VALUES (16, '1234', '123456', 'https://img2.baidu.com/it/u=3841326637,2519425910&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=501'); SET FOREIGN_KEY_CHECKS = 1;
(5)后端工程
首先打开IDEA,选择创建Spring Initializr,按照以下配置,jdk版本无法选择jdk1.8,先不管,进去以后可以改,具体操作可以看我的另一篇相关的博客
配置spring版本,先选择3.2.0,进入项目后再通过pom文件修改
进入项目后修改pom.xml文件为如下配置,我们在pom中手动修改了jdk版本为1.8,spring为2.7.8,这样兼容性比较好,修改后记得刷新maven
4.0.0 org.springframework.boot spring-boot-starter-parent 2.7.8 com.example Memo-hehang 0.0.1-SNAPSHOT hehang memo 1.8 org.springframework.boot spring-boot-starter-web org.mybatis.spring.boot mybatis-spring-boot-starter 2.3.0 org.mybatis.spring.boot mybatis-spring-boot-starter 2.3.0 org.springframework.boot spring-boot-starter-data-jpa com.mysql mysql-connector-j runtime org.projectlombok lombok true org.springframework.boot spring-boot-starter-test test com.baomidou mybatis-plus-boot-starter 3.4.2 com.qiniu qiniu-java-sdk [7.13.0, 7.13.99] com.google.code.gson gson 2.10.1 org.springframework.boot spring-boot-maven-plugin org.projectlombok lombok org.apache.maven.plugins maven-compiler-plugin 9 9
然后我们修改resources文件夹下的application.yml,数据库连接修改成你自己的,七牛云的使用可以看我上一篇博客
server: port: 2023 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3305/memo?characterEncoding=utf-8&serverTimezone=Asia/Shanghai username: root password: 123456 mybatis-plus: global-config: db-config: id-type: auto # configuration: # log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打开七牛云,找到密钥管理,把相关信息填写到下面3行 myoss: accessKey: yourAK secretKey: yourSK bucket: yourbucket
接下来在项目下创建如下几个包:
common包:
R.java
在common文件下创建 R.java 类,主要用于封装返回给前端的数据:
package com.example.memohehang.common; import lombok.Data; import java.io.Serializable; /** * 统一返回类型 */ @Data public class R implements Serializable { private int code; // 200是正常,非200表示异常 private String msg; private Object data; public static R success(Object data) { return success(200, "操作成功", data); } public static R success(int code, String msg, Object data) { R r = new R(); r.setCode(code); r.setMsg(msg); r.setData(data); return r; } public static R error(int i, String msg) { return error(400, msg, null); } public static R error(String msg, Object data) { return error(400, msg, data); } public static R error(int code, String msg, Object data) { R r = new R(); r.setCode(code); r.setMsg(msg); r.setData(data); return r; } }
config包:
CorsConfig.java
在config包下创建 CorsConfig.java 类,用于解决前端跨域问题,在config.AllowedOrigin中填写你自己的前端端口,一般为8080,或者填 * ,允许所有
package com.example.memohehang.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.filter.CorsFilter; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.cors.CorsConfiguration; //解决前端跨域问题 @Configuration public class CorsConfig { @Bean public CorsFilter corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration config = new CorsConfiguration(); config.addAllowedOrigin("http://localhost:8080"); config.addAllowedHeader("*"); config.addAllowedMethod("*"); config.setAllowCredentials(true); source.registerCorsConfiguration("/**", config); return new CorsFilter(source); } }
domain包:
对应数据库的实体类
Notes.java
这里我们利用jsonformat注解进行时间格式化
package com.example.memohehang.domain; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.fasterxml.jackson.annotation.JsonFormat; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.util.Date; @Data @AllArgsConstructor @NoArgsConstructor public class Notes { @TableId(value = "id", type = IdType.AUTO) private Integer id; private Integer rid; // 内容 private String detail; // 截止时间 @JsonFormat(locale = "zh", timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") private Date time; // 类型 private Integer type; //图片 private String photo; // 是否完成 0表示还没有 1表示完成了 private Integer finish; }
Type.java
package com.example.memohehang.domain; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class Type { private Integer typeid; private String type; }
User.java
package com.example.memohehang.domain; import lombok.AllArgsConstructor; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class User { //主键自增 @TableId(value = "id", type = IdType.AUTO) private Integer id; private String username; private String password; // 头像 private String avatar; }
utils包:
PathUtils.java
这是对上传的文件进行重命名,在后面的七牛云相关的service中会用到
package com.example.memohehang.utils; import java.text.SimpleDateFormat; import java.util.Date; import java.util.UUID; //对原始文件名进行修改文件名,并修改存放目录 public class PathUtils { public static String generateFilePath(String fileName) { //根据日期生成路径 SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd/"); String datePath = sdf.format(new Date()); //uuid作为文件名 String uuid = UUID.randomUUID().toString().replaceAll("-", ""); //后缀和文件后缀一致 int index = fileName.lastIndexOf("."); // test.jpg -> .jpg String fileType = fileName.substring(index); return new StringBuilder().append(datePath).append(uuid).append(fileType).toString(); } }
我一般写代码的顺序为:Controller----service----serviceImpl----mapper,在方法学一般先写调用体,根据调用写对应的实现,下面我们按照这个顺序来写:
controller包:
NotesController.java
package com.example.memohehang.controller; import com.example.memohehang.common.R; import com.example.memohehang.domain.Notes; import com.example.memohehang.service.NotesService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; @Controller @RequestMapping("/note") public class NotesController { @Autowired private NotesService notesService; // 添加 @RequestMapping("/save") @ResponseBody public R save(@RequestBody Notes notes) { System.out.println("添加备忘录:" + notes); return notesService.addNote(notes); } // 根据noteid查询对应的note @RequestMapping ("/selectByNote/{noteid}") @ResponseBody public R selectByNote(@PathVariable("noteid") Integer noteid) { return notesService.selectByNote(noteid); } // 查询 只显示用户自己的 @RequestMapping ("/selectAllByUserID/{userid}") @ResponseBody public R selectAllById(@PathVariable("userid") Integer userid,@RequestParam(defaultValue = "1") Integer currentPage) { return notesService.selectAllById(userid,currentPage); } // 查询最近即将截止的未完成的备忘录的时间差 @RequestMapping ("/selectTime/{userid}") @ResponseBody public R selectcutDownTime(@PathVariable("userid") Integer userid) { return notesService.selectcutDownTime(userid); } // 分类查询 @RequestMapping ("/selectByType/{userid}/{type}/{isFinish}") @ResponseBody public R selectByType(@PathVariable("userid") Integer userid, @PathVariable("type") Integer type,@PathVariable("isFinish") Integer isFinish,@RequestParam(defaultValue = "1") Integer currentPage) { return notesService.selectByType(userid,type,isFinish,currentPage); } // 修改 @RequestMapping("/update") @ResponseBody public R update(@RequestBody Notes notes) { return notesService.update(notes); } // 删除 @DeleteMapping("/delete/{id}") @ResponseBody public R delete(@PathVariable("id") Integer id) { return notesService.delete(id); } }
TypeController.java
package com.example.memohehang.controller; import com.example.memohehang.common.R; import com.example.memohehang.service.TypeService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; @Controller @RequestMapping("/type") public class TypeController { @Autowired private TypeService typeService; // 获取编号与类型的映射表 @ResponseBody @GetMapping("/getMapping") public R typeMapping() { return typeService.typeMapping(); } }
UploadController.java
package com.example.memohehang.controller; import com.example.memohehang.common.R; import com.example.memohehang.service.OssUploadService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; @RestController public class UploadController { @Autowired private OssUploadService ossUploadService; @PostMapping("/upload") public R uploadImg(MultipartFile img) { return ossUploadService.uploadImg(img); } }
UserController.java
package com.example.memohehang.controller; import com.example.memohehang.common.R; import com.example.memohehang.domain.User; import com.example.memohehang.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/user") public class UserController { @Autowired private UserService userService; // 登录功能 @RequestMapping(value = "/login", method = RequestMethod.POST) public R login(@RequestBody User user) { return userService.login(user); } // 注册功能 @RequestMapping(value = "/register", method = RequestMethod.POST) public R register(@RequestBody User user) { return userService.register(user); } // 根据用户id查询 @RequestMapping ("/selectUserById/{userid}") @ResponseBody public R selectUserById(@PathVariable("userid") Integer userid) { return userService.selectUserById(userid); } }
我们用mybatisplus自带的查询函数即可完成所有的CRUD,因此我们不需要写SQL语句
service包:
NotesService
package com.example.memohehang.service; import com.baomidou.mybatisplus.extension.service.IService; import com.example.memohehang.common.R; import com.example.memohehang.domain.Notes; import com.example.memohehang.domain.User; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; public interface NotesService extends IService { /** * 添加备忘录 * @param notes * @return */ public R addNote(Notes notes); /** * 根据noteid查询note * @param noteid * @return */ public R selectByNote(Integer noteid); /** * 查询 只显示用户自己的 * @param userid * @param currentPage * @return */ public R selectAllById(Integer userid,Integer currentPage); /** * 查询最近即将截止的未完成的备忘录的时间差 * @param userid * @return */ public R selectcutDownTime(Integer userid); /** * 分类查询 * @param userid * @param type * @param isFinish * @param currentPage * @return */ public R selectByType(Integer userid, Integer type,Integer isFinish,Integer currentPage); /** * 修改 * @param notes * @return */ public R update(Notes notes); /** * 删除 * @param id * @return */ public R delete(Integer id); }
OssUploadService
package com.example.memohehang.service; import com.example.memohehang.common.R; import org.springframework.web.multipart.MultipartFile; public interface OssUploadService { //图片上传到七牛云 R uploadImg(MultipartFile img); }
TypeService
package com.example.memohehang.service; import com.baomidou.mybatisplus.extension.service.IService; import com.example.memohehang.common.R; import com.example.memohehang.domain.Type; public interface TypeService extends IService { /** * 获取所有类型 * @return */ public R typeMapping(); }
UserService
package com.example.memohehang.service; import com.baomidou.mybatisplus.extension.service.IService; import com.example.memohehang.common.R; import com.example.memohehang.domain.User; public interface UserService extends IService { /** * 登录 * @param user * @return */ public R login(User user); /** * 注册 * @param user * @return */ public R register(User user); /** * 根据id查询用户 * @param userid * @return */ public R selectUserById(Integer userid); }
接下来在service包中创建Impl,注意第一个 “ I ” 是大写的 “ i ”,第二个是小写的 “ L ”
Impl包:
NotesServiceImpl.java
package com.example.memohehang.service.Impl; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.example.memohehang.common.R; import com.example.memohehang.domain.Notes; import com.example.memohehang.mapper.NotesMapper; import com.example.memohehang.service.NotesService; import org.springframework.stereotype.Service; import java.time.Duration; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @Service public class NotesServiceImpl extends ServiceImpl implements NotesService { private NotesMapper notesMapper; /** * 添加备忘录 * @param notes * @return */ @Override public R addNote(Notes notes) { boolean b = save(notes);//调用mybatis-plus if (b) { return R.success(200, "添加成功", null); } else { return R.error(405, "添加失败"); } } /** * 根据noteid查询note * @param noteid * @return */ @Override public R selectByNote(Integer noteid) { QueryWrapper wrapper = new QueryWrapper(); wrapper.eq("id", noteid); List note = list(wrapper); if (note == null) { return R.error(400,"查询失败"); } else { return R.success(note.get(0)); } } /** * 查询 只显示用户自己的 * @param userid * @param currentPage * @return */ @Override public R selectAllById(Integer userid, Integer currentPage) { Page page = new Page(currentPage, 20); // 查询条件 分页的基础上 再按照创建时间排序 IPage pageData = page(page, new QueryWrapper().orderByAsc("finish","time").eq("rid", userid)); return R.success(pageData); } /** * 查询最近即将截止的未完成的备忘录的时间差 * @param userid * @return */ @Override public R selectcutDownTime(Integer userid) { QueryWrapper wrapper = new QueryWrapper(); wrapper.eq("rid", userid).orderByAsc("finish", "time"); List note = list(wrapper); // 处理查询结果 if (note != null && !note.isEmpty()) { Notes firstUnfinishedNote = null; for (Notes n : note) { if (n.getFinish() == 0) { firstUnfinishedNote = n; break; } } if (firstUnfinishedNote != null) { LocalDateTime currentTime = LocalDateTime.now(); Date noteTime = firstUnfinishedNote.getTime(); Instant instant = noteTime.toInstant(); LocalDateTime noteLocalDateTime = instant.atZone(ZoneId.systemDefault()).toLocalDateTime(); Duration duration = Duration.between(currentTime, noteLocalDateTime); long days = duration.toDays(); long hours = duration.toHoursPart(); long minutes = duration.toMinutesPart(); long seconds = duration.toSecondsPart(); // 构造返回结果 Map resultMap = new HashMap(); resultMap.put("days", days); resultMap.put("hours", hours); resultMap.put("minutes", minutes); resultMap.put("seconds", seconds); System.out.println(resultMap); // 返回结果 return R.success(200, "duration", resultMap); } else { return R.error(405, "没有找到未完成的备忘录"); } } else { return R.error(405, "没有找到备忘录"); } } /** * 分类查询 * @param userid * @param type * @param isFinish * @param currentPage * @return */ @Override public R selectByType(Integer userid, Integer type, Integer isFinish, Integer currentPage) { Page page = new Page(currentPage, 20); IPage pageData = page(page, new QueryWrapper().orderByAsc("time").eq("rid", userid).eq("finish", isFinish).eq("type", type)); return R.success(pageData); } /** * 修改 * @param notes * @return */ @Override public R update(Notes notes) { System.out.println("开始更新"); System.out.println(notes); boolean b = update(notes, new QueryWrapper().eq("id", notes.getId())); if (b) { System.out.println("更新成功"); return R.success(200, "更新成功", null); } System.out.println("更新失败"); return R.error(405, "更新失败"); } /** * 删除 * @param id * @return */ @Override public R delete(Integer id) { System.out.println("user delete..." + id); boolean b = removeById(id); if (b) { return R.success(200, "删除成功", null); } return R.error(405, "删除失败"); } }
OssUploadServiceImpl.java
注意这里需要修改外链回显链接
package com.example.memohehang.service.Impl; import com.example.memohehang.common.R; import com.example.memohehang.service.OssUploadService; import com.example.memohehang.utils.PathUtils; import com.google.gson.Gson; import com.qiniu.common.QiniuException; import com.qiniu.http.Response; import com.qiniu.storage.Configuration; import com.qiniu.storage.Region; import com.qiniu.storage.UploadManager; import com.qiniu.storage.model.DefaultPutRet; import com.qiniu.util.Auth; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import java.io.InputStream; @Service @Data//为成员变量生成get和set方法 @ConfigurationProperties(prefix = "myoss") //把文件上传到七牛云 public class OssUploadServiceImpl implements OssUploadService { @Override //MultipartFile是spring提供的接口 public R uploadImg(MultipartFile img) { //获取原始文件名 String originalFilename = img.getOriginalFilename(); // 获取文件大小 long fileSize = img.getSize(); //PathUtils.generateFilePath(originalFilename)表示把原始文件名转换成指定文件名 String filePath = PathUtils.generateFilePath(originalFilename); //下面用于调用的uploadOss方法返回的必须是String类型 String url = uploadOss(img,filePath); System.out.println("外链地址:"+url); //把得到的外链地址返回给前端 return R.success(200,"操作成功",url); } //----------------------------------上传文件到七牛云---------------------------------------- //注意要从application.yml读取属性数据,下面的3个成员变量的名字必须对应application.yml的myoss属性的三个子属性名字 private String accessKey; private String secretKey; private String bucket; //上传文件的具体代码。MultipartFile是spring提供的接口,作用是实现文件上传 private String uploadOss(MultipartFile imgFile, String filePath){ //构造一个带指定 Region 对象的配置类。你的七牛云OSS创建的是哪个区域的,那么就调用Region的什么方法即可 Configuration cfg = new Configuration(Region.huanan()); cfg.resumableUploadAPIVersion = Configuration.ResumableUploadAPIVersion.V2;// 指定分片上传版本 UploadManager uploadManager = new UploadManager(cfg); //打开七牛云,把鼠标悬浮在右上角的个人头像,然后就会看到'密钥管理',点击进入就有你的密钥,把其中的AK和SK复制到下面两行 //String accessKey = "_ibGP9wytjLCAZPqcFaWQNxbw7fMUvofSOvOFFR3"; //String secretKey = "QSOAU-cv3sSDGNfVNPF6iXz-PsP5X9QTrjFI9zYw"; //String bucket = "hehang-blog"; //为避免上面3行暴露信息,我们会把信息写到application.yml里面,然后添加ConfigurationProperties注解、3个成员变量即可读取 //文件名,如果写成null的话,就以文件内容的hash值作为文件名 String key = filePath; try { //byte[] uploadBytes = "hello qiniu cloud".getBytes("utf-8"); //ByteArrayInputStream byteInputStream=new ByteArrayInputStream(uploadBytes); //上面两行是官方写的(注释掉),下面那几行是我们写的 //把前端传过来的文件转换成InputStream对象 InputStream xxinputStream = imgFile.getInputStream(); Auth auth = Auth.create(accessKey, secretKey); String upToken = auth.uploadToken(bucket); try { //把前端传过来的xxinputStream图片上传到七牛云 Response response = uploadManager.put(xxinputStream,key,upToken,null, null); //解析上传成功的结果 DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class); System.out.println("上传成功! 生成的key是: "+putRet.key); System.out.println("上传成功! 生成的hash是: "+putRet.hash); return "http://s6422okdy.hn-bkt.clouddn.com/"+key;//注意这个地方替换成自己的域名,http://不能掉 } catch (QiniuException ex) { Response r = ex.response; System.err.println(r.toString()); try { System.err.println(r.bodyString()); } catch (QiniuException ex2) { //ignore } } }catch (Exception e) { //ignore } return "上传失败"; } }
TypeServiceImpl.java
package com.example.memohehang.service.Impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.example.memohehang.common.R; import com.example.memohehang.domain.Type; import com.example.memohehang.mapper.TypeMapper; import com.example.memohehang.service.TypeService; import org.springframework.stereotype.Service; import java.util.HashMap; import java.util.List; @Service public class TypeServiceImpl extends ServiceImpl implements TypeService { /** * 获取所有类型 * @return */ @Override public R typeMapping() { List types = list(); HashMap hashMap = new HashMap(); for (Type type : types) { hashMap.put(type.getTypeid(), type.getType()); } return R.success(hashMap); } }
UserServiceImpl.java
package com.example.memohehang.service.Impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.example.memohehang.common.R; import com.example.memohehang.domain.User; import com.example.memohehang.mapper.UserMapper; import com.example.memohehang.service.UserService; import org.springframework.stereotype.Service; import java.util.List; @Service public class UserServiceImpl extends ServiceImpl implements UserService { /** * 登录 * @param user * @return */ @Override public R login(User user) { // 判断用户账号是否正确 User one = getOne(new QueryWrapper() .eq("username", user.getUsername()) .eq("password", user.getPassword()) ); if (one != null) { return R.success(200,"登录成功", one); } else { return R.error(405, "账号或密码错误"); } } @Override public R register(User user) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper(); queryWrapper.eq(User::getUsername, user.getUsername()); System.out.println(user); User tempUsername = getOne(queryWrapper); // 先判断一下用户是否存在 存在就返回false if (tempUsername != null) { return R.error(405,"账户已存在"); } else { //网上随机找的一个图片 user.setAvatar("https://img2.baidu.com/it/u=3841326637,2519425910&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=501"); // 反之加入 save(user); return R.success(user); } } /** * 根据id查询用户 * @param userid * @return */ @Override public R selectUserById(Integer userid) { // 判断用户账号是否正确 User one = getOne(new QueryWrapper() .eq("id", userid) ); if (one != null) { return R.success(200,"查询成功", one); } else { return R.error(405, "查询失败"); } } }
至此后端工程全部创建完毕,按照下图检查一下是否有缺少,注意Mapper可写也可以不写,因为我们不需要写SQL语句,不需要调用Mapper,全部完毕后就可以运行项目,利用apipost进行测试,或者前端创建完后直接集成测试
(6)前端工程
我们采用uniapp来写前端代码,按照以下步骤建立项目
输入项目名称,选择vue2
我们需要用到以下uniapp的组件,可以从uniapp组件库下载,链接为:组件使用的入门教程 | uni-app官网
对应的矢量图标可以在阿里巴巴矢量图库下载,链接为iconfont-阿里巴巴矢量图标库
然后我们在根目录下建立store文件夹,在此文件夹下建立index.js,用于存放一些函数
index.js
export function getUserid() { let userid = uni.getStorageSync("userid"); if (userid == null || userid === '') return ''; else return userid; } export function getNoteid() { let noteid = uni.getStorageSync("noteid"); if (noteid == null || noteid === '') return ''; else return noteid; } export function getUsername() { let username = uni.getStorageSync("username"); if (username == null || username === '') return ''; else return username; } export function hasLogin() { let userid = uni.getStorageSync("userid"); if (userid == null || userid === '') { return false; } else return true; } export function logout() { uni.removeStorageSync("userid"); uni.removeStorageSync("noteid"); uni.removeStorageSync("username"); uni.redirectTo({ url: "/pages/mine" }); }
随后修改pages.json中修改相关页面配置文件,可以先创建相关页面后再进行此步骤,以免编译时报错
pages.json
{ "pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages { "path": "pages/Main", "style": { "navigationBarTitleText": "个人备忘录" } } ,{ "path" : "pages/Login", "style" : { "navigationBarTitleText": "登录", "enablePullDownRefresh": false } } ,{ "path" : "pages/Main", "style" : { "navigationBarTitleText": "所有备忘录", "enablePullDownRefresh": false } }, { "path" : "pages/mine", "style" : { "navigationBarTitleText": "个人中心", "enablePullDownRefresh": false } } ,{ "path" : "pages/addNote", "style" : { "navigationBarTitleText": "添加/修改备忘录", "enablePullDownRefresh": false } } ,{ "path" : "pages/catNote", "style" : { "navigationBarTitleText": "查询备忘录", "enablePullDownRefresh": false } } ,{ "path" : "pages/Register", "style" : { "navigationBarTitleText": "注册", "enablePullDownRefresh": false } } ], "globalStyle": { "navigationBarTextStyle": "black", "navigationBarTitleText": "个人备忘录", "navigationBarBackgroundColor": "#F8F8F8", "backgroundColor": "#F8F8F8" }, "tabBar": { "list": [ { "text": "首页", "pagePath": "pages/Main", "iconPath": "static/images/首页.png", "selectedIconPath": "static/images/首页2.png" }, { "text": "记录", "pagePath": "pages/addNote", "iconPath": "static/images/记录.png", "selectedIconPath": "static/images/记录1.png" }, { "text": "分类", "pagePath": "pages/catNote", "iconPath": "static/images/分类.png", "selectedIconPath": "static/images/分类2.png" }, { "text": "我的", "pagePath": "pages/mine", "iconPath": "static/images/我的.png", "selectedIconPath": "static/images/我的2.png" } ] }, "uniIdRouter": {} }
然后再pages中建立以下页面文件,我这里没有创建同名目录
addNote.vue
{{ value }} 提交 选择文件 取消选择
上传文件 import {getUserid,getNoteid} from "@/store/index.js" export default { data(){ return{ noteId: '', userId: '', time: '', selectedType: '', types: {}, context: '', finish: false, note:{}, filePath: null, fileUrl: null, }; }, onLoad() { this.noteId = getNoteid()//获取缓存中的noteid this.userId = getUserid() uni.request({ url:`http://localhost:2023/type/getMapping`, method:"GET", success:(res)=>{ // 将返回的备忘录类型数据赋值给types数组 this.types = res.data.data } }); if(this.noteId != null && this.noteId != '') {//noteId不为空查询对应的note uni.request({ url: `http://localhost:2023/note/selectByNote/${this.noteId}`, method:"POST", success: (res) => { this.note = res.data.data //console.log(this.note); this.time = this.note.time this.selectedType = this.note.type this.context = this.note.detail this.finish = this.note.finish !== 0; //uni.removeStorageSync("noteid"); this.filePath = this.note.photo; this.fileUrl = this.note.photo } }) } }, methods: { cancelChooseFile() { this.filePath = null; this.fileUrl = null; console.log('用户取消选择文件'); }, chooseFile() { uni.chooseImage({ count: 1, success: (res) => { // 选择文件成功 this.filePath = res.tempFilePaths[0]; }, fail: (error) => { // 选择文件失败 console.error(error); }, }); }, uploadFile() { uni.uploadFile({ url: 'http://localhost:2023/upload', filePath: this.filePath, name: 'img', method:"POST", success: function (res) { // 上传成功 console.log(res); let responseData = JSON.parse(res.data); // 解析字符串为JSON对象 console.log(responseData); if(responseData.code === 200) { uni.showToast({ title: "上传成功", icon: "success", duration: 2000 }); this.fileUrl = responseData.data; console.log( "上传后:"+ this.fileUrl); uni.setStorageSync("fileurl", this.fileUrl); } else { uni.showToast({ title: "上传失败", icon: "error", duration: 2000 }); } } }) console.log(this.filePath); }, saveNote() { if(this.fileUrl === null || this.fileUrl === '0') { this.fileUrl = uni.getStorageSync("fileurl"); } //this.noteId = uni.getStorageSync('noteid') if(this.noteId === null || this.noteId === '') {//添加note // 构造备忘录的请求参数 console.log("添加:"+this.fileUrl); const note = { //id: this.noteId, rid: this.userId, detail: this.context, time: this.time, type: this.selectedType, finish: this.finish ? 1 : 0, photo: this.fileUrl ? this.fileUrl : 0 } uni.request({ url: 'http://localhost:2023/note/save', method: 'POST', data: note, success: (res) => { // 备忘录添加成功的处理逻辑 if(res.data.code === 200) { uni.showToast({ title: "添加成功", icon: "success", duration: 2000 }); } else { uni.showToast({ title: "添加失败", icon: "error", duration: 2000 }); } } }) } else {//更新note,更新完后要在缓存中移除noteid console.log("更新:" +this.fileUrl); const notes = { id: this.noteId, rid: this.userId, detail: this.context, time: this.time, type: this.selectedType, finish: this.finish ? 1 : 0, photo: this.fileUrl ? this.fileUrl : 0//因为mybatisplus不能更新为null } uni.request({ url: 'http://localhost:2023/note/update', method: 'POST', data: notes, success: (res) => { // 备忘录更新成功的处理逻辑 if(res.data.code === 200) { uni.showToast({ title: "修改成功", icon: "success", duration: 2000 }); } else { uni.showToast({ title: "修改失败", icon: "error", duration: 2000 }); } uni.removeStorageSync("noteid"); this.userId = null; } }) } uni.removeStorageSync("fileurl"); uni.reLaunch({ url:`/pages/Main` }); }, } } .example { padding: 15px; background-color: #fff; } .segmented-control { margin-bottom: 15px; } .button-group { margin-top: 15px; display: flex; justify-content: space-around; } .form-item { display: flex; align-items: center; } .button { display: flex; align-items: center; height: 35px; margin-left: 10px; } .select{ //display: flex; //align-items: center; height: 65rpx; width: 250rpx; background-color: #fff; border-radius: 10rpx; //margin-left: 10px; } .button-container { display: flex; /* 使用flex布局 */ justify-content: center; /* 水平居中对齐按钮 */ } .myimg{ width: 600rpx; height: 400rpx; }
catNote.vue
{{ value }} 查询截止日期:{{note.time}}
内 容:{{note.detail}}
任务类型:{{types[""+note.type]}}
是否完成:{{ note.finish === 1 ? "完成" : "未完成" }}
import {getUserid} from "@/store/index.js" export default { data() { return { userId: '', selectedType: '', finish: false, types: {}, notes: {}, currentPage: 0, total: 0, pageSize: 0, options:[ { text: '删除', style: { backgroundColor: '#dd524d' } } ], }; }, onLoad() { this.userId = getUserid(); uni.request({ url:`http://localhost:2023/type/getMapping`, method:"GET", success:(res)=>{ // 将返回的备忘录类型数据赋值给types数组 this.types = res.data.data } }); }, methods:{ findNotes() { const isfinish = this.finish ? 1 : 0 uni.request({ url:`http://localhost:2023/note/selectByType/${this.userId}/${this.selectedType}/${isfinish}?currentPage=${this.currentPage}`, method:"POST", success:(res)=>{ this.notes = res.data.data.records this.currentPage = res.data.data.current this.total = res.data.data.total this.pageSize = res.data.data.size } }); }, onReachBottom(){ this.pageSize += 1; this.findNotes(); }, bindClick(noteid) { uni.showmodal({ title: "是否确定删除", success: res => { if (res.confirm) { //删除 uni.request({ url:`http://localhost:2023/note/delete/${noteid}`, method:"DELETE", success:(res)=>{ //删除成功 uni.showToast({ title: "删除成功", icon: "success", duration: 2000 }); uni.reLaunch({ url:`/pages/catNote` }); } }); } } }); }, updateNote(id){ uni.setStorageSync("noteid",id); uni.reLaunch({ url:`/pages/addNote` }); }, } } .select{ //display: flex; //align-items: center; height: 65rpx; width: 250rpx; background-color: #fff; border-radius: 10rpx; //margin-left: 10px; } .select2{ //display: flex; //align-items: center; height: 55rpx; width: 50rpx; background-color: #fff; border-radius: 10rpx; //margin-left: 10px; } .finished { color: green; /* 已完成的备忘录显示为绿色 */ } .unfinished { color: red; /* 未完成的备忘录显示为红色 */ } .myimg{ width: 600rpx; height: 400rpx; }
Login.vue
登录 没有账号,注册一个 import {getUserid} from "@/store/index.js" export default { data() { return { user: { id:"", username: "", password: "", avatar:"" }, }; }, methods:{ submitForm() { this.$refs.form.validate().then((res) => { uni.request({ url: `http://localhost:2023/user/login`, method: "POST", data: { username: this.user.username, password: this.user.password }, success: (result) => { if (result.data.code === 200) { uni.showToast({ title: "登录成功", icon: "success", duration: 2000 }); setTimeout(() => { this.user = result.data.data, uni.setStorageSync("userid", result.data.data.id); uni.setStorageSync("username", result.data.data.username); uni.reLaunch({ url: "/pages/Main" }) }, 2000); } else { uni.showToast({ title: result.data.msg, icon: "error" }); } } }); }); }, gotoRegister() { uni.reLaunch({ url: "/pages/Register" }) } } } .loginform { margin: 6rpx; .submit { background-color: $uni-color-primary; color: white; } .noaccount { font-size: 30rpx; display: flex; justify-content: space-between; margin: 10rpx; text { color: red; } } }
Main.vue
截止日期:{{note.time}}
内 容:{{note.detail}}
任务类型:{{typeMap[""+note.type]}}
是否完成:{{ note.finish === 1 ? "完成" : "未完成" }}
import {getUserid,getUsername} from "@/store/index.js" export default { data() { return { imgP:"https://img2.baidu.com/it/u=3841326637,2519425910&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=501", options:[ { text: '删除', style: { backgroundColor: '#dd524d' } } ], userid:0, user:{}, notes: [], currentPage: 0, total: 0, pageSize: 0, typeMap:{}, finish:0, msg:'', days:0, hours:0, minutes:0, seconds:0, }; }, methods:{ showNotes(){ uni.request({ url:`http://localhost:2023/note/selectAllByUserID/${this.userid}?currentPage=${this.currentPage}`, method:"POST", success:(res)=>{ this.notes = res.data.data.records this.currentPage = res.data.data.current this.total = res.data.data.total this.pageSize = res.data.data.size } }); uni.request({ url:`http://localhost:2023/type/getMapping`, method:"GET", success:(res)=>{ this.typeMap = res.data.data; } }); }, updateNote(id){ uni.setStorageSync("noteid",id); uni.reLaunch({ url:`/pages/addNote` }); }, bindClick(noteid) { uni.showModal({ title: "是否确定删除", success: res => { if (res.confirm) { //删除 uni.request({ url:`http://localhost:2023/note/delete/${noteid}`, method:"DELETE", success:(res)=>{ //删除成功 if(res.data.code === 200) { uni.showToast({ title: "删除成功", icon: "success", duration: 2000 }); uni.reLaunch({ url:`/pages/Main` }); } else { uni.showToast({ title: "删除失败", icon: "error", duration: 2000 }); } } }); } } }); }, SetCountdown() { uni.request({ url:`http://localhost:2023/note/selectTime/${this.userid}`, method:"GET", success:(res)=>{ const { days, hours, minutes, seconds } = res.data.data this.days = parseInt(days) this.hours = parseInt(hours) this.minutes = parseInt(minutes) this.seconds = parseInt(seconds) } }); }, }, onLoad(){ this.userid = getUserid(); this.showNotes(); this.msg = '欢迎' + getUsername() + '回来,您有以下几条待办事件'; this.SetCountdown(); }, onReachBottom(){ this.pageSize += 1; this.showNotes(); }, } .a0{ //align-items: center; padding-left: 40rpx; } .a1{ border: 1px solid #ccc; border-radius: 5rpx; width: 650rpx; //text-align: center; //display: flex; // justify-content: center; // align-items: center; padding-left: 10rpx; padding-top: 20rpx; } .content-box { flex: 1; /* #ifdef APP-NVUE */ justify-content: center; /* #endif */ height: 44px; line-height: 44px; padding: 0 15px; position: relative; background-color: #fff; border-bottom-color: #f5f5f5; border-bottom-width: 1px; border-bottom-style: solid; } .content-text { font-size: 15px; } .example-body { /* #ifndef APP-NVUE */ display: flex; /* #endif */ flex-direction: row; justify-content: center; padding: 10px 0; background-color: #fff; } .button { border-color: #e5e5e5; border-style: solid; border-width: 1px; padding: 4px 8px; border-radius: 4px; } .button-text { font-size: 15px; } .slot-button { /* #ifndef APP-NVUE */ display: flex; height: 100%; /* #endif */ flex: 1; flex-direction: row; justify-content: center; align-items: center; padding: 0 20px; background-color: #ff5a5f; } .slot-button-text { color: #ffffff; font-size: 14px; } .finished { color: green; /* 已完成的备忘录显示为绿色 */ } .unfinished { color: red; /* 未完成的备忘录显示为红色 */ } .container { /* #ifndef APP-NVUE */ position: absolute; left: 0; right: 0; top: 0; bottom: 0; /* #endif */ } .myimg{ width: 600rpx; height: 400rpx; }
mine.vue
退出登录 import { hasLogin, logout, getUserid } from '@/store/index.js' export default { data() { return { user: { username: null, //用户账号 avatar: null, //个人照片 } }; }, onLoad() { if (hasLogin()) { this.getUserInfo(); } }, methods: { gotoLogin() { //跳转到的登录页面 uni.redirectTo({ url:"/pages/Login" }); }, getUserInfo() { this.userid = getUserid(); if (this.userid != null) { uni.request({ url: `http://localhost:2023/user/selectUserById/${this.userid}`, method: "GET", success: (res) => { this.user = res.data.data; } }); } }, gotoLogout() { uni.showModal({ title: "是否确定退出", success: res => { if (res.confirm) { logout(); this.user = { username: null, avatar: null, } } } }); } } } .mine { margin: 30rpx 30rpx; .top { display: flex; flex-direction: column; justify-content: space-between; .userinfo { display: flex; flex: row; justify-content: space-between; align-items: center; .group { display: flex; align-items: center; .pic { width: 120rpx; height: 120rpx; border-radius: 50%; overflow: hidden; border: 2rpx solid red; margin-right: 10rpx; image { width: 100%; height: 100%; } } .login { margin-left: 16rpx; font-size: 40rpx; } } .more { .iconfont { font-size: 40rpx; } } } .bloginfo { display: flex; flex: row; margin-top: 20rpx; view { margin-right: 30rpx; font-size: 26rpx; } } } .itemgroup { border-top: 4rpx solid #f4f4f4; margin-top: 30rpx; .item { padding: 24rpx 0; display: flex; justify-content: space-between; align-items: center; .left { text { margin-right: 16rpx; font-size: 36rpx; } } } } }
Register.vue
注册 export default { data() { return { user: {}, rules: { username: { rules: [{ required: true, errorMessage: '请输入账号', }, { minLength: 2, maxLength: 20, errorMessage: '账号长度在 {minLength}到 {maxLength}个字符 ', } ] }, password: { rules: [{ required: true, errorMessage: '请输入密码', }, { minLength: 2, maxLength: 20, errorMessage: '密码长度在 {minLength}到 {maxLength}个字符 ', } ] }, passwordconfirm: { rules: [{ required: true, errorMessage: '请输入密码', }, { minLength: 2, maxLength: 20, errorMessage: '密码长度在 {minLength}到 {maxLength}个字符 ', }, { validateFunction: function(rule, value, data, callback) { if (value !== data.password) { callback("两次输入的密码不一致"); } return true; } } ] }, } }; }, methods: { submitForm() { this.$refs.form.validate().then((res) => { Reflect.deleteProperty(this.user, "passwordconfirm"); // console.log('user 模型',this.user); uni.request({ url: "http://localhost:2023/user/register", method: "POST", data: { username: this.user.username, password: this.user.password, }, success: (result) => { if (result.data.msg) { uni.showToast({ title: "用户注册成功", duration: 2000 }); //注册成功则转到登录页面 setTimeout(() => { uni.redirectTo({ url: "/pages/Login" }); this.user = {}; }, 2000); } else { uni.showToast({ title: result.data.describe, duration: 2000, icon: "error" }) } } //end of success }); }).catch(err => { // console.log(err); }) }, } } .registerform { margin: 6rpx; .submit { background-color: $uni-color-primary; color: white; } }
到这里前后端代码已经全部完成,下面是运行的截图
到此全部结束啦,如果此文章对你有帮助,希望给一个关注+点赞+收藏
若需要源码可以私信我,免费分享