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

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

一、项目基本介绍

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();
          //创建构造函数note
          function 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 = this
    wx.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.note
    var nid = note.nid
    var time = note.time
    var mood = note.mood
    wx.redirectTo({
      url: '/pages/note/note?mood=' + mood + '&nid=' + nid + '&time=' + time + '&flag=1',
    })
  },

  dateInit: function (setYear, setMonth) {
    //全部时间的月份都是按0~11基准,显示月份才+1
    let 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 = this
    console.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基准,显示月份才+1
    let 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基准,显示月份才+1
    let 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.noteList
    noteList[productIndex].xmove = xmove
    this.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.productindex
    this.setXmove(productIndex, -65)
  },

  /**
   * 隐藏删除按钮
   */
  hideDeleteButton: function (e) {
    let productIndex = e.currentTarget.dataset.productindex

    this.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 = this
    wx.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.noteList
              let 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 {
    @Autowired
    UserDateService 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 {
    @Autowired
    UserDateMapper userDateMapper;
    @Override
    public 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;
        }
    }

    @Override
    public boolean mixOperate(UserDate userDate) {
        UserDate userDate1 = userDateMapper.gDateMood(userDate.getUid(), userDate.getDate());
        if (userDate1 == null) {
            return userDateMapper.insert(userDate);
        } else {
            return userDateMapper.update(userDate);
        }
    }

    @Override
    public 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.entity
  mapper-locations: classpath:mapper/*.xml
  configuration:
    map-underscore-to-camel-case: true
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl


spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mood_note?useUnicode=true&characterEncoding=utf8&useSSL=false
    username: root
    password: 123456
    driver-class-name: com.mysql.jdbc.Driver

server:
  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)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/982213.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【数据结构】什么是栈||栈的经典应用||分治递归||斐波那契问题和归并算法||递归实现||顺序栈和链栈的区分

文章目录 &#x1f967;栈的初步理解&#xff1a;&#x1f967;易错&#xff1a;如何判断栈满&#x1f967;栈满理解&#x1f967;栈的基本运算&#x1f4da;栈操作的伪代码逻辑&#xff08;顺序和链栈&#xff09;&#x1f4d5;顺序栈运算实现&#xff1a;顺序栈的表示&#x…

利用opencv_python(pdf2image、poppler)将pdf每页转为图片

1、安装依赖pdf2image pip install pdf2image 运行.py报错&#xff0c;因为缺少了poppler支持。 2、安装pdf2image的依赖poppler 以上命令直接报错。 改为手工下载&#xff1a; github: Releases oschwartz10612/poppler-windows GitHub 百度网盘&#xff1a; 百度网盘…

IDEA + DeepSeek 实现 AI辅助编程,提升效率10倍(全网超详细的终极图文实战指南)

前言 在软件开发的世界里&#xff0c;每个开发者都经历过这样的困境——在重复的CRUD代码中机械劳动&#xff0c;为复杂的业务逻辑调试数小时&#xff0c;或是在海量文档中寻找某个API的正确用法。传统的IDE工具虽能提供基础支持&#xff0c;却难以突破效率的“玻璃天花板”。而…

青训营:简易分布式爬虫

一、项目介绍 该项目是一个简易分布式爬虫系统&#xff0c;以分布式思想为基础&#xff0c;通过多节点协作的方式&#xff0c;将大规模的网页抓取任务分解&#xff0c;从而高效、快速地获取网络数据 。 项目地址&#xff1a;https://github.com/yanchengsi/distributed_crawle…

论坛系统测试报告

目录 一、项目背景二、论坛系统测试用例思维导图三、论坛系统测试3.1界面测试3.2登陆测试3.3主页测试3.4个人中心测试 四、自动化测试脚本4.1配置驱动4.2创建浏览器类4.3功能测试4.3.1登陆测试4.3.2注册测试4.3.3主页测试4.3.4帖子编辑4.3.5运行主代码 五、BUG分析六、测试总结…

C++ std::vector 超详细指南:基础实践(手搓vector)

目录 一.基本概念 二.类的常用接口说明 1.类对象的常见构造 2. vector类空间变化 1&#xff09;.size()&#xff08;获取数据个数&#xff09; 2&#xff09;.capacity()&#xff08;获取容量大小&#xff09; 3&#xff09;.empty()&#xff08;判断是否为空&#xff0…

文件上传漏洞:upload-labs靶场11-20

目录 pass-11 pass-12 pass-13 pass-14 pass-15 pass-16 pass-17 pass-18 pass-19 pass-20 pass-11 分析源代码 &#xff0c;发现上传文件的存放路径可控 if(isset($_POST[submit])){$ext_arr array(jpg,png,gif);$file_ext substr($_FILES[upload_file][name],st…

AGI 之 【Dify】 之 使用 Docker 在 Windows 端本地部署 Dify 大语言模型(LLM)应用开发平台

AGI 之 【Dify】 之 使用 Docker 在 Windows 端本地部署 Dify 大语言模型&#xff08;LLM&#xff09;应用开发平台 目录 AGI 之 【Dify】 之 使用 Docker 在 Windows 端本地部署 Dify 大语言模型&#xff08;LLM&#xff09;应用开发平台 一、简单介绍 二、Docker 下载安…

Redis的持久化-RDBAOF

文章目录 一、 RDB1. 触发机制2. 流程说明3. RDB 文件的处理4. RDB 的优缺点 二、AOF1. 使用 AOF2. 命令写⼊3. 文件同步4. 重写机制5 启动时数据恢复 一、 RDB RDB 持久化是把当前进程数据生成快照保存到硬盘的过程&#xff0c;触发 RDB 持久化过程分为手动触发和自动触发。 …

常见网络协议考察知识点

说说http,https协议&#xff1b; HTTPS&#xff08;Secure Hypertext Transfer Protocol&#xff09;安全超文本传输协议&#xff1a; 它是一个安全通信通道&#xff0c;它基于HTTP开发&#xff0c;用于在客户计算机和服务器之间交换信息&#xff0c;它使用安全套接字层(SSL)…

上海市闵行区数据局调研云轴科技ZStack,共探数智化转型新路径

为进一步深化人工智能、大模型技术的应用&#xff0c;推动区域数字经济高质量发展&#xff0c;2025年2月27日&#xff0c;上海市闵行区数据局局长吴畯率队赴上海云轴科技股份有限公司&#xff08;以下简称“云轴科技ZStack”&#xff09;开展专题调研。此次调研旨在深入了解企业…

数据结构秘籍(四) 堆 (详细包含用途、分类、存储、操作等)

1 引言 什么是堆&#xff1f; 堆是一种满足以下条件的树&#xff1a;&#xff08;树这一篇可以参考我的文章数据结构秘籍&#xff08;三&#xff09;树 &#xff08;含二叉树的分类、存储和定义&#xff09;-CSDN博客&#xff09; 堆中的每一个结点值都大于等于&#xff08…

MySQL增量更新数据:高效同步策略与PanguSync实战指南

Mysql增量更新数据软件下载https://pan.baidu.com/s/1WesHaKGO7uQMhPNE-BTDmg?pwdabcd#list/path%2F 在数据驱动的商业环境中&#xff0c;实时数据同步已成为企业数字化转型的关键。本文将深入探讨MySQL增量更新的核心技术&#xff0c;并详细解析如何通过PanguSync工具实现高…

【Wireshark 02】抓包过滤方法

一、官方教程 Wireshark 官网文档 &#xff1a; Wireshark User’s Guide 二、显示过滤器 2.1、 “数据包列表”窗格的弹出过滤菜单 例如&#xff0c;源ip地址作为过滤选项&#xff0c;右击源ip->prepare as filter-> 选中 点击选中完&#xff0c;显示过滤器&#…

run方法执行过程分析

文章目录 run方法核心流程SpringApplicationRunListener监听器监听器的配置与加载SpringApplicationRunListener源码解析实现类EventPublishingRunListener 初始化ApplicationArguments初始化ConfigurableEnvironment获取或创建环境配置环境 打印BannerSpring应用上下文的创建S…

前端知识一

&#xff08;ref函数&#xff09;1.为什么vue3中使用ref来创建响应式数据&#xff0c;而不是直接声明一个变量 import { ref } from "vue";const count ref(0); // 创建一个响应式的计数器&#xff0c;初始值为0function increment() {count.value; // 增加计数器的…

STM32---FreeRTOS中断管理试验

一、实验 实验目的&#xff1a;学会使用FreeRTOS的中断管理 创建两个定时器&#xff0c;一个优先级为4&#xff0c;另一个优先级为6&#xff1b;注意&#xff1a;系统所管理的优先级范围 &#xff1a;5~15 现象&#xff1a;两个定时器每1s&#xff0c;打印一段字符串&#x…

数据结构知识学习小结

一、动态内存分配基本步骤 1、内存分配简单示例&#xff1a; 个人对于示例的理解&#xff1a; 定义一个整型的指针变量p&#xff08;着重认为它是一个“变量”我觉得可能会更好理解&#xff09;&#xff0c;这个变量用来存地址的&#xff0c;而不是“值”&#xff0c;malloc函…

swift4-汇编分析枚举内存布局

一、枚举的内存原理 1.1 常规case enum TestEnum { case test1, test2, test3 } var t TestEnum.test1 t .test2 t .test3枚举是常规的case的情况-是采取一个字节来存枚举变量通过拿到枚举的内存地址&#xff0c;看地址里面存的枚举值情况窥探枚举内存存储情况 var t Te…