当前位置: 首页 > news >正文

【微信小程序】每日心情笔记

个人团队的比赛项目,仅供学习交流使用

一、项目基本介绍

1. 项目简介

一款基于微信小程序的轻量化笔记工具,旨在帮助用户通过记录每日心情和事件,更好地管理情绪和生活。用户可以根据日期和心情分类(如开心、平静、难过等)记录笔记,并随时查看历史记录。同时,项目还包含一个后台运营端小程序,用于数据统计、用户行为分析、用户反馈收集与回复,为运营决策提供支持。代码已上传至GitHub

2. 技术栈

微信小程序原生开发(JS、WXML、WXSS)、SpringBoot、MySQL、RESTful API、Postman接口测试、Axure

3. 项目功能

(1)用户端

微信授权登录

在这里插入图片描述

主界面:该功能模块主要包括显示日历、显示笔记、删除单条笔记。

  • 显示日历:日历供用户选择查看日期,当日总体心情为日期小角标,用户点击日期即可在页面下方显示该日笔记。

  • 显示笔记:底部笔记栏呈现所选日按修改时间进行排序的笔记(默认为当日),若无笔记出现"今日还未写笔记噢!"提示。

  • 删除单条笔记:右滑笔记出现删除按钮,并弹出提示框。

    在这里插入图片描述

个人中心:该功能模块主要包括反馈、分享、我的信箱与退出登录。

  • 反馈:用户在反馈渠道提出意见。

  • 分享:将小程序转发给微信好友。

  • 我的信箱:管理员向用户下发通知,用户在我的信箱查看

  • 退出登录:退出登录后再次登录需要再次授权。

    在这里插入图片描述

    在这里插入图片描述

    笔记记录:该功能模块主要功能包括心情选择和写笔记。

    • 心情选择:用户可在心情图案列表中选择本条笔记记录时的心情;若本条笔记为当日第二条及以上,自动弹出当日总体心情选择界面;在日历上方可以改变总体心情,若没有选择总体心情则会出现"今日还未选择总体心情哦"提示。

    • 写/修改笔记:用户可自由进行笔记记录或修改笔记内容及此条笔记心情。

      在这里插入图片描述

(2)开发者端

微信授权与密钥登陆

在这里插入图片描述

官方通知:发布官方通知下发到每一个用户

在这里插入图片描述

反馈回执:针对不同用户的返回发送回执
在这里插入图片描述

在这里插入图片描述

二、项目代码分析

1. 项目代码架构

前端小程序项目结构(以用户端为例)

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

后端Java项目结构

在这里插入图片描述

2.前端代码分析(以用户端主页面为例)

main.js
const util = require('../../utils/util.js')
var app = getApp()
Page({data: {avatarUrl: "/images/头像.png",nickName: '未登录',date: null,daymood: '今日还未选心情',moodList: new Array(),noteList: new Array(),noteisHave: false,year: 0,month: 0,head: ['日', '一', '二', '三', '四', '五', '六'],dateArr: [],isToday: 0,pickToday: 0,isTodayWeek: false,todayIndex: 0,nottoday: false,havenote:'今日还未写笔记哦!'},onShow() {let date = new Date();let now = new Date();let year = now.getFullYear();let month = now.getMonth() + 1;console.log(0)this.dateInit();this.setData({year: year,month: month,isToday: '' + year + '-' + month + '-' + now.getDate(),avatarUrl: app.globalData.avatarUrl,nickName: app.globalData.nickName,date: util.formatDate(date)})console.log(3)this.daymoodinit(util.formatYearDate(now)[0]);console.log(5)this.noteinit(util.formatYearDate(now)[0]);},noteinit(date) {var that = this//请求获取笔记列表wx.request({url: app.globalData.url + '/getNoteList',data: {uid: wx.getStorageSync('uid'),date: date},header: {'content-type': 'application/json'},success(res) {console.log(6)//获取后端传入的笔记列表var notelist = res.data.noteList//如果笔记列表不为空if (notelist) {//创建微信小程序存储数组值的变量var noteList = new Array();//创建构造函数notefunction Note(nid, context, time, mood) {this.nid = nid;this.context = context;this.time = time;this.mood = mood;}//遍历后端传来的值,将其加到我的数据中for (var i = 0; i < notelist.length; i++) {//对心情处理notelist[i].mood = '/images/' + notelist[i].mood + '.png';//赋值var note = new Note(notelist[i].nid, notelist[i].context+'...', notelist[i].time, notelist[i].mood)noteList[i] = note}//设置值that.setData({//笔记列表noteList: noteList,noteisHave: true})}}})},daymoodinit(date) {var that = thiswx.request({//获取某日的总体心情url: app.globalData.url + '/gDateMood',data: {uid: wx.getStorageSync('uid'),date: date},header: {'content-type': 'application/json'},success(res) {console.log(4)if (res.data.daymood) {if (date == util.formatYearDate(new Date())) {that.setData({daymood: '今日心情:' + res.data.daymood})} else {that.setData({daymood: '该日心情:' + res.data.daymood})}} else {if (date == util.formatYearDate(new Date())) {that.setData({daymood: '今日还未选心情'})} else {that.setData({daymood: '该日未记录心情'})}}}//为测试所用,正式直接删掉// fail() {//   that.setData({//     daymood: '今日心情:开心'//   })// }})},backnow() {var date = {date: util.formatYearDate(new Date()).toString()}this.date(date)//自动展示为当前月份的日历页面this.dateInit()this.setData({nottoday: false})},date(e) {//判断是从组件传的值(即点击日期)还是从函数传的值(即点击回到今日)if (e.date) {var date = e.date} else {var date = e.currentTarget.dataset.date}//转换日期var dates = date.split("-")var month = dates[1]var day = dates[2]var thisdate = month + '月' + day + '日'if(date == util.formatYearDate(new Date())){this.setData({noteisHave: false,pickToday: date,date: thisdate,nottoday: false,havenote:'今日还未写笔记哦!'})}else{this.setData({noteisHave: false,pickToday: date,date: thisdate,nottoday: true,havenote:'该日还未写笔记哦!'})}//修改页面总体心情this.daymoodinit(date)//向后端请求日期下的笔记列表this.noteinit(date)},add() {wx.navigateTo({url: '/pages/notemood/notemood'})},daymood() {wx.showModal({title: '只能修改今日总体心情',content: '确认要修改吗?',success(res) {if (res.confirm) {wx.navigateTo({url: '/pages/daymood/daymood'})}}})},mine() {wx.navigateTo({url: '/pages/mine/mine',})},changenote(e) {//需向后端传入标识,表示是第一次进入修改笔记页面,目的为保证渲染层的正确var note = e.currentTarget.dataset.notevar nid = note.nidvar time = note.timevar mood = note.moodwx.redirectTo({url: '/pages/note/note?mood=' + mood + '&nid=' + nid + '&time=' + time + '&flag=1',})},dateInit: function (setYear, setMonth) {//全部时间的月份都是按0~11基准,显示月份才+1let dateArr = []; //需要遍历的日历数组数据let arrLen = 0; //dateArr的数组长度let now = setYear ? new Date(setYear, setMonth) : new Date();let year = setYear || now.getFullYear();let nextYear = 0;let month = setMonth || now.getMonth(); //没有+1方便后面计算当月总天数let nextMonth = (month + 1) > 11 ? 1 : (month + 1);let startWeek = new Date(year + ',' + (month + 1) + ',' + 1).getDay(); //目标月1号对应的星期let dayNums = new Date(year, nextMonth, 0).getDate(); //获取目标月有多少天let obj = {};let num = 0;if (month + 1 > 11) {nextYear = year + 1;dayNums = new Date(nextYear, nextMonth, 0).getDate();}var that = thisconsole.log(1)//得到当月心情表从后端wx.request({url: app.globalData.url + '/selectAllMood',data: {uid: wx.getStorageSync('uid'),year: year,month: month + 1},header: {'content-type': 'application/json'},success(res) {console.log(2)if (!res.data) {wx.showToast({title: '日期超出可用范围咯!',icon: 'none',duration: 2000 //持续的时间})} else {that.setData({moodList: res.data.moodList,year: year,month: month + 1})arrLen = startWeek + dayNums;for (let i = 0; i < arrLen; i++) {if (i >= startWeek) {num = i - startWeek + 1;obj = {isToday: '' + year + '-' + (month + 1) + '-' + num,dateNum: num,weight: 5,mood: '/images/' + that.data.moodList[num - 1] + '色.png'}} else {obj = {};}dateArr[i] = obj;}that.setData({dateArr: dateArr})let nowDate = new Date();let nowYear = nowDate.getFullYear();let nowMonth = nowDate.getMonth() + 1;let nowWeek = nowDate.getDay();let getYear = setYear || nowYear;let getMonth = setMonth >= 0 ? (setMonth + 1) : nowMonth;if (nowYear == getYear && nowMonth == getMonth) {that.setData({isTodayWeek: true,todayIndex: nowWeek})} else {that.setData({isTodayWeek: false,todayIndex: -1})}}}//为测试所用,正式直接删掉// fail() {//   arrLen = startWeek + dayNums;//   for (let i = 0; i < arrLen; i++) {//     if (i >= startWeek) {//       num = i - startWeek + 1;//       obj = {//         isToday: '' + year + '-' + (month + 1) + '-' + num,//         dateNum: num,//         weight: 5,//         mood: '/images/' + that.data.moodList[num - 1] + '色.png'//       }//     } else {//       obj = {};//     }//     dateArr[i] = obj;//   }//   that.setData({//     dateArr: dateArr//   })//   let nowDate = new Date();//   let nowYear = nowDate.getFullYear();//   let nowMonth = nowDate.getMonth() + 1;//   let nowWeek = nowDate.getDay();//   let getYear = setYear || nowYear;//   let getMonth = setMonth >= 0 ? (setMonth + 1) : nowMonth;//   if (nowYear == getYear && nowMonth == getMonth) {//     that.setData({//       isTodayWeek: true,//       todayIndex: nowWeek//     })//   } else {//     that.setData({//       isTodayWeek: false,//       todayIndex: -1//     })//   }// }})},lastMonth: function () {//全部时间的月份都是按0~11基准,显示月份才+1let year = this.data.month - 2 < 0 ? this.data.year - 1 : this.data.year;let month = this.data.month - 2 < 0 ? 11 : this.data.month - 2;this.dateInit(year, month);},nextMonth: function () {//全部时间的月份都是按0~11基准,显示月份才+1let year = this.data.month > 11 ? this.data.year + 1 : this.data.year;let month = this.data.month > 11 ? 0 : this.data.month;this.dateInit(year, month);},/*** 设置movable-view位移*/setXmove: function (productIndex, xmove) {let noteList = this.data.noteListnoteList[productIndex].xmove = xmovethis.setData({noteList: noteList})},/*** 处理movable-view移动事件*/handleMovableChange: function (e) {if (e.detail.source === 'friction') {if (e.detail.x < -30) {this.showDeleteButton(e)} else {this.hideDeleteButton(e)}} else if (e.detail.source === 'out-of-bounds' && e.detail.x === 0) {this.hideDeleteButton(e)}},/*** 显示删除按钮*/showDeleteButton: function (e) {let productIndex = e.currentTarget.dataset.productindexthis.setXmove(productIndex, -65)},/*** 隐藏删除按钮*/hideDeleteButton: function (e) {let productIndex = e.currentTarget.dataset.productindexthis.setXmove(productIndex, 0)},/*** 处理touchstart事件*/handleTouchStart(e) {this.startX = e.touches[0].pageX},/*** 处理touchend事件*/handleTouchEnd(e) {if (e.changedTouches[0].pageX < this.startX && e.changedTouches[0].pageX - this.startX <= -30) {this.showDeleteButton(e)} else if (e.changedTouches[0].pageX > this.startX && e.changedTouches[0].pageX - this.startX < 30) {this.showDeleteButton(e)} else {this.hideDeleteButton(e)}},/*** 删除产品*/handleDeleteProduct: function ({currentTarget: {dataset: {nid}}}) {var that = thiswx.showModal({title: '删除该条笔记',content: '确认要删除吗?',success(res) {if (res.confirm) {wx.request({//传入nid请求删除url: app.globalData.url + '/deleteNote',data: {nid: nid},header: {'content-type': 'application/json'},success() {let noteList = that.data.noteListlet productIndex = noteList.findIndex(item => item.nid === nid)noteList.splice(productIndex, 1)that.setData({noteList})if (noteList[productIndex]) {that.setXmove(productIndex, 0)}if(!that.data.noteList[0]){that.setData({noteisHave: false,})}},fail() {wx.showToast({title: '删除失败!',icon: 'none',duration: 2000 //持续的时间})}})}}})},
})

data是初始化

onshow是登录后要展示的,要对当日心情进行初始化,要对当日笔记进行初始化

noteinit要根据用户的uid和date访问后端(app.globalData.url这个是后端服务器地址),获取到笔记信息后渲染到页面上,也就是重设data里面的值

daymoodinit也是一样

backnow是什么,里面要对当月的日历进行展示,还要在日历上展示当日的总体心情角标

里面要dateInit,也是从后端获取数据

后续的方法也是点击主页上的一个按钮,需要进行的操作,有点到某一日、修改总体心情、修改笔记等,比如修改笔记,就用wx.redirectTo进行了页面跳转,需要页面间传递的数据也要在跳转的时候传递;比如修改总体心情,使用的则是navigateTo,这是为啥,还有showModal就是在上层创建新窗口吗;比如date就是点击某一日,获得该日的笔记信息和总体心情,于是要noteinit和daymoodinit;后续还有滑动删除笔记事件

  1. 数据初始化(data)

data中,我们定义了页面初始化时需要使用的各种变量。这些变量包括用户的头像、昵称、日期、心情、笔记列表等。这些数据将在页面加载时被初始化,并在用户与页面交互时动态更新。

  • avatarUrl:用户的头像URL,默认值为/images/头像.png
  • nickName:用户的昵称,默认值为未登录
  • date:当前日期,初始值为null
  • daymood:当日的心情状态,默认值为今日还未选心情
  • moodList:心情列表,用于存储用户在不同日期的总体心情。
  • noteList:笔记列表,用于存储用户在不同日期的笔记内容。
  • noteisHave:标识当前日期是否有笔记,初始值为false
  • yearmonth:当前年份和月份,用于日历展示。
  • head:日历表头的星期几标识。
  • dateArr:日历数组,用于展示当前月份的日期和心情角标。
  • isToday:标识当前日期是否为今天。
  • pickToday:用户选择的日期。
  • isTodayWeek:标识当前日期是否在本周。
  • todayIndex:今天在日历中的索引。
  • nottoday:标识用户选择的日期是否为今天。
  • havenote:提示用户当前日期是否有笔记。
  1. 页面展示逻辑(onShow)

onShow是微信小程序的生命周期函数,当页面显示时触发。在这个函数中,我们主要做了以下几件事:

  • 获取当前日期:通过new Date()获取当前日期,并提取年份和月份。
  • 初始化日历:调用dateInit函数,初始化当前月份的日历数据。
  • 设置页面数据:将当前日期、用户头像、昵称等信息设置到页面的data中。
  • 初始化当日心情和笔记:调用daymoodinitnoteinit函数,分别获取并展示当日的心情和笔记。
  1. 笔记初始化(noteinit)

noteinit函数用于根据用户的uiddate从后端获取笔记列表,并将获取到的笔记数据渲染到页面上。

  • 请求笔记列表:通过wx.request向后端发送请求,获取指定日期的笔记列表。
  • 处理笔记数据:如果笔记列表不为空,遍历列表并将每条笔记的数据存储到noteList中。
  • 更新页面数据:将处理后的笔记列表设置到页面的data中,并更新noteisHave状态。
  1. 当日心情初始化(daymoodinit)

daymoodinit函数用于获取并展示用户当日的总体心情。

  • 请求当日心情:通过wx.request向后端发送请求,获取指定日期的总体心情。
  • 更新页面数据:根据获取到的心情数据,更新页面中的daymood状态。
  1. 返回今日(backnow)

backnow函数用于将页面重置为当前日期的状态。

  • 重置日期:将页面日期重置为当前日期。
  • 初始化日历:调用dateInit函数,重新初始化当前月份的日历数据。
  • 更新页面数据:将nottoday状态设置为false,表示当前日期为今天。
  1. 选择日期(date)

date函数用于处理用户选择日期的操作。

  • 获取选择的日期:根据用户点击的日期或从函数传入的日期,获取用户选择的日期。
  • 更新页面数据:将选择的日期设置到页面的data中,并更新noteisHavenottoday状态。
  • 初始化心情和笔记:调用daymoodinitnoteinit函数,获取并展示选择日期的心情和笔记。
  1. 添加笔记(add)

add函数用于跳转到添加笔记页面。

  • 页面跳转:使用wx.navigateTo跳转到/pages/notemood/notemood页面。
  1. 修改总体心情(daymood)

daymood函数用于处理用户修改总体心情的操作。

  • 弹出确认框:使用wx.showModal弹出确认框,询问用户是否确认修改总体心情。
  • 页面跳转:如果用户确认,使用wx.navigateTo跳转到/pages/daymood/daymood页面。
  1. 个人中心(mine)

mine函数用于跳转到个人中心页面。

  • 页面跳转:使用wx.navigateTo跳转到/pages/mine/mine页面。
  1. 修改笔记(changenote)

changenote函数用于处理用户修改笔记的操作。

  • 获取笔记信息:从用户点击的笔记中获取笔记的nidtimemood信息。
  • 页面跳转:使用wx.redirectTo跳转到/pages/note/note页面,并传递笔记的相关信息。
  1. 日历初始化(dateInit)

dateInit函数用于初始化当前月份的日历数据。

  • 获取当前月份的天数和起始星期:通过new Date()获取当前月份的天数和1号对应的星期。
  • 请求当月心情数据:通过wx.request向后端发送请求,获取当前月份的心情数据。
  • 更新页面数据:将获取到的心情数据设置到页面的data中,并生成日历数组dateArr
  1. 滑动删除笔记

滑动删除笔记功能通过handleMovableChangehandleTouchStarthandleTouchEnd等函数实现。

  • 显示删除按钮:当用户向左滑动笔记时,显示删除按钮。
  • 隐藏删除按钮:当用户向右滑动或滑动距离不足时,隐藏删除按钮。
  • 删除笔记:当用户点击删除按钮时,弹出确认框,确认后通过wx.request向后端发送删除请求,并更新页面数据。
main.wxml
<view class="data"><view class="circle" bindtap="mine"><image src="{{avatarUrl}}" class="head"></image></view><view class="date-mood"><text class="date">{{date}}</text><text class="mood" bindtap="daymood">{{daymood}}</text></view><view class="backnow"><image src="/images/今日.png" class="backnowimg"  bindtap="backnow" wx:if="{{nottoday}}"></image>
</view><image src="/images/添加.png" class="add" bindtap="add"></image>
</view>
<view class="calendar"><view class='wrap'><view><view class='date-show'><view class='lt-arrow' bindtap='lastMonth'><image src='/images/左箭头.png' mode='aspectFit'></image></view>{{year}}年{{month}}月<view class='rt-arrow' bindtap='nextMonth'><image src='/images/右箭头.png' mode='aspectFit'></image></view></view></view><view class='header'><view wx:for='{{head}}' class='{{(index == todayIndex) && isTodayWeek ? "weekMark" : ""}}'>{{item}}<view></view></view></view><view class='date-box'><view wx:for='{{dateArr}}'class='{{isToday == item.isToday ? "nowDay" : (pickToday == item.isToday ? "pickDay" : "")}}'data-date='{{item.isToday}}' bindtap="date"><view class="sort"><view class="minimoodview"><image src="{{item.mood}}" class="minimood"></image></view><view class='date-head'><view>{{item.dateNum}}</view></view></view></view></view></view>
</view>
<view class="nonote" wx:if="{{!noteisHave}}"><image src="/images/铃铛.png" class="bell"></image><view class="empty">{{havenote}}</view>
</view>
<view wx:else><view class="product-list"><view class="product-item" wx:for="{{noteList}}" wx:for-index="index" wx:key="{{item.nid}}"><movable-area data-note="{{item}}" bindtap="changenote"><movable-view out-of-bounds="true" direction="horizontal" x="{{item.xmove}}" inertia="true"data-productIndex="{{index}}" bindtouchstart="handleTouchStart" bindtouchend="handleTouchEnd"bindchange="handleMovableChange"><view class="product-item-wrap"><view class="expression"><image src="{{item.mood}}" class="expressionimg"></image></view><view class="product-movable-item"><view class="product-movable-item-name">{{item.time}}</view><view class="product-movable-item-code">{{item.context}}</view></view></view><view class="blank"></view></movable-view></movable-area><view class="delete-btn" data-nid="{{item.nid}}" bindtap="handleDeleteProduct"><image src="/images/删除.png" class="delete"></image></view></view></view>
</view>
  1. 顶部用户信息与操作区域
  • 用户头像:通过<image>组件展示用户头像,点击头像触发mine函数,跳转到个人中心页面。
  • 日期与心情:显示当前日期和当日心情,点击心情文本触发daymood函数,允许用户修改当日心情。
  • 返回今日按钮:如果用户选择的日期不是今天,显示“返回今日”图标,点击触发backnow函数,重置为当前日期。
  • 添加笔记按钮:点击“添加”图标触发add函数,跳转到添加笔记页面。
  1. 日历区域
  • 日历头部:显示当前年份和月份,左右箭头分别触发lastMonthnextMonth函数,用于切换月份。
  • 星期表头:显示星期几,当前星期会高亮显示。
  • 日期展示:展示当前月份的日期,每个日期块显示日期数字和对应的心情图标。点击日期块触发date函数,加载该日期的笔记和心情。
  1. 笔记展示区域
  • 无笔记提示:如果当前日期没有笔记,显示提示信息(如“今日还未写笔记哦!”)和一个铃铛图标。
  • 笔记列表:如果有笔记,展示笔记列表。每条笔记包含心情图标、时间和内容。笔记支持左右滑动,滑动后显示删除按钮。
    • 滑动删除:通过movable-view实现滑动功能,滑动到一定距离后显示删除按钮,点击删除按钮触发handleDeleteProduct函数,删除对应笔记。
    • 点击笔记:点击笔记内容触发changenote函数,跳转到修改笔记页面。

3. 后端代码分析

以主页逻辑业务为例

UserDateController.java
package st.nuc.edu.cn.mood_note.controller;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import st.nuc.edu.cn.mood_note.entity.UserDate;
import st.nuc.edu.cn.mood_note.service.UserDateService;@RestController
public class UserDateController {@AutowiredUserDateService userDateService;@RequestMapping("/gDateMood")public Object gDateMood(String uid, String date) {return userDateService.gDateMood(uid, date);}@RequestMapping("/mixOperate")public void mixOperate(UserDate userDate) {userDateService.mixOperate(userDate);}@RequestMapping("/selectAllMood")public Object selectAllMood(String uid, String year, String month) {return userDateService.selectAllMood(uid, year, month);}}

UserDateController是处理主页相关请求的控制器,主要包含以下接口:

  • gDateMood:根据用户ID和日期,获取某日的总体心情。
  • mixOperate:处理用户心情的插入或更新操作。
  • selectAllMood:根据用户ID、年份和月份,获取该月的所有心情数据。

这些接口通过调用UserDateService中的方法,完成具体的业务逻辑。

UserDateServiceImpl.java
package st.nuc.edu.cn.mood_note.service.impl;import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import st.nuc.edu.cn.mood_note.entity.UserDate;
import st.nuc.edu.cn.mood_note.mapper.UserDateMapper;
import st.nuc.edu.cn.mood_note.service.UserDateService;import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;@Component
public class UserDateServiceImpl implements UserDateService {@AutowiredUserDateMapper userDateMapper;@Overridepublic Object gDateMood(String uid, String date) {UserDate userDate = userDateMapper.gDateMood(uid, date);if (userDate != null) {JSONObject object = new JSONObject();object.put("daymood",userDate.getDateMood());return object;} else {return null;}}@Overridepublic boolean mixOperate(UserDate userDate) {UserDate userDate1 = userDateMapper.gDateMood(userDate.getUid(), userDate.getDate());if (userDate1 == null) {return userDateMapper.insert(userDate);} else {return userDateMapper.update(userDate);}}@Overridepublic Object selectAllMood(String uid, String year, String month) {int month1 = Integer.parseInt(month);String s = null;if ((month1>0)&&(month1<10)) {s = "0" + month1;} else {s = month;}List<UserDate> userDateList = userDateMapper.gAllDateMood(uid, year, s);if(!userDateList.isEmpty()) {List<String> moodList = new ArrayList();JSONObject object = new JSONObject();for (UserDate userDate : userDateList) {if (userDate.getDateMood() == null) {moodList.add(null);} else {moodList.add(userDate.getDateMood());}}object.put("moodList", moodList);return object;}return null;}
}

UserDateServiceImplUserDateService接口的实现类,主要功能如下:

  • gDateMood:通过UserDateMapper查询某日的心情数据,如果存在则返回心情信息,否则返回null
  • mixOperate:根据用户ID和日期,判断是插入新心情数据还是更新已有数据。
  • selectAllMood:查询某月的所有心情数据,并将其封装为JSON格式返回。如果某日没有心情数据,则对应位置为null
UserDateMapper.java
package st.nuc.edu.cn.mood_note.mapper;import org.apache.ibatis.annotations.*;
import st.nuc.edu.cn.mood_note.entity.UserDate;import java.util.List;@Mapper
public interface UserDateMapper {@Select("select * from user_date where uid = #{uid} and date = #{date}")UserDate gDateMood(@Param("uid")String uid, @Param("date")String date);List<UserDate> gAllDateMood(@Param("uid")String uid, @Param("year")String year, @Param("month")String month);@Insert("insert into user_date (uid,date,date_mood) values (#{uid},#{date},#{dateMood})")boolean insert(UserDate userDate);@Update("update user_date set date_mood=#{dateMood} where uid = #{uid} and date = #{date}")boolean update(UserDate userDate);}

UserDateMapper是MyBatis的Mapper接口,定义了与数据库交互的方法:

  • gDateMood:根据用户ID和日期,查询某日的心情数据。
  • gAllDateMood:根据用户ID、年份和月份,查询该月的所有心情数据。
  • insert:插入新的心情数据。
  • update:更新已有的心情数据。
UserDateMapper.xml
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="st.nuc.edu.cn.mood_note.mapper.UserDateMapper"><select id="gAllDateMood" resultType="userDate">SELECT a.uid,date.date,a.date_mood FROM date LEFT JOIN (SELECT * FROM user_date WHERE uid = #{uid}) a ON date.date=a.date where date.date LIKE '${year}_${month}%';</select></mapper>

UserDateMapper.xml是MyBatis的映射文件,定义了gAllDateMood方法的SQL查询逻辑。通过左连接查询date表和user_date表,获取某月的所有心情数据。

application.yaml
mybatis:type-aliases-package: st.nuc.edu.cn.mood_note.entitymapper-locations: classpath:mapper/*.xmlconfiguration:map-underscore-to-camel-case: truelog-impl: org.apache.ibatis.logging.stdout.StdOutImplspring:datasource:url: jdbc:mysql://localhost:3306/mood_note?useUnicode=true&characterEncoding=utf8&useSSL=falseusername: rootpassword: 123456driver-class-name: com.mysql.jdbc.Driverserver:port:8080

application.yaml是Spring Boot的配置文件,主要配置了:

  • MyBatis:指定实体类包路径、Mapper文件路径、日志实现等。
  • 数据源:配置MySQL数据库的连接信息,包括URL、用户名、密码等。
  • 服务器端口:设置服务端口为8080

三、数据库设计

1. 表结构

在这里插入图片描述

1.用户表(用户)

  • uid:用户ID,主键,类型为varchar(50)
  • opend:用户开放ID,类型为varchar(255)

2.用户日期表(用户日期)

  • uid:用户ID,外键,关联用户表,类型为varchar(50)
  • date:日期,外键,关联日期表,类型为date
  • date_mod:用户在该日期的总体心情,类型为varchar(10)

3.登记表(登记)

  • uid:用户ID,主键,类型为int
  • uid:用户ID,外键,关联用户表,类型为varchar(50)
  • date:日期,外键,关联日期表,类型为date
  • ncontext:笔记内容,类型为varchar(8000)
  • ntine:笔记时间,类型为time
  • mod:笔记心情,类型为varchar(5)

4.反馈表(反馈)

  • fid:反馈ID,主键,类型为int
  • uid:用户ID,外键,关联用户表,类型为varchar(50)
  • context:反馈内容,类型为varchar(500)
  • lz_read:是否已读,类型为varchar(10)
  • rcontext:回复内容,类型为varchar(500)
  • rdate:回复日期,类型为date
  • date:反馈日期,外键,关联日期表,类型为date

5.日期表(日期)

  • date:日期,主键,类型为date

6.管理员表(管理员)

  • aid:管理员ID,主键,类型为int
  • opend:管理员开放ID,类型为varchar(255)
  • password:管理员密码,类型为varchar(255)

7.官方通知表(官方通知)

  • aid:管理员ID,主键,类型为int
  • date:通知日期,类型为date
  • context:通知内容,类型为varchar(500)
  • lz_read:是否已读,类型为varchar(10)

相关文章:

【微信小程序】每日心情笔记

个人团队的比赛项目&#xff0c;仅供学习交流使用 一、项目基本介绍 1. 项目简介 一款基于微信小程序的轻量化笔记工具&#xff0c;旨在帮助用户通过记录每日心情和事件&#xff0c;更好地管理情绪和生活。用户可以根据日期和心情分类&#xff08;如开心、平静、难过等&#…...

PMP项目管理—沟通管理篇—3.监督沟通

文章目录 基本信息4W1HITTO输入工具与技术输出 工作绩效信息和变更请求 基本信息 4W1H what: 确保满足项目及其相关方的信息需求的过程。why: 通过监督沟通过程&#xff0c;来确定规划的沟通工作和沟通活动是否如预期&#xff0c;提高或保持了相关方对项目可交付成果与预计结…...

在Linux中开发OpenGL——检查开发环境对OpenGL ES的支持

由于移动端GPU规模有限&#xff0c;厂商并没有实现完整的OpenGL特性&#xff0c;而是实现了它的子集——OpenGL ES。因此如果需要开发的程序要支持移动端平台&#xff0c;最好使用OpenGL ES开发。 1、 下载支持库、OpenGL ES Demo 1.1、下载PowerVRSDK支持库作为准备&#xff…...

低空经济-飞行数据平台 搭建可行方案

搭建一个飞行数据平台是低空经济中至关重要的一环,它能够实现对飞行器的实时监控、数据分析、路径优化以及安全管理。以下是搭建飞行数据平台的详细步骤和技术方案: 一、平台的核心功能 实时监控: 实时获取飞行器的位置、速度、高度、电池状态等数据。提供可视化界面,展示飞…...

python量化交易——金融数据管理最佳实践——使用qteasy大批量自动拉取金融数据

文章目录 使用数据获取渠道自动填充数据QTEASY数据拉取功能数据拉取接口refill_data_source()数据拉取API的功能特性多渠道拉取数据实现下载流量控制实现错误重试日志记录其他功能 qteasy是一个功能全面且易用的量化交易策略框架&#xff0c; Github地址在这里。使用它&#x…...

为AI聊天工具添加一个知识系统 之136 详细设计之77 通用编程语言 之7

问题 Q1492、针对前面您给出的“AI聊天工具知识系统设计文档”&#xff0c;请就您后面所述“智能进化&#xff1a;认知演进路由驱动知识库持续优化”进行更深入的实现讨论 Q1493、感觉不够完整。下面我们针对您前面给出的“知识系统三层架构详述”逐层给出详细地实现方案。 …...

【CSRF实践】DVWA靶场之CSRF实践

CSRF介绍 CSRF(Cross-site request forgery)&#xff0c;中文名叫做“跨站请求伪造”&#xff0c;也被称作“one click attack/session riding”&#xff0c;缩写为“CSRF/XSRF”。在场景中&#xff0c;攻击者会伪造一个请求&#xff08;通常是一个链接&#xff09;&#xff0…...

数据库设计方面如何进行PostgreSQL 17的性能调优?

在数据库设计方面&#xff0c;PostgreSQL 17 的性能调优可以从以下几个方面入手&#xff1a; 表结构设计 选择合适的数据类型&#xff1a;根据数据的实际范围和业务需求&#xff0c;选择占用空间小、查询效率高的数据类型。对于固定长度的字符串&#xff0c;如性别字段&#…...

[场景题]如何实现购物车

1. 基于Session的购物车&#xff08;适合小型单体应用&#xff09; 核心思路&#xff1a;将购物车数据存储在用户会话&#xff08;Session&#xff09;中&#xff0c;适用于无需持久化的临时购物车。 实现步骤&#xff1a; 数据结构&#xff1a;使用Map<商品ID, 商品数量&g…...

Rust 并发编程:Futures、Tasks 和 Threads 的结合使用

一、线程&#xff08;Threads&#xff09;与异步&#xff08;Async&#xff09;的对比 1.1. 线程的优势与限制 线程是一种广泛使用的并发模型&#xff0c;几乎所有现代操作系统都支持。Rust 的标准库提供了 std::thread API&#xff0c;使得线程编程变得直观。然而&#xff0…...

常见的网络协议介绍

一、什么是网络协议 指的是通信双方的数据发送和接收顺序&#xff0c;数据的封装规则。 通俗解释&#xff1a;描述双方发送和接收的每个字节是按照什么规则。 二、TCP/IP体系的常用协议 (一)应用层 HTTP&#xff1a;超文本协议&#xff1b;指的是用来传输文本网页的协议&#…...

一文读懂加载地址、链接地址和运行地址

我们在做嵌入式系统开发时&#xff0c;会经常遇到加载地址、链接地址和运行地址的概念&#xff0c;可能会感到很困惑&#xff0c;搞不清它们三者的关系。希望此文能帮助大家彻底理解三者的关系。 一.概念 1.1.加载地址 加载地址&#xff0c;即Load Memory Address&#xff08…...

Unity帧同步与状态同步混合架构开发指南

一、技术背景与适用场景 1. 技术定位差异 帧同步&#xff08;Lockstep&#xff09;&#xff1a;同步操作指令&#xff0c;强调确定性计算&#xff0c;适用于实时性要求高的场景&#xff08;如MOBA、RTS&#xff09;&#xff0c;但存在反作弊难题16。 状态同步&#xff08;Sta…...

后路式编程

今天遇到一个问题&#xff0c;反馈的时候&#xff0c;已经提审过了&#xff0c;不能重新出包了。只能依赖Lua热更解决。非常巧的是&#xff0c;C#那边的变量全是Public的&#xff0c;这算是救了一命。想想确实可笑&#xff0c;本来是封装的问题&#xff0c;没有封装的太好。结果…...

Rust语言入门与应用:未来发展趋势解析

一、Rust语言核心优势解析 1.1 内存安全革命 rust复制 // 所有权系统示例 fn main() { let s1 String::from("hello"); // s1获得所有权 let s2 s1; // 所有权转移至s2 // println!("{}", s1); // 编译错误&#xff01;s1已失效 println!("{}&quo…...

【2025小白版】计算复试/保研机试模板(个人总结非GPT生成)附代码

一、编程语言选择 很多高校在机试中对编程语言都有明确规定&#xff0c;像复旦大学计算机学院就说明可选择 C、C 或 Java 语言答题&#xff0c;还支持 C11&#xff08;gcc5.4&#xff09;&#xff0c;C14&#xff08;g5.4&#xff09;&#xff0c;Java (openjdk1.8&#xff09…...

android11使用gpio口控制led状态灯

目录 一、简介 二、解决方法 A、底层驱动 B、上层调用 C、验证 一、简介 1、需求&#xff1a;这里是用2个gpio口来控制LED灯&#xff0c;开机时默认亮蓝灯&#xff0c;按开机键&#xff0c;休眠亮红灯&#xff0c;唤醒亮蓝灯。 原理图&#xff1a; 这里由于主板上电阻R63…...

基于Asp.net的高校一卡通管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…...

C++蓝桥杯基础篇(七)

片头 嗨~小伙伴们&#xff0c;大家好&#xff01;今天我们来一起学习蓝桥杯基础篇&#xff08;七&#xff09;&#xff0c;学习相关字符串的知识&#xff0c;准备好了吗&#xff1f;咱们开始咯&#xff01; 一、字符与整数的联系——ASCII码 每个常用字符都对应一个-128~127的…...

8.路由原理专题

路由器数据转发原理&#xff0c;路由表、FIB、快速转发表的关系 路由的控制平面与转发平面 控制平面:负责路由计算,维护;路由协议运行在控制平面 转发平面:进行数据包的封装,报文转发,路由表,FIB表,快速转发表等 控制平面与转发平面相互独立又协同工作 路由器检查数据包的目…...

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…...

零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?

一、核心优势&#xff1a;专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发&#xff0c;是一款收费低廉但功能全面的Windows NAS工具&#xff0c;主打“无学习成本部署” 。与其他NAS软件相比&#xff0c;其优势在于&#xff1a; 无需硬件改造&#xff1a;将任意W…...

条件运算符

C中的三目运算符&#xff08;也称条件运算符&#xff0c;英文&#xff1a;ternary operator&#xff09;是一种简洁的条件选择语句&#xff0c;语法如下&#xff1a; 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true&#xff0c;则整个表达式的结果为“表达式1”…...

多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验

一、多模态商品数据接口的技术架构 &#xff08;一&#xff09;多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如&#xff0c;当用户上传一张“蓝色连衣裙”的图片时&#xff0c;接口可自动提取图像中的颜色&#xff08;RGB值&…...

Matlab | matlab常用命令总结

常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...

Java入门学习详细版(一)

大家好&#xff0c;Java 学习是一个系统学习的过程&#xff0c;核心原则就是“理论 实践 坚持”&#xff0c;并且需循序渐进&#xff0c;不可过于着急&#xff0c;本篇文章推出的这份详细入门学习资料将带大家从零基础开始&#xff0c;逐步掌握 Java 的核心概念和编程技能。 …...

tree 树组件大数据卡顿问题优化

问题背景 项目中有用到树组件用来做文件目录&#xff0c;但是由于这个树组件的节点越来越多&#xff0c;导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多&#xff0c;导致的浏览器卡顿&#xff0c;这里很明显就需要用到虚拟列表的技术&…...

大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计

随着大语言模型&#xff08;LLM&#xff09;参数规模的增长&#xff0c;推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长&#xff0c;而KV缓存的内存消耗可能高达数十GB&#xff08;例如Llama2-7B处理100K token时需50GB内存&a…...

在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?

uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件&#xff0c;用于在原生应用中加载 HTML 页面&#xff1a; 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...

STM32HAL库USART源代码解析及应用

STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...