目录

一、学习背景

一年前,姐夫的一位朋友想找我帮忙做个小程序,那时我还是一名只会写 Java 后端的开发,对前端和小程序几乎一窍不通,一个人实在扛不下整个项目,这事只好不了了之。

一年后,我觉得是时候把前端的短板补上了,于是从 HTML、CSS、JavaScript 开始系统学习,又陆续接触了 Ajax、TypeScript、Vue2 和 Vue3。有了一定 Vue 基础后,我开始考虑做小程序,经过了解发现 Uniapp 非常契合我的情况:多端适配、条件编译、支持 Vue 语法,简直就是为我量身定做的方案。

说干就干,我在网上找了两个 Uniapp 课程,收获最大的就是 B 站 UP 主咸虾米的实战教程。跟着敲完代码,我对 Uniapp 的整体开发流程心里有了底。接着,基于自己 Java 后端的优势,我重写了所有接口,并结合若依框架搭建了管理后台,自己开发页面、对接接口。后来为了真正让项目上线,又买了域名、租了服务器,进行小程序和域名 ICP 认证的流程(目前小程序已认证通过,域名备案进行中)。

这一趟下来,从后端到前端,从开发到部署,真真切切地走了一遍全栈流程,对项目开发的认识深了不少,所以想用这篇博客把这段经历和踩过的坑记录下来。

二、学习过程与前期准备

1、跟着B站UP主-咸虾米入门,其余自己摸索

总结:通过上面两个课程,我们基本可以了解uniapp如何开发微信小程序项目了

2、即时设计的使用(画原型/UI)

2.1、官网

即时设计官网:https://js.design

2.2、设计图为什么需要设置成750px

注意:Uniapp 默认以 750rpx 为屏幕宽度,设计稿通常也是 750px,所以 100vw 等价于 750px,这是 uniapp 推荐的适配基准。因此代码开发中我们不使用px,而是使用vw,所以设计图需要调整为750px。

2.3、如何将设计图设置成750px

将图片拖进即时设计编辑页面,选中图片,点击上面的等比缩放按钮:

在这里插入图片描述

将宽度调整为750px,然后点击退出等比缩放按钮,其他图片按照这种方式依次调节即可。

在这里插入图片描述

三、项目初期:基于咸虾米接口的前台开发

1、微信申请个人小程序

1.1、注册微信小程序(已注册可跳过)

访问微信公众平台官网,点击右上角立即注册按钮,根据要求完成注册

在这里插入图片描述

1.2、登录微信公众平台

访问微信公众平台官网,微信扫码登录即可

在这里插入图片描述

1.3、补充小程序信息

注意:小程序信息和小程序类目根据提示补充即可。小程序备案需要政府部门审核,时间上会慢一些(比如我审批用了10天)。微信认证需要等待程序写好后在认证(个人认证收费30元,不认证影响分享功能,甚至连开发环境的都会影响,比如分享到朋友圈和好友)
在这里插入图片描述

1.4、配置开发管理

主要是配置服务器域名,其中request域名是发送普通请求用的,然后downloadFile合法域名是下载文件用的,当然还有其他域名类型,按需填写即可,避免无法发送请求

在这里插入图片描述

1.5、查找AppID(小程序ID)

该ID在开发过程中会使用到

在这里插入图片描述

2、使用UP主提供的接口完成前台功能

四、项目进阶:自建后端与若依框架集成

1、为什么需要自己写接口

  • 使用受限:使用作者的接口虽好,但是某一天作者接口无法使用了,我的程序就废了
  • 需要扩展:作者是开发的引路人,我不能仅仅站在他的肩膀上看世界,有些功能需要自己开发,比如我在基础上开发了微信登录、邮箱登录等功能,让这个小程序更加像那回事

2、引入若依作为后台管理系统

上面目录提到了自己写接口的原因,那写接口必然需要后端代码。作为一个java后端程序员,我就在若依的基础上进行二次开发,从而将作者的接口变成我自己的接口,其中接口返回值基本按照作者的来,避免产生大的改动

  • 后端代码:采用SpringBoot2框架,点击我
  • 前端代码:采用vue3框架,点击我

在这里插入图片描述

3、数据库与接口设计简表

3.1、新增壁纸表:xianxiami_wallpaper

CREATE TABLE `xianxiami_wallpaper`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `classid` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '所属分类classid(关联classify.classid)',
  `description` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '描述',
  `small_picurl` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '小图',
  `big_picurl` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '大图/原图',
  `tabs` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '标签,JSON数组字符串',
  `score` decimal(2, 1) NULL DEFAULT 5.0 COMMENT '评分(支持小数,如4.5)',
  `nickname` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '发布者昵称',
  `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建者',
  `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '更新者',
  `update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`) USING BTREE,
  INDEX `idx_classid`(`classid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 329 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '壁纸' ROW_FORMAT = Dynamic;

3.2、新增壁纸评分表:xianxiami_wallpaper_score

CREATE TABLE `xianxiami_wallpaper_score`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `wallpaper_id` bigint(20) NOT NULL COMMENT '壁纸ID',
  `score` decimal(2, 1) NOT NULL COMMENT '评分(如4.5)',
  `user_id` bigint(20) NULL DEFAULT NULL COMMENT '评分用户ID',
  `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '评分时间',
  PRIMARY KEY (`id`) USING BTREE,
  INDEX `idx_wallpaper_id`(`wallpaper_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '壁纸评分' ROW_FORMAT = Dynamic;

3.3、新增壁纸下载记录表:xianxiami_wallpaper_download_record

CREATE TABLE `xianxiami_wallpaper_download_record`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `wallpaper_id` bigint(20) NOT NULL COMMENT '壁纸ID',
  `user_id` bigint(20) NULL DEFAULT NULL COMMENT '下载用户ID',
  `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '下载时间',
  PRIMARY KEY (`id`) USING BTREE,
  INDEX `idx_wallpaper_id`(`wallpaper_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 10 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '壁纸下载记录' ROW_FORMAT = Dynamic;

3.4、新增资讯公告表:xianxiami_notice

CREATE TABLE `xianxiami_notice`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `title` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '标题',
  `author` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '作者',
  `content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '内容(HTML)',
  `view_count` int(11) NULL DEFAULT 0 COMMENT '阅读数',
  `is_select` tinyint(1) NULL DEFAULT 0 COMMENT '是否推荐(0-否,1-是)',
  `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建者',
  `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '更新者',
  `update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间(作为发布日期)',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '资讯公告' ROW_FORMAT = Dynamic;

3.5、新增壁纸分类表:xianxiami_classify

CREATE TABLE `xianxiami_classify`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '分类名称',
  `sort` int(11) NULL DEFAULT 0 COMMENT '排序',
  `picurl` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '分类图片',
  `is_select` tinyint(1) NULL DEFAULT 1 COMMENT '是否推荐(0-否,1-是)',
  `is_show` tinyint(1) NULL DEFAULT 1 COMMENT '是否展示(0-否,1-是)',
  `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建者',
  `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '更新者',
  `update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 19 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '壁纸分类' ROW_FORMAT = Dynamic;

3.6、修改系统用户表(sys_user),新增weixin_openid字段

-- 在 sys_user 表中新增微信 openid 字段,允许为空(因为并非所有用户都通过微信登录)
ALTER TABLE sys_user 
ADD COLUMN weixin_openid VARCHAR(64) NULL COMMENT '微信小程序openid';

五、AI 在开发中的应用

关于咸虾米作者写的那些页面,我是自己敲了一遍,但是集成微信一键登录、邮箱登录的前端页面代码和后端代码,我通过AI 辅助来写,然后我进行审校与微调

六、Uniapp 项目开发详解

1、项目创建与基础配置(插件、appid、H5 模式)

1.1、下载HbuilderX

官网下载地址:https://www.dcloud.io/hbuilderx.html

1.2、创建项目

在这里插入图片描述

输入项目信息,创建项目:

在这里插入图片描述

1.3、安装插件

1.3.1、进入插件市场

官方插件市场网址:https://ext.dcloud.net.cn/

1.3.2、安装插件

首先需要打开HBuilderX,然后找到合适的插件后,点击下载插件并导入HbuilderX,此时会弹出窗口,我们点击打开HBuilderX:
在这里插入图片描述
此时HBuilderX中会弹出一个弹窗,需要选择插件安装的项目名称,然后点击确定按钮:

在这里插入图片描述

如果后续弹出窗口让你进行合并操作,你直接点击合并即可,HbuilderX会自动处理合并事宜。

1.3.3、卸载插件

当插件安装之后,就会进入uni_modules目录下,找到对应插件目录删除即可

在这里插入图片描述

1.4、配合微信开发工具使用

1.4.1、配置微信小程序APPID

在这里插入图片描述

1.4.2、让HBuilderX能够调用微信开发者工具
1.4.2.1、下载微信开发者工具

官方下载地址

1.4.2.2、在HBuilderX中配置微信开发者工具安装路径

打开配置页面:

在这里插入图片描述

将微信开发者工具安装路径配置一下:

在这里插入图片描述

1.4.2.3、在HBuilderX中调用微信开发者工具

在这里插入图片描述

1.4.3、项目开发调试

如果安装新插件之后,最好手动关闭微信开发者工具,然后在HBuilderX中重新运行微信小程序,这样HbuilderX会自动启动微信开发者工具,避免新代码不生效

1.4.4、清理缓存、授权

在这里插入图片描述

1.4.5、发布微信小程序

首先关闭微信小程序开发工具,然后在HBuilderX中执行如下操作:

在这里插入图片描述

填写基本信息,然后点击发行按钮:

在这里插入图片描述

然后HBuilderX会唤醒微信小程序开发工具,之后点击上传按钮:

在这里插入图片描述

填写相关信息后,点击上传按钮即可:

在这里插入图片描述

1.5、配合谷歌浏览器使用

1.5.1、运行到谷歌浏览器
1.5.1.1、配置web服务器

将谷歌浏览器的路径配置到下面

在这里插入图片描述

1.5.1.2、运行项目到浏览器

在这里插入图片描述

1.5.2、打包成H5页面
1.5.2.1、配置Web信息

在这里插入图片描述

1.5.2.2、打包

在这里插入图片描述

点击发行即可打包

在这里插入图片描述

打包结果是web目录(如下图),当然也会在HBuilderX控制台打印出完整路径

在这里插入图片描述

2、工程化:Sass 变量、全局 API 封装

2.1、Sass变量

2.1.1、uni.scss(全局sass变量定义入口)
  • 定义sass变量:例如$uni-text-color:#000;//基本色
  • 引入其他sass类型文件:@import '@/common/style/base-style.scss';
2.1.2、定义其他sass类型文件

说明: 文件内容如下,然后在uni.scss中使用@import关键字引入即可(上面已解释,不在赘述)。下面文件中的变量从引入之后也是全局sass变量

/* 文字基本颜色 */
$uni-text-color:#000;//基本色
$uni-text-color-inverse:#fff;//反色
$uni-text-color-grey:#666;//辅助灰色,如加载更多的提示信息
$uni-text-color-placeholder: #808080;
$uni-text-color-disable:#c0c0c0;

// 品牌主体色
$brand-theme-color:#28B389;

// 设置uni-icons标签中的color属性
// 用法:<uni-icons type="search" size="20" color="var(--uni-text-color-grey)"></uni-icons>
:root {
	--uni-text-color-grey: #{$uni-text-color-grey};
	--brand-theme-color: #{$brand-theme-color}
}
2.1.3、使用sass变量

在这里插入图片描述

2.2、全局 API 封装

2.2.1、API定义js文件
import {BASE_URL} from '@/utils/request.js'

// 处理路径的方法
export const getFullImageUrl = (path) => {
  if (!path) return ''
  if (path.startsWith('http') || path.startsWith('//')) return path
  // 确保路径以 / 开头
  const normalizedPath = path.startsWith('/') ? path : `/${path}`
  return BASE_URL + normalizedPath
}
2.2.2、在main.js中挂载全局API方法
import App from './App'
import { getFullImageUrl } from '@/utils/imageHelper'

// #ifndef VUE3
import Vue from 'vue'
import './uni.promisify.adaptor'
Vue.config.productionTip = false
App.mpType = 'app'

// Vue2 挂载全局方法
Vue.prototype.$getFullImageUrl = getFullImageUrl

const app = new Vue({
  ...App
})
app.$mount()
// #endif

// #ifdef VUE3
import { createSSRApp } from 'vue'
export function createApp() {
  const app = createSSRApp(App)
  
  // Vue3 挂载全局方法
  app.config.globalProperties.$getFullImageUrl = getFullImageUrl
  
  return {
    app
  }
}
// #endif
2.2.3、使用全局方法
2.2.3.1、在html中使用

全局API不需要引入,直接使用即可

在这里插入图片描述

2.2.3.2、在js脚本中使用(vue3语法)
<script setup>
	import {
		getCurrentInstance
	} from 'vue'
	
	const {
		proxy
	} = getCurrentInstance()
	
	// 示例
	const image = await new Promise((resolve, reject) => {
		uni.getImageInfo({
			// 使用方法如下
			src: proxy.$getFullImageUrl(currentPicture.value.bigPicurl),
			success: resolve,
			fail: reject
		})
	})
</script>

3、页面与组件拆分、Pinia 状态管理

3.1、页面与组件拆分

3.1.1、页面

pages目录下创建vue文件,这些都是做页面用的,和pages.json文件中的页面信息一一对应

在这里插入图片描述

3.1.2、组件

在根目录下创建components目录,然后该目录下面创建vue文件,这就是组件

在这里插入图片描述

components目录下创建的组件,如果需要在pages目录下的vue文件中使用,不需要引入,直接使用即可,这是uniapp都处理好的

但是在components目录下创建的组件需要互相引入,不能直接使用,只能通过import方式引入后才能使用组件

3.2、Pinia 状态管理

3.2.1、创建状态信息—js文件

例如存储用户信息的功能,可以创建stores》user.js文件

// stores/user.js
import {
	defineStore
} from 'pinia'
import {
	setToken,
	getToken,
	setUserInfo,
	getUserInfo,
	removeToken,
	removeUserInfo
} from '@/utils/storage'
import { getFullImageUrl } from '@/utils/imageHelper.js'   // 根据实际路径导入

export const useUserStore = defineStore('user', {
	state: () => ({
		token: '',
		userInfo: null
	}),
	actions: {
		// 初始化:从本地恢复数据
		restore() {
			this.token = getToken()
			this.userInfo = getUserInfo()
		},
		// 登录成功:保存到 Pinia 和本地
		recordToken(token) {
			this.token = token
			setToken(token)
		},
		recordUserInfo(userInfo) {
			this.userInfo = userInfo
			setUserInfo(userInfo)
		},
		// 退出登录
		logout() {
			this.token = ''
			this.userInfo = null
			removeToken()
			removeUserInfo()
		},
		// 更新用户信息(通用方法)
		updateUserInfo(updates) {
			// 合并更新对象
			this.userInfo = {
				...this.userInfo,
				...updates
			}
			// 同步到本地存储
			setUserInfo(this.userInfo)
		}
	},
	getters: {
		userAvatar() {
			if (this.userInfo?.avatar) {
				return getFullImageUrl(this.userInfo.avatar)
			}
			return '/static/images/xxmLogo.png'
		}
	}
})
3.2.2、在main.js中安装pinia
import App from './App'
import * as Pinia from 'pinia';

// #ifdef VUE3
import { createSSRApp } from 'vue'
export function createApp() {
  const app = createSSRApp(App)
  
  // 安装pinia
  app.use(Pinia.createPinia());
  
  return {
    app,
		Pinia, // 此处必须将 Pinia 返回
  }
}
// #endif
3.2.3、使用pinia
3.2.3.1、在script中使用
import {
	useUserStore
} from '@/stores/user'

const userStore = useUserStore()

// 解构pinia变量/方法
const {
	userInfo
} = storeToRefs(userStore)

// 通用上传函数:将临时路径上传到服务器
const uploadAvatar = async (tempFilePath) => {
  uni.showLoading({ title: '上传中...', mask: true })
  try {
    const uploadRes = await uni.uploadFile({
      url: BASE_URL + '/system/user/profile/avatar',
      filePath: tempFilePath,
      name: 'avatarfile',
      // 使用pinia变量
      header: { Authorization: `Bearer ${userStore.token}` }
    })
    const resData = JSON.parse(uploadRes.data)
    if (resData.code === 200) {
      // 使用pinia方法
      userStore.updateUserInfo({ avatar: resData.imgUrl })
      uni.showToast({ title: '头像更新成功', icon: 'success' })
    } else {
      throw new Error(resData.msg || '上传失败')
    }
  } catch (err) {
    console.error(err)
    uni.showToast({ title: '头像上传失败', icon: 'none' })
  } finally {
    uni.hideLoading()
  }
}
3.2.3.2、在html中使用
<template>
	<view class="profile-edit">
		<!-- 头像区域 -->
		<view class="avatar-wrapper">
			<!-- 使用pinia状态 -->
			<image class="avatar" :src="userStore.userAvatar" mode="aspectFill" />
			<!-- #ifdef MP-WEIXIN -->
			<button class="avatar-btn" open-type="chooseAvatar" @chooseavatar="onChooseAvatar" />
			<!-- #endif -->
			<!-- #ifndef MP-WEIXIN -->
			<button class="avatar-btn" @click="chooseImageH5">选择头像</button>
			<!-- #endif -->
		</view>

4、生命周期与 Vue 相关 API 的统一引入

使用unplugin-auto-import插件,解决引入 ref、reactive、onLoad、onShow 这些 API的问题,请看博客

5、开发中遇到的坑与解决(样式不生效、真机调试差异等)

一般关闭微信小程序开发工具,重启服务即可解决问题

6、其他知识点

6.1、生命周期

官方网址:页面生命周期,uniapp的生命周期不同于Vue的生命周期,uniapp常用生命周期钩子如下:

  • onLoad:比较适合的操作是:接受上页的参数,联网取数据,更新data。
  • onUnload:监听页面卸载
  • onShow和onHide:注意页面显示,是一个会重复触发的事件。进入页面触发当前页面的onShow生命周期,离开页面触发当前页面的onHide生命周期
  • onReachBottom:比如设为50,那么滚动页面到距离底部50px时,就会触发onReachBottom事件。可在pages.json里定义具体页面底部的触发距离onReachBottomDistance,默认值是50px
  • onPageScroll:监听滚动事件
  • onPullDownRefresh:监听用户下拉动作,一般用于下拉刷新
  • onShareAppMessage:用户点击右上角分享
  • onShareTimeline:监听用户点击右上角转发到朋友圈

6.2、html标签

在uniapp中,已经不在使用传统的html标签,只能使用uniapp自定义的标签,其实就是uniapp自定义的组件

6.3、API

6.4、编译器(条件编译)

uniapp是一套代码,每一种情况都能使用,虽然uniapp官方已经进行了大部分兼容工作,但是肯定不可能做完,如果我们想让不同的小程序展示不同的效果,那就需要使用条件编译,点我查看官方文档

6.5、相关网址

  • 教程:uniapp的介绍信息、使用信息、相关用法,也包括vue在unaipp中的用法、条件编译等
  • 全局文件:包括pages.json(页面信息)、manifest.json(小程序、网页等配置信息)、vite.config.js等内容讲解
  • 组件:相当于html中的标签
  • API:uniapp内置的api方法
  • 插件:需要啥插件直接去插件市场搜索即可,不过需要注意适配的vue版本,以及最近更新时间,避免出现没人维护的情况

七、项目部署与上线

1、域名申请与备案、微信小程序认证

1.1、域名申请与备案

  • 域名申请:可以在腾讯云或者阿里云等网址购买域名,比如我是在腾讯云买的,首年免费,2年起购
  • 域名备案:通过域名访问到服务器,需要进行ICP备案才行,我是通过阿里云进行的ICP备案,点击我官网

1.2、微信小程序认证

针对个人用户来说,需要支付30元进行微信小程序认证,否则不能上线,但是企业用户的还不知道啥情况。这一步最好放到网站域名可用,服务开发完成时在进行微信小程序认证,不然小程序都不能使用,那认证也没法通过

2、服务器环境搭建(MySQL、Redis、Nginx)

2.1、MySQL

2.1.1、拉取镜像
docker pull mysql5.7
2.1.2、创建目录
mkdir -p /data/docker-volumes/mysql/{log,data,conf}
2.1.3、创建配置文件

进入/data/docker-volumes/mysql/conf,执行vim my.cnf,将以下内容复制到文件中,然后保存即可。其中cnf文件名称无所谓,其中容器会加载并引入 /etc/mysql/conf.d/ 目录下所有以 .cnf 结尾的文件

[client]
default-character-set=utf8mb4

[mysql]
default-character-set=utf8mb4

[mysqld]
# 字符集设置
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci

# 连接初始化设置
init_connect='SET NAMES utf8mb4'
init_connect='SET collation_connection = utf8mb4_unicode_ci'

# 跳过客户端字符集协商(强制使用服务器端设置)
skip-character-set-client-handshake

# 禁用 DNS 反向解析(加速连接,避免 DNS 问题)
skip-name-resolve

# 解决时区问题
default-time-zone = '+08:00'
2.1.4、启动容器
docker run -d --name mysql5.7 -p 13306:3306 --privileged=true --restart=always \
-v /data/docker-volumes/mysql/log:/var/log/mysql \
-v /data/docker-volumes/mysql/data:/var/lib/mysql \
-v /data/docker-volumes/mysql/conf:/etc/mysql/conf.d \
-e MYSQL_ROOT_PASSWORD=123456 mysql:5.7

2.2、Redis

2.2.1、拉取镜像
docker pull redis:6.0.8
2.1.2、创建目录
mkdir -p /data/docker-volumes/redis/{data,conf}
2.1.3、创建配置文件

进入/data/docker-volumes/redis/conf,执行vim redis.conf,将以下内容复制到文件中,然后保存即可。

// 将以下链接中的redis.conf文件复制到conf目录下
链接:https://pan.baidu.com/s/1OLPyYh0NcwmXlHIKhFr3dQ?pwd=oq8y
更改参数说明:1、开启密码验证,搜索“requirepass”可见;2、注释“bind 127.0.0.1”,允许外部连接;3、设置“daemonize no”,避免和docker run中-d参数冲突,导致容器启动失败;4、设置“appendonly yes ”,开启容器持久化
2.2.4、启动容器
docker run -d   -p 16379:6379   --privileged=true \
--name="redis6.0.8"   --restart=always \
-v /data/docker-volumes/redis/conf/redis.conf:/etc/redis/redis.conf \
-v /data/docker-volumes/redis/data:/data redis:6.0.8 \
redis-server /etc/redis/redis.conf

2.3、Nginx

2.3.1、拉取镜像
docker pull nginx:alpine
2.3.2、创建目录
mkdir -p /data/docker-volumes/nginx/{html,conf,ssl-cert}
2.3.3、创建配置文件—default.conf

进入目录/data/docker-volumes/nginx/conf,执行vim default.conf,将以下内容赋值进去,根据你的来改哈,这是我的配置。

说一下哈,conf目录下以conf结尾的文件都会被根配置文件自动引入,所以我们自定义的配置文件里面只需要添加server配置即可。

# 处理 HTTP 访问:
# 1. 访问 http://www.eastmoonlight.com → 301 重定向到 HTTPS 版本
# 2. 访问 http://eastmoonlight.com → 也重定向到 https://www.eastmoonlight.com(避免证书错误)
server {
    listen 80 default_server;
    client_max_body_size 20M;
    server_name www.eastmoonlight.com;
    return 301 https://www.eastmoonlight.com$request_uri;
}

# HTTPS 核心配置(只针对 www.eastmoonlight.com)
server {
    listen 443 ssl http2;
    client_max_body_size 20M;
    server_name www.eastmoonlight.com;   # 只能写这一个域名

    # SSL 证书路径(替换成你实际的文件名)
    ssl_certificate     /etc/nginx/ssl/www.eastmoonlight.com.pem;
    ssl_certificate_key /etc/nginx/ssl/www.eastmoonlight.com.key;

    ssl_session_timeout 5m;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
    ssl_prefer_server_ciphers on;

    # ----- 以下是你原有的网站配置,保持不变 -----
    # 全局根目录
    root /usr/share/nginx/html;

    # 重定向到项目
    location / {
        return 301 /xxm-h5/;
    }

    # 处理前端路由(SPA)
    location /xxm-admin/ {
        try_files $uri $uri/ /xxm-admin/index.html;
    }
    location /xxm-h5/ {
        try_files $uri $uri/ /xxm-h5/index.html;
    }

    # 静态资源(带扩展名)直接返回,不经过前端路由
    location ~* ^/(xxm-admin|xxm-h5)/.*\.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
        try_files $uri =404;
    }

    # 后端 API 代理
    location /xxm-api/ {
        proxy_pass http://172.17.0.1:18080/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}
2.3.4、配置ssl证书
2.3.4.1、证书作用

如果不申请证书,域名前面就没法使用https协议,这样微信小程序中的图片就没法展示了(微信要求图片的链接必须是https协议)

2.3.4.2、申请ssl配置文件

对于个人网站来说,可以申请测试证书即可,阿里云每年提供20次ssl证书申请机会,每次申请的证书有效期是90天。点我去申请证书 阿里云官网网址,需要进行一次认证,一般都是配合申请域名的平台添加一个解析链接就可以认证了

2.3.4.3、下载证书

当验证完成后,就可以下载证书了

在这里插入图片描述

当证书下载完成后,里面有两个文件

在这里插入图片描述

2.3.4.4、安装证书

进入目录/data/docker-volumes/nginx/ssl-cert,将上面两个配置文件复制到上述目录

2.3.5、启动容器
docker run -d   --name nginx   -p 80:80 -p 443:443 \
-v /data/docker-volumes/nginx/conf:/etc/nginx/conf.d \
-v /data/docker-volumes/nginx/html:/usr/share/nginx/html \
-v /data/docker-volumes/nginx/ssl-cert:/etc/nginx/ssl:ro nginx:alpine

3、前后端服务部署

3.1、部署后端服务

3.1.1、放置jar包

创建目录/home/xxm-wallpaper/backend,然后将jar包复制到该目录下

在这里插入图片描述

3.1.2、创建启动配置文件

进入目录/etc/systemd/system,创建文件xxm-backend.service,将以下内容复制进去

[Unit]
Description=XXM Wallpaper Backend
After=network.target

[Service]
Type=simple
User=root
WorkingDirectory=/home/xxm-wallpaper/backend
ExecStart=/usr/bin/java -jar /home/xxm-wallpaper/backend/ruoyi-admin.jar --spring.profiles.active=prod -Duser.timezone=Asia/Shanghai
Restart=on-failure
RestartSec=10

[Install]
WantedBy=multi-user.target
3.1.3、启动服务
# 重新加载 systemd 配置
sudo systemctl daemon-reload

# 启动服务
sudo systemctl start xxm-backend

# 查看状态
sudo systemctl status xxm-backend

# 设置开机自启
sudo systemctl enable xxm-backend
3.1.4、日常维护命令
systemctl stop ruoyi      # 停止
systemctl restart ruoyi   # 重启
journalctl -u ruoyi -f    # 实时查看日志

3.2、部署前端服务

3.2.1、上传压缩包并解压

将打包完成的结果,直接上传到nginx外挂的html目录下

在这里插入图片描述

3.2.2、前端配置:网页访问前缀
3.2.2.1、uniapp项目

在这里插入图片描述

3.2.2.2、普通vue3项目

vite配置文件:

在这里插入图片描述

路由配置:

在这里插入图片描述

3.2.3、前端配置:访问后端地址
3.2.3.1、uniapp项目

可以在本地使用,也向外暴露了,哪个地方需要哪里引入即可,一处更改,处处生效

在这里插入图片描述

3.2.3.2、普通vue3项目

.env.production配置:

在这里插入图片描述

request.js配置:

在这里插入图片描述

这样配置之后,前端会自动使用域名+/xxm-api去访问后端接口,当然我已经在nginx配置文件中声明好了,系统会自动将请求转到后端服务

3.2.4、后端配置:接口访问前缀

配置成/即可,我已经在nginx中配置好了,系统会自动将/xxm-api前缀的请求转发到后端服务中

八、项目成果与收获总结

1、管理后台

在这里插入图片描述

2、H5端

在这里插入图片描述

3、小程序端

微信小程序名称: 月色东升壁纸

在这里插入图片描述

更多推荐