【景途无忧微信小程序】——零基础手把手带你实现,既能连接数据库,又能实现多项功能的前后端交互的微信小程序设计(上)

🎼个人主页:【Y小夜】

😎作者简介:一位双非学校的大三学生,编程爱好者,

专注于基础和实战分享,欢迎私信咨询!

🎆入门专栏:🎇【MySQLJava基础Rust

🎈热门专栏:🎊【PythonJavawebSpringboot】 

感谢您的点赞、关注、评论、收藏、是对我最大的认可和支持!❤️

目录

🎈项目背景

🎊需求分析

🎊性能需求

🎊功能需求

🎈登录功能

🎊创建数据库

🎊后台服务端

🎄初始化服务端

🎄功能实现

🎁utils文件夹

 🎁routers文件夹

 🎁app.js文件

 🎄测试功能

🎊前台微信小程序

🎄功能实现

 🎁index.html

 🎁index.js

🎄 页面展示

🎈注册功能

🎊后台服务端

🎊前端服务端

🎄功能实现

 🎁regist.js

🎁regist.wxml

🎄页面展示


🎈项目背景

🎊需求分析

        在当今这个快节奏、高互联的时代,旅游已不仅仅是简单的出行,它更是一种生活方式的探索与体验。随着科技的进步和人们生活品质的提升,现代旅行者对旅游服务的需求日益多元化和个性化。他们渴望在旅途中不仅能够享受到便捷的预订服务,还希望能获得深度的文化体验、实时的信息更新以及社交互动的乐趣。因此,设计一款集景区展示、购票服务、景点推荐、AI答疑等功能于一体的微信小程序“景途无忧”,显得尤为迫切和必要。

🎊性能需求

  • 正确性需求

管理员应能够进行有关的旅游信息准确地添加到数据库中。系统用户登录后,系统应能正确地读取用户个人信息。系统的操作结果与预期的结果应该是一致。

  • 安全性需求

无重大安全漏洞,用户数据得到妥善保护。

  • 及时性需求

即时可见:对旅游信息的处理(包括添加、删除、修改)将立即在后台数据库中进行更新,达到“即时操作、即时生效”的功能

  • 稳定性需求

系统部署后,在硬件条件和支持软件条件没有变化的情况下,能够一直保持运行状态,直到系统被升级或代替。

  • 扩展性需求

系统应该支持功能扩展与支持环境的扩展。功能扩展就是在现有的功能模块的基础上可以添加信息的功能模块。

  • 故障处理能力需求

系统可能遇到的软件故障是数据库与应用程序服务器。为了满足信息处理的需求,可以采取数据恢复来解决。

🎊功能需求

  •         运行景途无忧小程序后,进入登录/注册页面,用户如已有账号,可以直接输入账号和密码进行登录,若无账号,可以先进行注册,然后再进行登录操作。
  •         首页对数据库中的景点数据进行展示,并且用户可以根据景点名称对感兴趣的景点进行搜索,用户也可以对景点的门票进行购买,加入订单中。
  •         小助手页面是调用智能云平台创建的旅游小助手智能体,用于对用户提出的关于旅游的问题进行回答。
  •         订单页面可以查看自己购买的门票,并且可以对订单进行取消操作。
  •         我的页面用户可以进行查看个人信息、快速注册、退出登录或查看关于我们的界面

🎈登录功能

🎊创建数据库

先自己创建一个MySQL的tour数据库

🎊后台服务端

🎄初始化服务端

先自己创建一个文件夹,用于存放服务端代码

然后开始搭建服务器

  • 下载Node.js(https://nodejs.org),选择长期支持版下载。
  • 安装Node.js,双击下载的安装包安装即可,安装选项全部使用默认值。
  • “用户登录”文件夹下创建文件夹“服务器端”来存放小程序项目对应的服务器端文件。
  • “服务器端”文件夹下进入DOS命令界面。
  • 初始化服务器端项目,将会自动创建package.json配置文件。    npm init  -y
  • 安装Express框架,用于快速搭建HTTP服务器。 npm install express  --save
  • 安装request模块。npm install request  --save
  • 安装nodemon监控代码修改。 npm install nodemon  -g

安装完之后再在根目录下创建一个app.js文件,如下图

最后使用vscode将自己创建的文件加打开

🎄功能实现

🎁utils文件夹

首先,在根目录下创建utils文件夹

在utils文件夹下创建BaseDB.js文件用于导入MySQL的模块

//导入mysql的模块
const mysql=require("mysql")
//创建数据库连接
const db=mysql.createConnection({
    //数据库的主机地址
    host:"localhost",
    //数据库账号
    user:"root",
    //数据库密码
    password:"密码",
    //操作的目标数据库
    database:"数据库名"
})
//导出数据库连接对象
module.exports=db

在utils文件夹下创建Result.js文件用于封装结果类

//定义Result结果封装类
class Result{
    //返回成功的对象的方法
    static success(data){
        //返回结果
        return{
            code:0,
            msg:"成功",
            data:data
        }
    }
    //返回失败时的对象的方法
    static fail(data){
        return{
            code:1,
            msg:"失败",
            data:data
        }
    }
}
module.exports=Result
 🎁routers文件夹

在routers文件下创建userRouter.js文件,开始编写用户登陆的功能

//导入express用模块
const express=require("express")
//导入获得路由实例
const router=express.Router()
//导入数据库连接对象
const db=require("../utils/BaseDB")
//导入结果封装类
const Result=require("../utils/Result")

//用户登录
router.post('/user/login',(req,resp)=>{
    //获取用户名和密码
    let username=req.body.username
    let password=req.body.password
    //定义sql语句
    let sql=`
        select * from user where username=? and password=?
    `
    //定义参数
    let params=[username,password]
    //查询数据库
    db.query(sql,params,(err,res)=>{
        //错误
        if(err){
            resp.send(Result.fail(err))
        }else{
            //成功
            resp.send(Result.success(res))
        }
    })
})
//进行导出
module.exports=router
 🎁app.js文件

在app.js文件中编写代码,将路由引入

//导入express模块
const express = require('express')
//创建express的实例
const app=express()
//解析提交的json数据
app.use(express.json())
//解析提交表单的的数据
app.use(express.urlencoded({extended:true}))
//导入用户模块
const userRouter=require('./routers/userRouter')

//配置路由
app.use(userRouter)

// 监听3000端口
app.listen(3000,()=>{
    console.log("服务端启动成功.....")
})

 🎄测试功能

先打开终端,再根目录下使用node app 命令运行程序,但是不出意外的话这里要出意外了,请看下图报错

这里是意思是指没有引入mysql模块,我们查看一下node_modules文件夹,发现确实没有mysql

这时我们可以在终端使用 npm install mysql 命令下载mysql模块

下载完毕后,再次运行,发现运行成功。

        但是使用node命令运行,当代码发生改变时,页面并不会自动刷新。所以我们可以使用nodemon,nodemon可以实现对代码的监控,使得当代码更新时,不需要重启服务器,就可以自动更新代码。

使用npm install -g nodemon

 然后我们使用nodemon app运行,这时候可能还会出现一种错误,如下图

解决方案:

先使用管理员身份登录vscode

  1. 在终端运行:get-ExecutionPolicy,显示Restricted(表示状态是禁止的)
  2. 在终端执行,set-ExecutionPolicy RemoteSigned
  3. 在终端运行:get-ExecutionPolicy,显示RemoteSigned
  4. 再次运行nodemon app就可不会报错了

接下来使用apifox进行登录测试

请求:

响应:

到此我们的登录接口测试成功。

🎊前台微信小程序

🎄功能实现

 🎁index.html
<!-- 登录界面 -->
<view class="one">景途无忧</view>
<view class="conent">
    <view class="field">
        <view class="title">账号</view>
        <view>
            <input type="text" bind:input="usernameInput"
            placeholder="请输入账号"/>
        </view>
    </view>
    <view class="hr"></view>
    <view class="field">
        <view class="title">密码</view>
        <view>
            <input password="{{true}}" bind:blur="pwdBlur" placeholder="请输入密码"/>
        </view>
    </view>
    <view class="hr"></view>
    <view class="btns">
        <button type="primary" bind:tap="login" disabled="{{disabled}}">登陆</button>
        <button type="default" bind:tap="regist">注册</button>
    </view>
</view>
    <!-- 重影 -->
<view class="shadow shadow-1"></view><view class="shadow shadow-2"></view>
<view class="two">在这里,我们致力于为您提供一个无忧无虑的旅行体验。无论您是想要探索美丽的自然风光,还是体验丰富的文化之旅,景途无忧都能满足您的需求。我们深知旅行中的每一个细节都至关重要,因此,从购票、规划行程到应对突发情况,我们都为您提供全方位的保障和支持。选择景途无忧,让我们一起开启一段美好的旅程吧!</view>


 🎁index.js
// 登录界面的js
//获取全局的app对象
const app = getApp()

Page({
    data: {
        disabled:true,
        username:"",
        password:""
    },
    //账号文本框输入事件
    usernameInput(e){
        //获取当前输入的账号
        let username = e.detail.value
        if(username){
            //让登陆按钮处于启用状态
            this.setData({
                disabled:false,
                username:username
            })
        }else{
            this.setData({
                disabled:true,
                username:username
            })
        }
    },
    //绑定密码的失焦函数
    pwdBlur(e){
        //将密码框中的数据,设置到data.password上
        this.setData({
            password:e.detail.value
        })
    },
    //点击登陆按钮
    login(e){
        let that=this
        //判断是否输入密码
        if(!this.data.password){
            wx.showToast({
              title: '请输入密码',
              icon:"error"
            })
            return
        }
        //发起服务端请求,进行登陆操作
        wx.request({
          //请求地址
          url:app.globalData.baseUrl+'/user/login',
          //请求方法
          method:"POST",
          //提交到后端的数据
          data:{
              "username":this.data.username,
              "password":this.data.password
          },
          success:(res)=>{
              //请求成功之后,获取后端响应的结果
              if(res.data.code==0 &&
                res.data.data.length>0){
                    wx.showToast({
                      title: '登陆成功',
                      icon:"success"
                    })
                    //设置全局用户名
                    app.globalData.username=that.data.username
                    //登陆成功,将用户数据,存储到本地
                    //跳转到商品首页
                    setTimeout(()=>{
                      wx.switchTab({
                        url: '/pages/home/home',
                      })
                    },200)
            }else{
                wx.showToast({
                  title: '登陆失败',
                  icon:"error"
                })
            }
          }
        })
    },
    //注册事件
    // 导航到注册
    regist(e){
        wx.navigateTo({
          url: '/pages/regist/regist',
        })
    },
    /**
     * 生命周期函数--监听页面加载
     */
    onLoad(options) {

    },

    /**
     * 生命周期函数--监听页面初次渲染完成
     */
    onReady() {

    },

    /**
     * 生命周期函数--监听页面显示
     */
    onShow() {

    },

    /**
     * 生命周期函数--监听页面隐藏
     */
    onHide() {

    },

    /**
     * 生命周期函数--监听页面卸载
     */
    onUnload() {

    },

    /**
     * 页面相关事件处理函数--监听用户下拉动作
     */
    onPullDownRefresh() {

    },

    /**
     * 页面上拉触底事件的处理函数
     */
    onReachBottom() {

    },

    /**
     * 用户点击右上角分享
     */
    onShareAppMessage() {

    }
})

🎄 页面展示

🎈注册功能

🎊后台服务端

// 用户注册
router.post('/user/regist', (req, resp) => {
    console.log(req.body);
    //获取获取一系列信息
    const { username, password, phone, address } = req.body;
    //定义sql语句
    let sql = `
        insert into user(username,password,phone,address) values(?,?,?,?)
    `;
    //定义参数
    let params = [username, password, phone, address];
    //执行sql语句
    db.query(sql, params, (err, res) => {
        //错误
        if (err) {
            resp.send(result.fail(err));
        }
        //成功
        else {
            resp.send(result.success(res));
        }
    });
});

🎊前端服务端

🎄功能实现

 🎁regist.js
// pages/regist/regist.js
const app=getApp();

Page({
  /**
   * 页面的初始数据
   */
  data: {
    username: "",
    password: "",
    phone: "",
    address: "",
    region: ['河南省', '洛阳市', '涧西区'],
    customItem: '全部'
  },
  // 绑定账号输入
  bindUsernameInput: function(e) {
    this.setData({
      username: e.detail.value
    });
  },
  // 绑定密码输入
  bindPasswordInput: function(e) {
    this.setData({
      password: e.detail.value
    });
  },
  // 绑定电话输入
  bindPhoneInput: function(e) {
    this.setData({
      phone: e.detail.value
    });
  },
  // 改变地区
  bindRegionChange: function(e) {
    this.setData({
      region: e.detail.value
      // 更新地址为选中的地区
    });
  },
  regist(e) {
    const { username, password, phone, region } = this.data;
    // 由于picker组件的值是数组,我们需要将其转换为字符串
    const address = region.join('');
    // 查看表格是否为空
    if (!username || !password || !phone || !address) {
      wx.showToast({
        title: '请填写完整信息',
        icon: 'error'
      });
      return;
    }
    // 提交数据
    wx.request({
      url: app.globalData.baseUrl + "/user/regist",
      method: "POST",
      data:{
        "username":username,
        "password":password,
        "phone":phone,
        "address":address
      },
      success: (res) => {
        if ((res.data.code==0)) {
          wx.showToast({
            title: '注册成功',
            icon: "success",
          });
          setTimeout(() => {
            wx.redirectTo({
              url: '/pages/index/index',
            });
          }, 100); // 0.1秒后跳转
        } else {
          wx.showToast({
            title: '注册失败',
            icon: 'error'
          });
        }
      }
    });
  }
});
🎁regist.wxml
<!--pages/regist/regist.wxml-->
<form bindsubmit="regist">
  <view class="conent">
  <view class="field">
    <view class="title">账号</view>
    <view>
      <input type="text" name="username" placeholder="请输入账号" bindinput="bindUsernameInput"/>
    </view>
  </view>
  <view class="hr"></view>
  <!-- 密码 -->
  <view class="field">
    <view class="title">密码</view>
    <view>
      <input password="{{true}}" name="password" placeholder="请输入密码" bindinput="bindPasswordInput"/>
    </view>
  </view>
  <view class="hr"></view>
  <!-- 电话号 -->
  <view class="field">
    <view class="title">电话</view>
    <view>
      <input type="text" name="phone" placeholder="请输入手机号" bindinput="bindPhoneInput"/>
    </view>
  </view>
  <view class="hr"></view>
  <view class="field">
    <view class="title">地址</view>
    <picker mode="region" bindchange="bindRegionChange" value="{{region}}" custom-item="{{customItem}}">
      <view class="picker">
        {{region[0]}},{{region[1]}},{{region[2]}}
      </view>
    </picker>
  </view>
  <view class="hr"></view>
    <button  class="btns" form-type="submit">注册</button>
</view>
</form>

🎄页面展示

 今天的讲解就到这里,预知后续如何,请看下篇文章!

评论 48
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Y小夜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值