本微信小程序主要由Mysql,Eclipse和微信开发者工具共同完成,其主要功能有分角色登录,新闻页浏览及推送,实验室条件筛选查询,实验室预约,查看历史预约记录或取消当前预约以及个人信息修改和教师用户管理实验室功能等
1.数据库
根据上述功能我们大致可以建立以下数据库表如图
这里详细列出lab表,news表和students表,record表中的字段
lab表
news表
students表
?
records表
这里我所使用的数据库可视化组件为phpMyAdmin,teacher表中字段大致与student表中字段相同
2.后台服务器部分?
这里后台服务器选用如今主流框架来进行搭建,分别为Mybatis和Spring Boot
在新建Spring项目后,有一点很关键的是在于如何配置pom.xml文件,如图
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>spring</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
除此之外,我们就可以在src文件中开始搭建项目,其主体目录结构如下图
这其中的application配置文件也十分重要,这里直接贴出代码
mybatis.type-aliases-package=com.example.demo
#mysql驱动
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#远程数据库链接 serverTimezone不可少
spring.datasource.url=jdbc:mysql://localhost:3306/Reservation?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
#MySQL数据库用户名、密码
spring.datasource.username=你的数据库用户名
spring.datasource.password=你的数据库密码
#xml格式的mapper文件位置
mybatis.mapper-locations=classpath:/mybatis/mapper/*.xml
server.port=8080
server.servlet.encoding.force=true
server.servlet.encoding.charset=UTF-8
server.servlet.encoding.enabled=true
server.tomcat.uri-encoding=UTF-8
同时还需注意的是Application.java为项目的启动文件,同样贴出代码
package com.example.demo;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan(value = "com.example.demo.mapper")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
要注意的是@MapperScan中的值要设定为mapper接口文件位置
当所有配置完毕时,可以点击绿色启动按钮,能在控制台看到以下图,就代表你的服务器已经搭建成功了
?然后我们就可以愉快的编写后台代码了,这里列出其中一条系列流程
首先,你应该想到的是实体类,去建立一个什么样的对象。然后就是小程序传给后台的值要来做什么,我需要返回什么,编写一个大致的接口函数,这就是mapper包中的文件,然后在下方的resources文件夹中的mybatis中的相应mapper中建立编写sql语句的文件,最后在controller中去选择调用mapper类的接口函数。
这里分别贴出Records实体类,RecordsMapper,RecordsController以及RecordsMapper.xml代码
Records.java
package com.example.demo.entity;
public class Records {
public int id;
public String date;
public String lname;
public String uname;
public String number;
public String address;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String getLname() {
return lname;
}
public void setLname(String lname) {
this.lname = lname;
}
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
RecordMapper.java
package com.example.demo.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import com.example.demo.entity.Records;
@Mapper
public interface RecordsMapper {
public int findBydateAndLname(String date,String lname);
public void Book(String lname,String address,String date,String number,String uname);
public List<Records> findAllRecordsByNumber(String number);
public int findBydateAndLnameAndUname(String date,String lname,String uname);
public List<Records> findByUnumber(String number);
public List<Records> findBydateAndUnumber(String date,String number);
public void deleteBydateAndLnameAndUnumber(String date,String lname,String number);
}
RecordMapper.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 = "com.example.demo.mapper.RecordsMapper">
<select id="findBydateAndLname" resultType = "java.lang.Integer" parameterType="java.lang.String">
SELECT count(*) FROM `records` where date = #{date} and lname = #{lname};
</select>
<insert id="Book" parameterType="java.lang.String">
INSERT INTO `records`(`lname`, `address`, `date`, `number`, `uname`) VALUES (#{lname},#{address},#{date},#{number},#{uname});
</insert>
<select id="findAllRecordsByNumber" resultType="com.example.demo.entity.Records" parameterType="java.lang.String">
SELECT * FROM `records` where number = #{number};
</select>
<select id="findBydateAndLnameAndUname" resultType = "java.lang.Integer" parameterType="java.lang.String">
SELECT count(*) FROM `records` where date = #{date} and lname = #{lname} and uname = #{uname};
</select>
<select id="findByUnumber" resultType = "com.example.demo.entity.Records" parameterType="java.lang.String">
SELECT * FROM `records` where number = #{number};
</select>
<select id="findBydateAndUnumber" resultType = "com.example.demo.entity.Records" parameterType="java.lang.String">
SELECT * FROM `records` where date = #{date} and number = #{number};
</select>
<delete id="deleteBydateAndLnameAndUnumber">
DELETE FROM `records` WHERE date=#{date} and lname =#{lname} and number = #{number};
</delete>
</mapper>
RecordsController.java
package com.example.demo.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.demo.entity.Records;
import com.example.demo.mapper.RecordsMapper;
@RestController
@RequestMapping("/Record")
public class RecordsController {
@Autowired
private RecordsMapper r;
@RequestMapping("/Booknum")
public int Booknum(String date,String lname) {
int num;
num = r.findBydateAndLname(date, lname);
return num;
}
@RequestMapping("/Book")
public void Book(String lname,String address,String date,String number,String uname) {
r.Book(lname, address, date, number, uname);
}
@RequestMapping("/checkBook")
public int checkBook(String date,String lname,String uname) {
return r.findBydateAndLnameAndUname(date, lname, uname);
}
@RequestMapping("/BookHistory")
public List<Records> BookHistory(String number){
return r.findByUnumber(number);
}
@RequestMapping("/TodayBook")
public List<Records> TodayBooks(String date,String number){
return r.findBydateAndUnumber(date, number);
}
@RequestMapping("/TomorrowBook")
public List<Records> TomorrowBooks(String date,String number){
return r.findBydateAndUnumber(date, number);
}
@RequestMapping("DeleteBook")
public void DeleteBook(String date,String lname,String number) {
r.deleteBydateAndLnameAndUnumber(date, lname, number);
}
}
到这里,不出意外的话后台就和数据库顺利相连接了
要注意的是
1.mapper.xml中的返回值类型和参数类型
2.mapper.java中要标注@Mapper,迎接controller.java中的@RestController,否则可能会导致相互寻找不到
3.要注意controller.java中的@RequestMapping中的数即为传给小程序的url地址
这完这些后我们可以简单打开浏览器输入url来进行测试
例如BookHistory这一项,你可以输入http://localhost:8080/Record/BookHistory?number=参数来进行测试,如果页面能正常返回数据库结果则代表已经成功
3.微信开发者工具
这里如果你想在手机调试的话需要在设置中配置不使用任何代理,然后在项目的本地设置中设置不校验合法域名,证书等。同时还要在缓存中开启支持使用工具段的Storage。
首先展示出小程序的目录结构,如图
下面是具体程序页面和功能展示
首页
新闻详情界面
预约查询界面
预约界面点击效果
我的界面
当前预约界面
登录界面
大体效果如上图所示,主要展示一个首页页面代码?
首页文件除去tabbar还可分为
tabbar段代码需要在app.json文件中设置,同时其他页面跳转到带有tabbar页面需要使用wx.switchTab函数,代码如下
"tabBar": {
"color": "#000",
"selectedColor": "#328EEB",
"list": [
{
"pagePath": "pages/index/index",
"iconPath": "images/a-huaban2.png",
"text": "首页",
"selectedIconPath": "images/a-huaban2-2.png"
},
{
"pagePath": "pages/book/book",
"iconPath": "images/a-huaban2fuben4.png",
"text": "预约",
"selectedIconPath": "images/a-huaban2fuben4-2.png"
},
{
"pagePath": "pages/information/information",
"iconPath": "images/jiaoseguanli.png",
"text": "我的",
"selectedIconPath": "images/jiaoseguanli-2.png"
}
]
},
?其他代码
index.js
// index.js
var common =require('../../utils/common.js')
// 获取应用实例
Page({
/**
* 页面的初始数据
* 幻灯片图片以及参数
*/
data:{
indicatorDots:true,
autoplay:true,
interval:10000,
duration:1000,
imgUrls:[
"../../images/hebeidaxue.jpeg",
"../../images/wangjixueyuan.png"
],
newsList:[]
},
//界面跳转到预约规则界面
ToRules :function () {
wx.navigateTo({
url: '../index/yuyuerule/yuyuerule',
})
},
//界面跳转到实验室概况界面
ToLabs : function(){
wx.navigateTo({
url: '../index/lab/lab',
})
},
ToTeacherKnow : function () {
wx.navigateTo({
url: '../index/teacherKnow/teacherKnow',
})
},
goToDetail : function(e){
let id = e.currentTarget.dataset.id;
wx.navigateTo({
url: '../index/detail/detail?id='+id,
})
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
var that = this;
wx.request({
url: 'http://localhost:8080/News/listNews',
method:"GET",
data:{},
success:function (res) {
var list =res.data;
if(list==null){
var toastText='获取数据失败';
wx.showToast({
title:toastText,
icon:'',
duration:2000
})
}
else{
that.setData({
newsList:list
})
}
}
})
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
其中wx.request函数便是向服务器传递数据重要函数,使用起来也很简单,看图中参数就能明白
index.json暂无数据,故不展示
index.wxml
<!--index.wxml-->
<view class="haibao">
<swiper indicator-dots="{{indicatorDots}}" autoplay="{{autoplay}}" interval="{{interval}}" duration="{{duration}}">
<block wx:for="{{imgUrls}}">
<swiper-item>
<image src="{{item}}" class="silde-image" style="width: 100%;"></image>
</swiper-item>
</block>
</swiper>
</view>
<view class="nav">
<view class="nav-item">
<view bindtap="ToTeacherKnow"><image src="../../images/hangyezhengce.png" style="width: 25px;height: 25px;"></image></view>
<view>教师须知</view>
</view>
<view class="nav-item">
<view bindtap="ToRules"><image src="../../images/hangyezixun.png" style="width: 25px;height: 25px;"></image></view>
<view>预约规则</view>
</view>
<view class="nav-item">
<view bindtap="ToLabs"><image src="../../images/qiyehuaxiang.png" style="width: 25px;height: 25px;"></image></view>
<view>实验室概况</view>
</view>
</view>
<view class="hr"></view>
<view id="news-list">
<view class="list-item" wx:for="{{newsList}}" wx:for-item="news" wx:key="{{news.id}}">
<image src="{{news.poster}}"></image>
<text bindtap="goToDetail" data-id="{{news.id}}">{{news.title}}\n\n{{news.time}}</text>
</view>
</view>
index.wxss
/**index.wxss**/
.nav{
display: flex;
flex-direction: row;
text-align: center;
}
.nav-item{
width: 33%;
margin-top: 25px;
font-size: 12px;
}
.hr{
height: 10px;
background-color: gray;
margin-top: 15px;
opacity: 0.2;
}
swiper{
height: 200px;
}
swiper image{
width: 100%;
height: 100%;
}
#news-list{
min-height: 600rpx;
padding: 15rpx;
}
.list-item{
display: flex;
flex-direction: row;
border-bottom: 1rpx solid gray;
}
.list-item image{
width: 230rpx;
height: 150rpx;
margin:10rpx;
}
.list-item text{
width: 100%;
line-height: 60rpx;
font-size: 10pt;
}
?这里要注意的是wxml,wxss文件大体作用如同html,css文件其中view标签与div标签相似。
同时微信小程序不支持getelementbyid函数,所以在取页面值是要注意设置data-id,然后在js代码中使用e.currentTarget.dataset.id来获取界面值。
带页面数值跳转时可以将数据存储到缓存中,然后在页面生命周期函数中可以顺利取值赋予给新页面的元素。
选题的时候头脑发热想尝试微信小程序,一路写下来遇到不少bug,好在是顺利解决。虽然程序简单,但对我来说还是从中获取到了不少新的知识,积累经验希望能对以后的项目有所帮助。
引用伟人的话:
恰同学少年,风华正茂;书生意气,挥斥方遒。
指点江山,激扬文字,粪土当年万户侯。
曾记否,到中流击水,浪遏飞舟?
|