《Techporters架构搭建》-Day06 国际化
什么是国际化?
国际化,也叫i18n,为什么叫i18n呢?
"i18n"是国际化(internationalization)的缩写,数字18代表了国际化这个单词中间的字母数量。类似这样的缩写还有k8s(kubernetes)等
为什么使用国际化?
简单理解就是开发的软件需要能同时应对不同国家和地区的用户访问,并根据用户地区和语言习惯,提供相应的、符合用具阅读习惯的页面和数据,例如,为中国用户提供汉语界面显示,为美国用户提供提供英语界面显示。
国际化细分
国际化需要分成两个部分:
前端国际化
前端国际化主要关注页面的显示和用户界面的本地化。它涉及将应用程序的界面元素,如文本、标签、按钮等,根据用户的语言和地区进行翻译和适配。前端国际化通常使用资源文件、语言包或翻译服务来存储和管理不同语言的文本。前端开发人员可以通过使用国际化框架或库,如React Intl、Vue I18n或Angular i18n等,来实现前端国际化功能
后端国际化
后端国际化主要关注处理与业务逻辑和数据相关的国际化问题。这包括但不限于日期和时间格式、货币符号、数字格式、排序规则、接口提示信息等。后端国际化的目标是确保应用程序能够适应不同的语言和地区,并提供正确的本地化数据。后端国际化可以通过使用国际化库或框架,如SpringBoot I18n,来实现后端国际化功能
总之,前端国际化主要关注页面显示和用户界面的本地化,而后端国际化则处理与业务逻辑和数据相关的国际化问题。两者通常需要协同工作,以实现完整的国际化功能
国际化相关知识
Locale对象
需要支持国际化,得先知道选择的是哪种地区的哪种语言,java中使用java.util.Locale来表示地区语言,这个对象内部包含了国家和语言的信息。
Locale中最常用的构造方法:
public Locale(String language, String country) {this(language, country, "");
}
构造方法有两个参数:language:语言、country:国家
这两个参数的值不是乱写的,国际上有统一的标准,如:zh-CN表示中国大陆地区的中文,zh-TW表示中国台湾地区的中文,en-US表示美国地区的英文,en-GB表示英国地区的英文等等。通过语言和国家构造Locale对象,比如Locale locale = new Locale(“zh”, “CN”);,表示中国大陆地区的中文。
MessageSource接口
这是 Spring 国际化的核心接口,其定义如下:
public interface MessageSource {/*** 获取国际化信息*/@NullableString getMessage(String code, @Nullable Object[] args, @Nullable String defaultMessage, Locale locale);/*** 与上面的方法类似,只不过在找不到资源中对应的属性名时,直接抛出NoSuchMessageException异常*/String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException;/*** @param MessageSourceResolvable 将属性名、参数数组以及默认信息封装起来,它的功能和第一个方法相同*/String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException;
}
MessageSource接口提供了三个获取国际化消息的方法,其主要是根据 Locale 信息获取对应的国际化消息的集合,然后根据 code 获取对应的消息,并且通过提供的参数 args 还可以对获取后的消息进行格式化。
具体参数含义如下:
| 参数名 | 含义 |
|---|---|
| code | 表示国际化资源中的属性名 |
| args | 为消息中的参数填充的值 |
| defaultMessage | 默认的消息,如果没有找到将返回默认消息 |
| resolvable | 消息参数,封装了 code、args、defaultMessage |
| locale | 表示本地化对象 |
类图结构

常见3个实现类:
| 类名 | 含义 |
|---|---|
ResourceBundleMessageSource | 这个是基于Java的ResourceBundle基础类实现,允许仅通过资源名加载国际化文件 |
ReloadableResourceBundleMessageSource | 这个功能和第一个类的功能类似,多了定时刷新功能,允许在不重启系统的情况下,更新国际化文件的信息 |
StaticMessageSource | 它允许通过编程的方式提供国际化信息。 |
重点:我们在项目中会创建 MessageSource接口,但不管使用哪个实现类或者我们自定义的类,都要将Bean名称设置为messageSource
加载ApplicationContext时,自动搜索上下文中定义的MessagesSource Bean(名称必须为messageSource)。
如果无法找到消息的任何源,则实例化一个空的messageSource。
LocaleResolver接口
这个接口是用来设置当前会话默认的国际化语言的,其定义如下:
public interface LocaleResolver {/*** 根据当前请求解析当前请求的本地化信息*/Locale resolveLocale(HttpServletRequest request);/*** 设置当前请求、响应的本地化信息*/void setLocale(HttpServletRequest request, @Nullable HttpServletResponse response, @Nullable Locale locale);
}
resolveLocale方法用于从当前request中解析对应出对应的Locale对象,场景如:
常见4个实现类:
| 类名 | 含义 |
|---|---|
AcceptHeaderLocalResovler | 通过请求头里面的Accept-Language:zh,en;q=0.9,zh-HK;q=0.8来决定使用具体的Locale实例,其实AcceptHeaderLocalResovler就是使用HttpServletRequest实例中的Locale实例,在进入DispatcherServlet的时候HttpServletRequest实例里面就已经有Locale实例了,可以通过request.getLocale();来获取Locale实例,HttpServletRequest里面的Locale实例就是使用请求头里面的Accept-Language:zh,en;q=0.9,zh-HK;q=0.8来构建的,比如请求头里面的Accept-Language:zh,en;q=0.9,zh-HK;q=0.8 就表示zh的权重是1,en;q=0.9表示en的权重是0.9,zh-HK;q=0.8就表示zh-HK的权重是0.8,那么我么通过request.getLocale();获取到的就是权重最高的zh,然后就是构建一个zh的Locale实例,那么AcceptHeaderLocalResovler在解析Locale的时候就会返回zh的Locale实例 |
CookieLocaleResovler | 根据用户在Cookie中设置的某参数来进行确定具体的本地化Locale实例 |
SessionLocaleResovler | 根据用户在HttpSession中设置某参数来进行确定具体的本地化Locale实例 |
FixedLocalResovler | 使用jdk自带的默认的Locale实例 |
国际化文件
项目中,在resources目录下创建名为i18n的文件目录,然后我们在i18n目录创建国际化文件
格式为:名称_语言_地区.properties
我们先来创建两种语言,如:
message.properties(这个文件名称没有指定Local信息,当系统找不到的时候会使用这个默认的)
name=您的姓名
text=默认文本
message_cn_ZH.properties:中文【中国】
name=姓名
text=文本
messages_en_US.properties 英文【美国】
name=name
text=text
我们通过MessageSource接口的getMessage方法传入对应的key(如name、text),便可以从国际化文件中取值。同时我们还可以指定Locale对象,便能找到对应的国际化文件然后取值。
国际化一般实现
一般让前端在请求头中, 添加 { “Accept-Language”: “zh” }来标识,用户使用的语言
然后我们添加拦截器, 将这个值取出来, 这一步springboot已经帮我们做了(默认配置)
所以一般的单体springboot项目中, 直接在配置一下国际化资源文件即可
@Configuration
public class I18nConfig implements WebMvcConfigurer {@Beanpublic MessageSource messageSource() {// 多语言文件地址Locale.setDefault(Locale.CHINA);ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();//设置国际化文件存储路径 resources目录下 可以设置多个messageSource.addBasenames("i18n/common/messages","i18n/system/messages","i18n/device/messages");//设置根据key如果没有获取到对应的文本信息,则返回key作为信息messageSource.setUseCodeAsDefaultMessage(true);//设置字符编码messageSource.setDefaultEncoding(StandardCharsets.UTF_8.toString());return messageSource;}
}
然后在对应的目录文件(/i18n/common/)下定义国际化资源文件
美式英语 messages_en_US.properties
user.login.username=User name
user.login.password=Password
user.login.code=Security code
user.login.remember=Remember me
user.login.submit=Sign In
中文简体 messages_zh_CN.properties
user.login.username=用户名
user.login.password=密码
user.login.code=验证码
user.login.remember=记住我
user.login.submit=登录
MessageUtils工具类
public class MessageUtils
{/*** 根据消息键和参数 获取消息 委托给spring messageSource** @param code 消息键* @param args 参数* @return 获取国际化翻译值*/public static String message(String code, Object... args){MessageSource messageSource = SpringUtils.getBean(MessageSource.class);return messageSource.getMessage(code, args, LocaleContextHolder.getLocale());}
}
然后直接这样使用就行
MessageUtils.message("user.login.username")
MessageUtils.message("user.login.password")
国际化改进版
下面看网上的两种国际化
通过数据库实现国际化
基于若依-cloud的国际化方案
框架中国际化
目前我们国际化应用场景1.接口抛出的异常国际化 2.参数校验实现国际化
① 因为每个服务都有国际化配置文件,所以关于加载国际化配置的配置类我们放在common包中,首选创建加载MessageSource实现类的I18nConfig 配置类,这个配置类有以下作用:
- 实例化ReloadableResourceBundleMessageSource
- MessageSourceAccessor是对MessageSource的封装,提供了更便捷的方法来获取消息,免去我们封装MessageUtils类。
package com.tps.cloud.config;import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.context.MessageSource;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.context.annotation.Bean;@AutoConfiguration
public class I18nConfig {private static final String BASE_NAME = "classpath:i18n/messages";@Beanpublic MessageSource messageSource() {ReloadableResourceBundleMessageSource reloadableResourceBundleMessageSource = new ReloadableResourceBundleMessageSource();reloadableResourceBundleMessageSource.setBasenames(BASE_NAME);reloadableResourceBundleMessageSource.setCacheSeconds(5);reloadableResourceBundleMessageSource.setDefaultEncoding("UTF-8");return reloadableResourceBundleMessageSource;}@Beanpublic MessageSourceAccessor messageSourceAccessor(MessageSource messageSource) {MessageSourceAccessor accessor = new MessageSourceAccessor(messageSource) ;return accessor ;}}
②ValidatorConfig配置类,此类作用:
- 注入MessageSource,用于国际化配置。
- 实例化工厂LocalValidatorFactoryBean,设置:
- 设置国际化:将MessageSource设置到ValidationMessageSource
- 设置提供者类(校验器):HibernateValidator
- 设置属性:实例化Properties,配置Hibernate的快速异常返回,hibernate.validator.fail_fast,加入到工厂配置。(快速返回指的是遇到一个不合法的,就不继续往下校验。)
- 加载配置:调用factoryBean的afterPropertiesSet
- 返回工厂方法的Validator
这里可以顺便谈谈关于Spring的FactoryBean:
- FactoryBean是接口,实现该接口的类可以自定义创建Bean。一般在框架中用来创建复杂的Bean。
- 这里的FactoryBean,实现InitializingBean接口,在afterPropertiesSet方法中创建bean,会在bean 实例化后调用。
- FactoryBean让Bean构建过程更灵活,可以理解为一种策略模式,我们需要生成什么样的
bean,可以通过实现接口来自定义。
package com.tps.cloud.config;import jakarta.validation.Validator;
import org.hibernate.validator.HibernateValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;import java.util.Properties;@AutoConfiguration
public class ValidatorConfig {@Autowiredprivate MessageSource messageSource;/*** 配置校验框架 快速返回模式*/@Beanpublic Validator validator() {LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();// 国际化factoryBean.setValidationMessageSource(messageSource);// 设置使用 HibernateValidator 校验器factoryBean.setProviderClass(HibernateValidator.class);Properties properties = new Properties();// 设置 快速异常返回properties.setProperty("hibernate.validator.fail_fast", "true");factoryBean.setValidationProperties(properties);// 加载配置factoryBean.afterPropertiesSet();return factoryBean.getValidator();}
}
③ 在对应的服务下创建国际化资源文件

④ 在接口入参对象上添加占位符,然后测试保存用户接口
@NotBlank(message = "{SystemUserDto.Username.NotEmpty}")@UniqueUsernameprivate String username;
@PostMappingpublic Result<Long> save(@RequestBody @Validated SystemUserDto systemUserDto) {Long id=systemUserService.createUser(systemUserDto);return Result.ok(id);}
⑤ 创建异常处理器,用于捕获参数验证异常,并返回统一数据结构
package com.tps.cloud.handler;import com.tps.cloud.response.Result;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;import java.util.List;/*** 全局异常处理器MethodArgumentNotValidException*/
@RestControllerAdvice
public class GlobalExceptionHandler {/*** validation Exception (以form-data形式传参)* @param exception* @return Result*/@ExceptionHandler({ BindException.class })@ResponseStatus(HttpStatus.BAD_REQUEST)public Result bindExceptionHandler(BindException exception) {List<FieldError> fieldErrors = exception.getBindingResult().getFieldErrors();return Result.failed(fieldErrors.get(0).getDefaultMessage());}/*** validation Exception* @param exception* @return Result*/@ExceptionHandler({ MethodArgumentNotValidException.class })public Result handleBodyValidException(MethodArgumentNotValidException exception) {FieldError fieldError = exception.getBindingResult().getFieldError();return Result.failed(String.format("%s", fieldError.getDefaultMessage()));}
}
⑥通过Apifox测试,通过Header传递国际化参数Accept-Language参数(en-US,zh-CN),模拟参数username为空状态


⑦ 现在模拟异常抛出国际化,首先在保存接口添加用户账号唯一校验(记得去除掉上节添加的@UniqueUsername注解,防止被影响)
private final MessageSourceAccessor messages;@PostMappingpublic Result<Long> save(@RequestBody @Validated SystemUserDto systemUserDto) {//验证用户唯一SystemUserVo systemUserVo=systemUserService.findByUsername(systemUserDto.getUsername());if(systemUserVo!=null){return Result.failed(messages.getMessage("SystemUserDto.Username.Exist"));}Long id=systemUserService.createUser(systemUserDto);return Result.ok(id);}
国际化配置文件添加SystemUserDto.Username.Exist:

通过Apifox测试,通过Header传递国际化参数Accept-Language参数(en-US,zh-CN),模拟参数username重复存在的情况。

相关文章:
《Techporters架构搭建》-Day06 国际化
什么是国际化? 国际化,也叫i18n,为什么叫i18n呢? "i18n"是国际化(internationalization)的缩写,数字18代表了国际化这个单词中间的字母数量。类似这样的缩写还有k8s(kube…...
Linux ACL 访问控制
今天给伙伴们分享一下Linux ACL 访问控制,希望看了有所收获。 我是公众号「想吃西红柿」「云原生运维实战派」作者,对云原生运维感兴趣,也保持时刻学习,后续会分享工作中用到的运维技术,在运维的路上得到支持和共同进步…...
hg transformers pipeline使用
什么是hg transformers pipeline? 在Hugging Face的transformers库中,pipeline是一个高级API,它提供了一种简便的方式来使用预训练模型进行各种NLP任务,比如情感分析、文本生成、翻译、问答等。通过pipeline,你可以在几行代码内…...
高性能内存对象缓存
Memcached概述 一套开源的高性能分布式内存对象缓存系统 所有的数据都存储在内存中 支持任意存储类型的数据 提高网站的访问速度 数据存储方式与数据过期方式 数据存储方式:Slab Allocation 按组分配内存,每次先分配一个Slab,相当于一个大小为1M的页&…...
文件上传-CMS文件上传分析
黑盒思路: 上传点抓包测试 个人用户中心是否存在文件上传功能后台管理系统是否存在文件上传功能字典目录扫描探针文件(eg:upload.php)构造地址字典目录扫描探针编辑器目录构造地址(编辑器目录一般是默认的)…...
云原生日志Loki
1. Loki简介 1.1 Loki介绍 Loki是 Grafana Labs 团队最新的开源项目,是一个水平可扩展,高可用性,多租户的日志聚合系统。它的设计非常经济高效且易于操作,因为它不会为日志内容编制索引,而是为每个日志流编制一组标签…...
初阶数据结构之直接选择排序和快速排序
直接选择排序 1.在元素集合 array[i]–array[n-1] 中选择关键码最⼤(⼩)的数据元素 2.若它不是这组元素中的最后⼀个(第⼀个)元素,则将它与这组元素中的最后⼀个(第⼀个)元素 交换 3.在剩余的 array[i]–array[n-2](array[i1]–…...
Java语言程序设计——篇十三(4)
🌿🌿🌿跟随博主脚步,从这里开始→博主主页🌿🌿🌿 欢迎大家:这里是我的学习笔记、总结知识的地方,喜欢的话请三连,有问题可以私信🌳🌳&…...
低代码: 组件库测试之渲染和元素获取,触发事件,更新表单,验证事件以及异步请求
组件库测试步骤 渲染组件(怎样将一个组件渲染到测试用例里面) mount 和 shallowMount传递属性元素是否成功的显示 查找元素的不同写法get, getAllfind, findAllfindComponent 和 getComponent触发事件(是click也好,是input也好,让它触发对应的事件) trigger 方法观察测试界面…...
银河麒麟服务器操作系统Kylin-Server-V10-SP3-2403-Release-20240426-x86_64安装步骤
银河麒麟服务器操作系统 Kylin-Server-V10-SP3-2403-Release-20240426-x86_64安装步骤 一、准备工作1. 下载ISO镜像2. 制作安装介质3. 设置BIOS 二、安装过程1. 启动系统2. 选择安装语言3. 选择安装配置4. 配置root密码与创建用户5. 开始安装6. 重启系统7. 同意许可协议 三、系…...
2024年电赛H题全开源
当题目出来的的那一刻,看到了M0芯片,我们实验室只有一块板子,并且我没有接触过M0,电赛只准备了TI的MSP430f5529。但是我并没有放弃,决然的选择了H题。基本上将四问全做出来,可是测试由于使用了感为科技的寻…...
Docker:宿主机可以ping通外网,docker容器内无法ping通外网之解决方法
问题描述 1、宿主机可以ping外网,docker容器内无法ping外网 ping www.baidu.com 提示:unknown host baidu.com 2、宿主机可以wget下载,docker容器内无法wget下载 wget www.baidu.com 提示:unknown host baidu.com 解决方法 1、…...
bootchart抓Android系统启动各阶段性能数据
最近在做Android系统启动优化,首要任务是找到启动过程中各阶段耗时点,进而有针对性地进行优化。主要用bootchart抓开机数据,本文主要记录下工具的使用方法。 1.抓开机数据 adb root adb shell ‘touch /data/bootchart/enabled’ adb rebo…...
使用 Node.js 和 Express 框架通过网页访问GPIO和嵌入式 Linux 系统中使用 GSM/3G/4G 模块
点击上方"蓝字"关注我们 01、前言 想要快速开发嵌入式 Linux 网络应用,控制硬件 GPIO,从而使得用户能够远程控制和监控系统。 主要目的是向读者展示开发使用文件系统控制 GPIO 的 Node 代码、创建用户有好的界面、以及运行基于 Express 框架使用 AJAX 通客户端进…...
IT 行业的就业情况
当前,IT 行业的就业情况呈现出以下特点: 1. 需求持续增长:随着数字化转型的加速,各个行业对信息技术的依赖程度不断提高,推动了对 IT 人才的持续需求。特别是在云计算、大数据、人工智能、物联网等新兴领域ÿ…...
如何快速获取麒麟操作系统版本信息
如何快速获取麒麟操作系统版本信息 一、桌面版系统1. 使用 /etc/kylin-build 文件2. 使用 /etc/.kyinfo 文件 二、服务器版系统1. 使用 /etc/.productinfo 文件2. 使用 nkvers 命令3. 使用 /etc/kylin-release 文件 三、总结 💖The Begin💖点点关注&…...
git提交规范检查husky
一、Eslint 尤雨溪推荐的 prettierrc 配置,句尾不带分号 单引号。 尤雨溪推荐配置:vue-next/.prettierrc lint lint 是最著名的 C 语言工具之一,是由贝尔实验室 SteveJohnson 于 1979 在 PCC(PortableC Compiler) 基础上开发的静态代码分…...
LeetCode 919. 完全二叉树插入器
完全二叉树是每一层(除最后一层外)都是完全填充(即,节点数达到最大)的,并且所有的节点都尽可能地集中在左侧。 设计一个用完全二叉树初始化的数据结构 CBTInserter,它支持以下几种操作…...
C++密码管理器
先问一句 最近有几个关注我的原力等级为0或-1,文章全是转载,转载时间基本都在2021年,而且关注了很多人,这些是僵尸粉吗? 文末有投票,麻烦参与一下谢谢 实现功能列表 暂时还没做加密功能 打算用openssl/a…...
算法【Java】 —— 滑动窗口
滑动窗口 在上一篇文章中,我们了解到了双指针算法,在双指针算法中我们知道了前后指针法,这篇文章就要提到前后指针法的一个经典的使用 —— 滑动窗口,在前后指针法中,我们知道一个指针在前,一个指针在后&a…...
KubeSphere 容器平台高可用:环境搭建与可视化操作指南
Linux_k8s篇 欢迎来到Linux的世界,看笔记好好学多敲多打,每个人都是大神! 题目:KubeSphere 容器平台高可用:环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...
龙虎榜——20250610
上证指数放量收阴线,个股多数下跌,盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型,指数短线有调整的需求,大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的:御银股份、雄帝科技 驱动…...
设计模式和设计原则回顾
设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...
C++_核心编程_多态案例二-制作饮品
#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...
css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...
工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...
从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...
SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...
