news 2026/10/10 9:59:52

微信小程序二手物品交易系统:环境配置到项目复现全流程指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
微信小程序二手物品交易系统:环境配置到项目复现全流程指南

简介:面向毕业设计场景的微信小程序二手物品交易项目源码包,适合小程序开发者、Java后端学习者及需要快速搭建完整项目的学生。压缩包共1154个文件,包含java/class后端逻辑、wxml/wxss小程序前端页面、xml配置文件、png/jpg/gif界面素材及sql数据库脚本,整体约17MB,目录结构完整。当前已有408人学习下载,源码经过本地编译验证,配置相应环境后即可直接运行,核心功能均通过老师验收。借助这份资料,可系统梳理小程序前端与Java后端的交互流程,复用商品发布、求购信息、订单管理等模块,也能参考数据库设计与页面布局完成毕业设计或课程项目。

1. 先说结论:微信小程序二手物品交易系统,比想象中更吃环境配置

微信小程序二手物品交易系统这类毕业设计选题,打开压缩包之前很多人以为是个“解压即用”的现成项目,实际跑过一圈就会发现,真正决定成败的不是代码本身,而是环境对不对得上。这份资源难能可贵在结构完整——小程序前端、Java 后端、数据库脚本都打包在一起,发布者也确认本地编译通过、功能得到导师认可。对正在做毕业设计、需要一套能演示能答辩的完整项目的人来说,这就是最缺的东西。但对完全不熟悉 Java Web 开发的人来说,上手前必须先搞清楚模块之间怎么配合,否则连首页都刷不出来。我从复现角度把这条路完整走一遍,说清楚每一步做什么、看什么、坑在哪。

2. 从压缩包到跑通:环境选型与项目结构拆解

拿到手的第一步不是急着双击运行,而是先把依赖环境对齐。这套系统是典型的小程序前端加 Java 后端结构,前端跑在微信开发者工具里,后端跑在本机 Java 环境里,数据落在 MySQL 里。三个部分版本对不上,后面全是连锁反应。

2.1 环境清单:先对照版本再动手

我复现这类项目时一般固定用以下组合,兼容性最稳,资料也好找:

组件建议版本说明
JDK8 或 11老项目常见 JDK 8,新一点的有用 11,建议先看后端代码里有没有用新语法
MySQL5.7 或 8.0两个版本在连接驱动和认证方式上有差别,8.0 需要配cj驱动
Maven3.6 以上后端依赖管理用
微信开发者工具稳定版即可导入时注意基础库版本,别选太新的 RC 版
IDEA2020 以后版本导入 Maven 工程更省心

为什么先对着这个清单检查?因为源码包里的pom.xml和application.yml不会自己适应你的电脑。常见的翻车情况是:电脑里装的是 JDK 17,但后端代码用的是 JDK 8 编译方式,启动直接报unrecognized --release option;或者 MySQL 用了 8.0,配置文件里写的还是老驱动类名。所以拿到压缩包,我建议先把pom.xml打开扫一眼,确认<java.version>和<maven.compiler>对应的版本,再决定装哪个环境。

2.2 解压后的目录结构:先分清三层再导入

压缩包解压后,典型的三层结构长这样,你可以对照自己的包确认一下:

secondhand-trading/ ├── miniprogram/ # 微信小程序前端源码 │ ├── pages/ # 页面目录 │ │ ├── index/ # 首页,商品列表 │ │ ├── detail/ # 商品详情 │ │ ├── publish/ # 发布闲置 │ │ ├── order/ # 我的订单 │ │ └── mine/ # 个人中心 │ ├── utils/ # 请求封装与工具函数 │ ├── app.js # 小程序入口逻辑 │ └── app.json # 全局配置与页面注册 ├── src/ # Java 后端 SpringBoot 工程 │ ├── main/java/… # 控制器、服务、Mapper 等 │ ├── main/resources/ │ │ ├── application.yml # 核心配置文件 │ │ └── mapper/ # MyBatis 映射文件 │ └── pom.xml # Maven 依赖清单 └── sql/ └── secondhand.sql # 数据库初始化脚本

这段结构里最需要注意两点。第一,miniprogram目录是前端,导入的是微信开发者工具,不是 IDEA;src目录是后端,导入的是 IDEA,两者不要搞混。第二,sql目录里的脚本是整个系统的地基,没有它,后端启动时连不上表,接口全报 500。我见过有人直接把整个压缩包拖进微信开发者工具,结果报错一堆“找不到 app.json”,就是因为导错了目录层级。正确做法是先进入miniprogram那一层再导入。

2.3 数据库初始化:导 SQL 之前先改三个参数

数据库脚本一般用SOURCE命令或命令行导入。实际操作前,先确认三件事:MySQL 服务有没有启动、root 密码是什么、字符集能不能支持中文。最省事的方式是先用命令行建库并指定编码:

mysql -u root -p -e "CREATE DATABASE IF NOT EXISTS secondhand DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;" mysql -u root -p secondhand < sql/secondhand.sql

第一行命令创建数据库并声明utf8mb4字符集,这是为了防止商品描述里的表情符号、生僻字写入后变乱码;第二行把包里现成的 SQL 脚本导入。如果你用的 MySQL 是 8.0,客户端连接时可能遇到Public Key Retrieval is not allowed的报错,这时要在连接参数里加allowPublicKeyRetrieval=true。

导入完成后,用SHOW TABLES;看一眼表清单,常见的应该有用户表、商品表、订单表、收藏表、留言表这几类。如果表数量明显不对,或者导入时报“表已存在”,说明脚本执行了不止一次,直接把库删掉重新导一遍就是。数据库这一层搞定,后端启动才有物理基础,别在这步偷懒,后面启动报错十个里有八个能追溯到建库不干净。

3. Java 后端启动:SpringBoot 工程的导入与接口验证

数据库就绪后,进到后端环节。这套系统的后端是典型的 SpringBoot 加 MyBatis 组合,配置和启动顺序有讲究。我见过很多人上来就点运行,然后对着满屏红色日志发呆,其实按照下面节奏来,十分钟内能把接口拉起来。

3.1 用 IDEA 导入 Maven 工程:卡住的地方在依赖下载

打开 IDEA,选File -> Open,定位到src目录所在那一层,选中pom.xml或整个后端工程目录,IDEA 会识别为 Maven 工程并自动开始拉依赖。这里出现两种常见情况:

第一种是第一次加载需要下载大量包,进度条卡在某个百分比不动。这不是项目坏了,而是 Maven 中央仓库在国内网络下速度不稳定。这时候我会检查本地 Maven 的settings.xml,确认是否配置了国内镜像源,比如aliyun镜像。修改后重启加载,依赖下载会流畅很多。

第二种是 IDEA 提示Project SDK is not defined,说明没有给工程指定 JDK。在File -> Project Structure -> Project里把 SDK 切到本机装好的 JDK 版本,同时确认pom.xml里的java.version和它一致。两个版本不一致,编译阶段就会挂,IDE 里全是飘红的 import。依赖下载完成后,先不要急着启动,先做一次mvn clean compile,看能否编译通过。这一步能过滤掉大部分环境问题,编译过了再启动,心理也有底。

mvn clean compile -DskipTests

3.2 改配置文件:端口、数据库、微信密钥一个都不能错

编译通过后,重点改src/main/resources/application.yml。这个文件是后端的总开关,四个关键项必须和本地环境匹配:

server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/secondhand?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver servlet: multipart: max-file-size: 10MB max-request-size: 10MB wx: appid: wx1234567890abcdef secret: your-secret-here

第一项是server.port,默认 8080,如果本机端口被占用,改成 8081 后,前端所有请求地址也要跟着变。第二项是数据库连接串,localhost:3306/secondhand对应数据库名,serverTimezone=Asia/Shanghai处理时区问题,不写的话 MySQL 8.0 下大概率报时间乱码。第三项是文件上传大小限制,二手物品交易需要传商品图片,默认 1MB 根本不够,至少给到 10MB。第四项是微信小程序的appid和secret,这是登录功能的密钥,先用占位符跑通流程,等小程序注册好了再替换成真实的。注意secret不要提交到公开仓库,后端接口被刷是小事情,泄露密钥导致的费用问题才是真麻烦。

3.3 启动与接口自测:用 curl 验证登录和数据接口

配置改完,直接运行启动类。SpringBoot 的标志是以Spring Boot开头的横幅日志打印出来,然后看到Tomcat started on port 8080,说明后端已经起来了。这时我一般不会立刻打开小程序,而是先用 curl 测两个核心接口,确认网络链路是通的:

# 测试商品列表接口 curl -X GET "http://localhost:8080/api/product/list" # 测试微信登录接口(code 先随便填,能返回结构就算通) curl -X POST "http://localhost:8080/api/user/login" \ -H "Content-Type: application/json" \ -d '{"code": "test-code-123"}'

如果商品接口返回了 JSON 数组且里面有数据库里的商品数据,说明后端到数据库的链路没问题。登录接口哪怕返回“无效的 code”,只要响应结构是正常的 JSON,也说明接口本身工作正常——微信 code 校验失败是预期内的,因为还没有真实的小程序 appid。这一遍自测做完,后端部分就算过关,接下来切到前端。

4. 小程序前端对接:从开发者工具到真机预览

后端接口跑通,小程序前端反而是更磨人的一环。微信开发者工具的导入逻辑、AppID 的三种选择、本地调试时的域名校验,每一步都能卡住人。这一章把流程盘顺。

4.1 导入项目与 AppID 设置:测试号、正式号、企业号的取舍

打开微信开发者工具,选择“导入项目”,目录指向miniprogram所在那一层,而不是压缩包解压后的最外层。AppID 这里有三种选择:

如果你只是本地学习和演示,直接选“测试号”最快,不需要注册小程序账号也能跑起来,但测试号有功能限制,比如支付、部分 API 不可用。如果你已经注册了个人主体的小程序,用个人 AppID 能体验完整功能,但个人主体同样没有微信支付权限。如果你做的是课程设计或学校演示,能用企业号或者测试号就先用测试号,省去审核和资质验证的麻烦。

AppID 决定之后,appid要和后端application.yml里的wx.appid保持一致。这里有个隐藏坑:很多人前端用测试号、后端填的是正式 appid,结果登录接口永远报invalid code。因为小程序前端拿到的code是基于当前 AppID 生成的,后端拿这个 code 去微信接口换 openid,AppID 对不上,微信服务器直接拒绝。

// app.js 中初始化全局配置时的简写 App({ onLaunch() { // 开发阶段可以全局打印启动参数,方便排查 console.log('app launched') } })

4.2 把 request 地址从 localhost 切到局域网 IP

这是小程序开发里最容易忽略的一点:在开发者工具里,localhost能访问,但真机预览时,手机上访问的是开发者工具所在电脑的localhost,指向的是手机自己,所以必须换成电脑的局域网 IP。

// utils/request.js // 开发环境用电脑局域网 IP,发布时换成已备案的 HTTPS 域名 const BASE_URL = 'http://192.168.1.108:8080' module.exports = function request(path, method = 'GET', data = {}) { return new Promise((resolve, reject) => { wx.request({ url: BASE_URL + path, method, data, header: { 'Content-Type': 'application/json', 'Authorization': wx.getStorageSync('token') || '' }, success: res => resolve(res.data), fail: err => reject(err) }) }) }

这段代码里,BASE_URL是全局唯一需要改的地址。header中的Authorization字段很关键,后端会校验这个 token,没有或失效就返回 401。排查问题时,先看这个字段有没有带上,比抓后端日志更快。

需要注意的是,开发者工具默认开启“校验合法域名”选项,调试阶段可以在工具栏点“详情 -> 本地设置”,勾选“不校验合法域名”。但这个选项只对工具内预览生效,真机调试时也会绕过,唯独发布上线时必须要合法域名加 HTTPS,否则正式版请求直接被拦。

4.3 wx.login 登录链路与 token 存储

用户的登录流程,是这套系统里前端与后端配合最紧密的一环。整体逻辑是:小程序调wx.login拿临时code,传给后端,后端拿code找微信服务器换openid,生成自己的 token 返回给前端,前端把 token 存起来,之后每次请求都带上。

// pages/login/login.js const request = require('../../utils/request') Page({ async handleLogin() { // 1. 获取微信临时登录凭证 const { code, errMsg } = await wx.login() if (!code) { wx.showToast({ title: '登录凭证获取失败', icon: 'none' }) return } // 2. 发送到后端登录接口 const res = await request('/api/user/login', 'POST', { code }) if (res.code === 0) { // 3. 保存 token 和用户信息到本地 wx.setStorageSync('token', res.data.token) wx.setStorageSync('userInfo', res.data.userInfo) wx.switchTab({ url: '/pages/index/index' }) } else { wx.showToast({ title: res.msg || '登录失败', icon: 'none' }) } } })

这里三个步骤对应三个容易踩的点。第一步wx.login()返回的code有效期只有五分钟,后端必须及时拿它换openid,如果前后端时间差太大,或者后端处理后长时间才发起微信请求,code 就失效了。第三步的 token 存储类型是同步接口,用wx.setStorageSync没问题,但要注意 token 过期后,首页还在用旧的用户信息展示,需要统一处理 401 跳登录页。常见做法是在request.js里拦截响应,状态码是 401 就清理本地存储并跳转到登录页。

登录链路走通后,整个项目在本地环境就形成了闭环:前端发起请求、后端接住、数据库读写、返回结果渲染。到这里已经能演示核心功能了,但演示前的稳定性,还得看下一章的坑排除得干不干净。

5. 避坑手册:六个高频翻车点与排查方法

任何项目在别人电脑上能跑,不等于在你电脑上能跑。这一章专门记录我在复现这类毕业设计源码时遇到频率最高的六个问题,每一条都是实打实踩过的,按“现象 -> 原因 -> 解决”的顺序说透。

5.1 数据库连接失败:时区、密码、MySQL 8.0 认证插件

现象:后端启动时控制台报Access denied for user 'root'@'localhost'或The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized。

原因分两种。第一种是密码不对或用户权限不够,配置文件里的username和password与本地 MySQL 实际不一致。第二种是 MySQL 8.0 默认时区不是 UTC 也不是中国时区,连接串里没带serverTimezone=Asia/Shanghai就会报时区错误。另外 MySQL 8.0 换了认证插件为caching_sha2_password,老驱动不支持,需要换成com.mysql.cj.jdbc.Driver。

解决:先确认密码无误,再检查连接串。我一般会先用命令行工具mysql -u root -p登录验证密码,再用 Navicat 之类工具测试连接串里的主机、端口、用户、密码四项。如果驱动报错,就去pom.xml里把mysql-connector-java版本升到 8.0.x。这个坑的排查思路是“从下往上逐层验证”,不要上来就怀疑代码。

5.2 小程序 request 请求直接失败:域名校验与明文 HTTP

现象:开发者工具里点击按钮发请求,控制台报fail url not in domain list,或者真机上完全没反应。

原因:微信小程序的安全策略要求所有请求域名必须是 HTTPS 且在后台配置过白名单,而本地调试走的是http://192.168.x.x:8080,既不是 HTTPS,也没有配置域名。

解决:开发者工具右上角“详情”按钮,进入“本地设置”,勾选“不校验合法域名、web-view(业务域名)、TLS 版本以及 HTTPS 证书”。这是本地调试的合法捷径。但如果要在真机上稳定预览,需要把手机和电脑连到同一个 WiFi,并把BASE_URL改成电脑的局域网 IP,同时开启工具里的“真机调试”模式。真机调试可以绕过域名校验,比预览更稳。

5.3 图片上传成功却显示不出来:静态资源映射缺失

现象:发布商品后,图片上传接口返回了路径,但前端<image>标签渲染时是裂图。

原因:后端把图片保存到了本地磁盘,但没有把磁盘目录映射成可访问的 URL 路径。SpringBoot 默认只处理classpath下的静态资源,你存到D:/upload/的图片,用户请求http://localhost:8080/upload/xxx.jpg时,后端没有对应的路由,自然 404。

解决:加一个静态资源映射配置,把本地上传目录暴露出去。

@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { // 把 /upload/** 请求映射到磁盘上的 upload 目录 String uploadPath = System.getProperty("user.dir") + "/upload/"; registry.addResourceHandler("/upload/**") .addResourceLocations("file:" + uploadPath); } }

这段配置里,addResourceHandler定义的是前端访问的 URL 前缀,addResourceLocations定义的是磁盘实际路径,两者要一一对应。配置完后,前端图片地址必须是http://localhost:8080/upload/xxx.jpg这种完整形式,不能只存“/upload/xxx.jpg”然后再自己拼域名,否则换环境调试时全乱。

5.4 用户登录态反复失效:token 过期与 session_key 不匹配

现象:用着用着,操作某个功能突然跳回登录页,或者后端接口报token invalid。

原因:后端生成的 token 设置了过期时间,前端却一直沿用旧 token;另外有些项目把session_key也当 token 用,但session_key会随着用户在小程序里重新调用wx.login而变化,一旦变化,后端那边的 session 就失配了。

解决:确认后端 token 的过期策略,是 30 分钟还是 24 小时,前端在request.js里统一拦截 401 状态并跳转登录页。不要把session_key直接暴露给前端,正确做法是后端拿code换openid和session_key之后,自己生成一个业务 token 返回。如果觉得频繁登录烦,可以把 token 有效期设到 7 天,毕业设计演示完全够用。

5.5 页面白屏或接口 404:基础库版本与路由路径不匹配

现象:小程序打开后一片空白,或者点击商品进入详情页时提示page not found。

原因:两个可能。第一个是开发者工具的基础库版本太新,新版本移除了一些旧 API 的支持;第二个是页面路径在app.json里没注册,或者wx.navigateTo跳转时把路径写错了。

解决:先看 console 里的报错信息。如果是thirdScriptError,多半是基础库问题,在“详情 -> 本地设置”里把调试基础库切回旧一点的稳定版本。如果是page not found,打开app.json检查pages数组里的路径是否与目录结构一致,尤其注意大小写。小程序的路由是大小写敏感的,Pages/index和pages/index是两个路径。

5.6 端口被占用导致后端起不来

现象:启动后端时,控制台报Port 8080 was already in use。

原因:之前启动的后端进程没有完全关闭,或者电脑上其他程序占用了 8080 端口。

解决:用命令行查是谁占了端口。

# 查看 8080 端口对应的进程 PID(Windows 与 mac/Linux 命令略有差异) netstat -ano | findstr 8080 taskkill /PID 进程号 /F

Linux 或 mac 上可以用lsof -i :8080查。杀完进程后重启后端即可。如果这个端口经常被占,直接把application.yml里的端口改成 8081,同时记住前端BASE_URL也要同步改。这里最忌讳的是只改后端不改前端,接口请求全部失败,还以为是后端没起来。

6. 把模板变成自己的:二次开发与验收清单

源码跑通只是及格线,答辩和评审时,能说出“我改了哪里、为什么改”,比“项目能跑”值钱得多。这一章给三个低成本又容易讲清楚的改造方向,按工作量从小到大排。

6.1 加一个商品搜索:后端 SQL 加前端输入框

大多数二手交易模板的首页只有列表,没有搜索功能。给它加一个按标题模糊搜索的能力,改动量很小,但属于完整功能闭环。

// ProductController.java @GetMapping("/api/product/search") public Result search(@RequestParam String keyword) { // keyword 为空时返回全部在售商品 if (keyword == null || keyword.trim().isEmpty()) { return Result.ok(productService.listOnSale()); } return Result.ok(productService.searchByKeyword(keyword.trim())); }

配合的 SQL 在 Mapper 里:

<!-- ProductMapper.xml --> <select id="searchByKeyword" resultType="Product"> SELECT * FROM product WHERE status = 1 AND (title LIKE CONCAT('%', #{keyword}, '%') OR description LIKE CONCAT('%', #{keyword}, '%')) ORDER BY create_time DESC </select>

这段实现里,status = 1是“在售”状态的过滤条件,防止搜到下架商品;LIKE CONCAT是模糊匹配,注意不要自己拼字符串去 SQL,容易出注入问题。前端只需要在首页顶部加一个input框,把输入值作为keyword参数请求这个接口,逻辑很直白。答辩时你可以先说“搜索我用的是模糊查询 + 在售状态过滤”,比讲框架概念实在。

6.2 答辩演示前的检查清单:一键跑通的路径

演示前最后一晚,我一般会完整走一遍这条路径,顺序不对就会翻车。先启动 MySQL,确认SHOW TABLES能看到业务表;再启动后端,看到Tomcat started on port 8080;再打开微信开发者工具,确认不校验域名选项开启;然后用真实手机做一次完整的“登录 -> 浏览商品 -> 发布商品 -> 对商品下单”流程。每一步之间隔十秒再操作,给前端请求留时间,别点太快把接口刷崩了。

从那以后,我每次复现这类毕业设计源码,都强制先走一遍完整验收清单再改代码,因为这个流程能在五分钟内暴露百分之九十的环境问题,比对着报错日志猜快得多。环境稳了,才有精力做真正的功能修改。希望这篇拆解能帮你少花几个晚上在处理环境问题上,把时间留给能写进论文和答辩里的那部分。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/10 9:59:44

让VSCode像Dev-C++一样弹窗运行C程序:配置详解

1. 先说清楚&#xff1a;为什么会有这个需求&#xff0c;以及它到底在解决什么写 C 程序的老伙计们&#xff0c;应该都有一段 Dev-C 的青春记忆。大学上机课、计算机二级备考、被指针和结构体折磨的夜晚&#xff0c;那个老旧的界面和“运行”按钮一点就弹出来的黑色控制台窗口&…

作者头像 李华
网站建设 2026/10/10 9:58:43

模块化磁盘存储管理客户端:LVM四层抽象与在线扩容实战指南

简介&#xff1a;这份资源面向戴尔存储系统的IT管理员与运维工程师&#xff0c;提供Modular Disk Storage Manager Client&#xff08;MDSM&#xff09;客户端的官方下载入口。MDSM用于监控、配置和优化Dell磁盘存储资源&#xff0c;支持存储设备发现与映射、存储池与卷管理、快…

作者头像 李华
网站建设 2026/10/10 9:58:16

2024年Windows XP x64还能跑哪些应用?五类关键场景与兼容性实战

1. 为什么还有人折腾 Windows XP x64先把话说在前头&#xff1a;这篇文章不是劝你拿 XP 当主力机&#xff0c;而是给那些手里还压着老设备、老工控机、老授权软件的人一条能走通的路。Windows XP x64 这个系统本身就挺特殊&#xff0c;它是基于 Windows Server 2003 内核做的 6…

作者头像 李华
网站建设 2026/10/10 9:58:11

基于SpringBoot的大学生健康管理平台设计:从数据库到答辩全流程

看到这个标题点进来的朋友&#xff0c;多半已经在毕设选题的边缘反复横跳了。每年这个时间点&#xff0c;总有学弟学妹问我同一个问题&#xff1a;“学长&#xff0c;做什么题目比较好过&#xff1f;代码自己写得出来吗&#xff1f;答辩要怎么讲才不翻车&#xff1f;”我统一的…

作者头像 李华
网站建设 2026/10/10 9:57:48

Flink批处理 vs Spark:六大短板与选型建议

最近我在好几个技术社群里连续被问到同一个问题&#xff1a;团队想推流批一体&#xff0c;准备把批处理也迁到 Flink 上&#xff0c;到底值不值&#xff1f;说 Flink 流处理强&#xff0c;大家基本没意见&#xff0c;但一聊到批处理&#xff0c;争论就多起来了。真去翻社区的吐…

作者头像 李华
网站建设 2026/10/10 9:57:00

API调用全攻略:从概念、原理到实战调试的完整指南

API这个词&#xff0c;干这行的人天天挂在嘴边&#xff0c;但真被问到"它到底是什么、怎么用"时&#xff0c;不少工作了两三年的开发者也会愣一下。我在带新人和做技术分享时有个很深的体会&#xff1a;很多人不是没听过API&#xff0c;而是从来没有"从一个使用…

作者头像 李华