SpringBoot+微信小程序充电桩管理系统开发实战

SpringBoot+微信小程序充电桩管理系统开发实战 随着新能源汽车的快速普及充电桩管理系统的需求日益增长。很多开发者在实际项目中需要构建一个完整的充电桩管理系统但往往面临技术栈选择、架构设计和功能实现的挑战。本文将基于SpringBoot后端框架和微信小程序前端详细讲解如何从零搭建一个功能完善的充电桩管理系统涵盖用户管理、订单处理、充电桩监控等核心功能。1. 系统架构设计与技术选型1.1 系统整体架构充电桩管理系统采用典型的前后端分离架构。后端基于SpringBoot框架提供RESTful API接口前端使用微信小程序作为用户交互界面数据库采用MySQL存储业务数据Redis用于缓存和会话管理。系统架构分为四层表现层微信小程序界面负责用户交互和数据展示应用层SpringBoot业务逻辑处理包括用户服务、订单服务、充电桩服务等数据层MySQL数据持久化存储Redis缓存加速设备层充电桩硬件设备接入和状态监控1.2 技术栈说明后端技术栈SpringBoot 2.7.x快速开发框架Spring Security安全认证和权限控制MyBatis-Plus数据持久层框架MySQL 8.0关系型数据库Redis 6.x缓存和会话存储Maven项目构建管理前端技术栈微信小程序原生框架WeUI组件库界面样式统一wx.request网络请求封装微信支付SDK支付功能集成2. 开发环境准备2.1 基础环境配置开发前需要安装以下软件环境Java开发环境# 检查Java版本 java -version # 应该显示openjdk version 11.0.15 # 检查Maven版本 mvn -version # 应该显示Apache Maven 3.8.6数据库环境配置-- 创建数据库 CREATE DATABASE charging_pile DEFAULT CHARACTER SET utf8mb4; -- 创建用户并授权 CREATE USER charging_user% IDENTIFIED BY your_password; GRANT ALL PRIVILEGES ON charging_pile.* TO charging_user%; FLUSH PRIVILEGES;2.2 项目结构规划创建标准的Maven多模块项目结构charging-system/ ├── charging-common/ # 公共模块 ├── charging-dao/ # 数据访问层 ├── charging-service/ # 业务逻辑层 ├── charging-controller/ # 控制层 ├── charging-wechat/ # 微信小程序相关 └── pom.xml # 父POM配置3. 数据库设计与建模3.1 核心表结构设计充电桩管理系统需要设计以下核心数据表用户表userCREATE TABLE user ( id bigint(20) NOT NULL AUTO_INCREMENT, openid varchar(100) NOT NULL COMMENT 微信openid, nickname varchar(100) DEFAULT NULL COMMENT 用户昵称, phone varchar(20) DEFAULT NULL COMMENT 手机号, balance decimal(10,2) DEFAULT 0.00 COMMENT 账户余额, vip_level int(11) DEFAULT 0 COMMENT 会员等级, create_time datetime DEFAULT CURRENT_TIMESTAMP, update_time datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_openid (openid), KEY idx_phone (phone) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT用户表;充电桩表charging_pileCREATE TABLE charging_pile ( id bigint(20) NOT NULL AUTO_INCREMENT, pile_code varchar(50) NOT NULL COMMENT 充电桩编号, location varchar(200) DEFAULT NULL COMMENT 安装位置, type int(11) DEFAULT 1 COMMENT 充电桩类型1-快充2-慢充, status int(11) DEFAULT 0 COMMENT 状态0-空闲1-使用中2-故障, power decimal(5,2) DEFAULT NULL COMMENT 功率(kW), price decimal(5,2) DEFAULT NULL COMMENT 单价(元/度), create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_pile_code (pile_code), KEY idx_location (location(50)) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT充电桩表;3.2 业务关联表设计订单表charging_orderCREATE TABLE charging_order ( id bigint(20) NOT NULL AUTO_INCREMENT, order_no varchar(50) NOT NULL COMMENT 订单编号, user_id bigint(20) NOT NULL COMMENT 用户ID, pile_id bigint(20) NOT NULL COMMENT 充电桩ID, start_time datetime DEFAULT NULL COMMENT 开始时间, end_time datetime DEFAULT NULL COMMENT 结束时间, total_amount decimal(10,2) DEFAULT 0.00 COMMENT 总金额, status int(11) DEFAULT 0 COMMENT 状态0-进行中1-已完成2-已取消, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_order_no (order_no), KEY idx_user_id (user_id), KEY idx_pile_id (pile_id), KEY idx_create_time (create_time) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT充电订单表;4. SpringBoot后端核心实现4.1 项目依赖配置pom.xml关键依赖dependencies !-- SpringBoot基础依赖 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency !-- 数据库相关 -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.33/version /dependency dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3.1/version /dependency !-- Redis缓存 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-redis/artifactId /dependency !-- 微信小程序SDK -- dependency groupIdcom.github.binarywang/groupId artifactIdweixin-java-miniapp/artifactId version4.4.0/version /dependency /dependencies4.2 数据层实现实体类定义// 充电桩实体类 Data TableName(charging_pile) public class ChargingPile { TableId(type IdType.AUTO) private Long id; private String pileCode; private String location; private Integer type; private Integer status; private BigDecimal power; private BigDecimal price; private LocalDateTime createTime; } // Mapper接口 public interface ChargingPileMapper extends BaseMapperChargingPile { // 根据位置查询可用充电桩 Select(SELECT * FROM charging_pile WHERE location LIKE CONCAT(%,#{location},%) AND status 0) ListChargingPile selectAvailableByLocation(Param(location) String location); }4.3 业务逻辑层充电桩服务实现Service public class ChargingPileServiceImpl extends ServiceImplChargingPileMapper, ChargingPile implements ChargingPileService { Autowired private RedisTemplateString, Object redisTemplate; private static final String PILE_STATUS_KEY charging:pile:status:; Override public ListChargingPile getAvailablePiles(String location) { // 先查缓存 String cacheKey PILE_STATUS_KEY location; ListChargingPile cachedPiles (ListChargingPile) redisTemplate.opsForValue().get(cacheKey); if (cachedPiles ! null) { return cachedPiles; } // 缓存不存在查询数据库 ListChargingPile piles this.baseMapper.selectAvailableByLocation(location); // 写入缓存有效期5分钟 redisTemplate.opsForValue().set(cacheKey, piles, Duration.ofMinutes(5)); return piles; } Override public boolean startCharging(Long pileId, Long userId) { ChargingPile pile this.getById(pileId); if (pile null || pile.getStatus() ! 0) { throw new BusinessException(充电桩不可用); } // 更新充电桩状态 pile.setStatus(1); this.updateById(pile); // 清除相关缓存 redisTemplate.delete(PILE_STATUS_KEY pile.getLocation()); return true; } }4.4 控制器层充电桩API接口RestController RequestMapping(/api/charging) Api(tags 充电桩管理接口) public class ChargingController { Autowired private ChargingPileService chargingPileService; Autowired private OrderService orderService; GetMapping(/piles) ApiOperation(获取可用充电桩列表) public ResultListChargingPile getAvailablePiles( RequestParam String location) { try { ListChargingPile piles chargingPileService.getAvailablePiles(location); return Result.success(piles); } catch (Exception e) { return Result.error(查询失败 e.getMessage()); } } PostMapping(/start) ApiOperation(开始充电) public ResultString startCharging( RequestBody StartChargingRequest request) { try { boolean success chargingPileService.startCharging( request.getPileId(), request.getUserId()); if (success) { // 创建订单 orderService.createOrder(request.getUserId(), request.getPileId()); return Result.success(充电开始); } return Result.error(启动失败); } catch (BusinessException e) { return Result.error(e.getMessage()); } } }5. 微信小程序前端开发5.1 小程序项目结构miniprogram/ ├── pages/ │ ├── index/ # 首页 │ ├── map/ # 地图页面 │ ├── order/ # 订单页面 │ └── profile/ # 个人中心 ├── components/ # 公共组件 ├── utils/ # 工具类 ├── app.js # 小程序入口 ├── app.json # 全局配置 └── app.wxss # 全局样式5.2 首页实现index.wxmlview classcontainer view classsearch-bar input classsearch-input placeholder输入地址搜索充电桩 bindinputonSearchInput value{{searchText}}/ button classsearch-btn bindtaponSearch搜索/button /view view classlocation-info text classlocation-text当前位置{{currentLocation}}/text /view view classpile-list view classpile-item wx:for{{pileList}} wx:keyid bindtaponPileTap>Page({ data: { searchText: , currentLocation: 北京市海淀区, pileList: [] }, onLoad() { this.loadPileList(); }, onSearchInput(e) { this.setData({ searchText: e.detail.value }); }, onSearch() { this.loadPileList(this.data.searchText); }, loadPileList(location ) { const that this; wx.request({ url: https://your-domain.com/api/charging/piles, data: { location: location || that.data.currentLocation }, success(res) { if (res.data.code 200) { that.setData({ pileList: res.data.data }); } } }); }, onPileTap(e) { const pile e.currentTarget.dataset.pile; if (pile.status 0) { wx.navigateTo({ url: /pages/charging/charging?pileId${pile.id} }); } else { wx.showToast({ title: 该充电桩正在使用中, icon: none }); } } });5.3 充电页面实现charging.wxmlview classcharging-container view classpile-info-card text classpile-code{{pileInfo.pileCode}}/text text classpile-location{{pileInfo.location}}/text view classcharging-stats text当前电量{{currentPower}}%/text text已充电{{chargedTime}}分钟/text text消费金额{{consumedAmount}}元/text /view /view view classcontrol-panel button classbtn-start wx:if{{!isCharging}} bindtapstartCharging开始充电/button button classbtn-stop wx:else bindtapstopCharging结束充电/button /view /view6. 系统集成与接口联调6.1 微信登录集成后端登录接口RestController RequestMapping(/api/auth) public class AuthController { Autowired private UserService userService; PostMapping(/wxlogin) public ResultLoginResponse wechatLogin(RequestBody LoginRequest request) { // 调用微信接口获取openid String openid wechatService.getOpenid(request.getCode()); // 查询或创建用户 User user userService.getOrCreateUser(openid, request.getUserInfo()); // 生成token String token jwtUtil.generateToken(user.getId()); LoginResponse response new LoginResponse(); response.setToken(token); response.setUser(user); return Result.success(response); } }6.2 支付功能实现微信支付集成Service public class WechatPayService { public MapString, String createPayment(Order order, String openid) { try { WxPayUnifiedOrderRequest request new WxPayUnifiedOrderRequest(); request.setBody(充电费用支付); request.setOutTradeNo(order.getOrderNo()); request.setTotalFee(order.getTotalAmount().multiply(new BigDecimal(100)).intValue()); request.setOpenid(openid); request.setTradeType(JSAPI); WxPayUnifiedOrderResult result wxPayService.unifiedOrder(request); // 构造前端支付参数 MapString, String payParams new HashMap(); payParams.put(timeStamp, String.valueOf(System.currentTimeMillis() / 1000)); payParams.put(nonceStr, result.getNonceStr()); payParams.put(package, prepay_id result.getPrepayId()); payParams.put(signType, MD5); return payParams; } catch (Exception e) { throw new BusinessException(支付创建失败); } } }7. 系统部署与运维7.1 生产环境配置application-prod.ymlserver: port: 8080 servlet: context-path: /charging-api spring: datasource: url: jdbc:mysql://mysql-prod:3306/charging_pile?useUnicodetruecharacterEncodingutf8 username: charging_prod password: ${DB_PASSWORD} redis: host: redis-prod port: 6379 password: ${REDIS_PASSWORD} profiles: active: prod logging: level: com.charging: INFO file: name: /logs/charging-system.log7.2 Docker部署配置DockerfileFROM openjdk:11-jre-slim VOLUME /tmp COPY target/charging-system-1.0.0.jar app.jar ENTRYPOINT [java,-Djava.security.egdfile:/dev/./urandom,-jar,/app.jar]docker-compose.ymlversion: 3.8 services: charging-app: build: . ports: - 8080:8080 environment: - SPRING_PROFILES_ACTIVEprod - DB_PASSWORDyour_db_password depends_on: - mysql - redis mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: root_password MYSQL_DATABASE: charging_pile volumes: - mysql_data:/var/lib/mysql redis: image: redis:6.2-alpine command: redis-server --requirepass your_redis_password volumes: mysql_data:8. 常见问题与解决方案8.1 开发阶段常见问题问题1微信登录失败现象调用wx.login获取code后后端验证失败原因AppID和AppSecret配置错误或网络问题解决检查微信开发者平台配置确保前后端AppID一致问题2数据库连接超时现象应用启动时报数据库连接异常原因数据库地址配置错误或网络不通解决检查数据库连接字符串确认网络连通性8.2 生产环境问题排查问题1充电桩状态不同步现象小程序显示充电桩空闲实际已被占用原因缓存未及时更新或分布式锁问题解决优化缓存更新策略添加分布式锁机制问题2支付回调失败现象用户已支付但订单状态未更新原因网络超时或回调接口异常解决添加重试机制完善日志监控9. 性能优化与安全加固9.1 数据库优化策略索引优化-- 为常用查询字段添加索引 ALTER TABLE charging_order ADD INDEX idx_user_status (user_id, status); ALTER TABLE charging_pile ADD INDEX idx_location_status (location, status); -- 定期分析表状态 ANALYZE TABLE charging_order;查询优化// 使用分页查询避免全表扫描 PageChargingPile page new Page(pageNum, pageSize); LambdaQueryWrapperChargingPile queryWrapper new LambdaQueryWrapper(); queryWrapper.eq(ChargingPile::getStatus, 0) .like(StringUtils.isNotBlank(location), ChargingPile::getLocation, location); PageChargingPile result chargingPileService.page(page, queryWrapper);9.2 安全防护措施接口安全Configuration EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests() .antMatchers(/api/auth/**).permitAll() .antMatchers(/api/**).authenticated() .and() .addFilter(new JwtAuthenticationFilter(authenticationManager())); } }数据加密Component public class DataEncryptor { public String encryptSensitiveData(String data) { try { Cipher cipher Cipher.getInstance(AES/GCM/NoPadding); // 加密实现... return encryptedData; } catch (Exception e) { throw new BusinessException(数据加密失败); } } }充电桩管理系统的开发涉及多个技术环节从后端API设计到前端交互实现都需要充分考虑用户体验和系统稳定性。本文提供的完整解决方案可以帮助开发者快速构建属于自己的充电桩管理系统在实际项目中根据具体需求进行调整和优化。