同城拼车要点_01
发布时间:2026/9/7 19:14:19 作者:尧图编辑部 阅读量:1,286

目录1解释Openresty作用2启动3可能遇到的问题:4开发用户模块51前端是怎么通过openrstry启动并运行的6parameterTypecom.heima.modules.po.AccountPO7 ?1. 核心作用2. 配套结构说明第一步先定义通用字段片段一般写在当前 mapper 文件顶部第二步在 select 中引用8ResponseBody1. 核心作用2. 不加该注解的后果3. 加了之后流程9如何实现延时自动取消功能10有些面试官问你怎么检测出来时间从 2s 优化到 300ms 的1. 代码埋点打印耗时2. Postman / Apifox 工具测试二、测试环境压力测试模拟真实并发量化指标四、面试加分总结话术直接背11介绍你的项目以及遇到的问题与解决方案?12怎么结合RDB和AOF一起实现Redis持久化1314skyWalking怎么在项目中部署以及使用编辑15你们项目中有没有做过限流怎么做的16为什么分布式锁一定要先于事务执行1解释Openresty作用一、基础定位OpenResty Nginx Lua 脚本扩展是前置接入层网关所有用户请求最先到达它承担动静分离、流量入口、反向代理能力在整个架构最外层。二、两大核心职责对应图里两条分支1. 直接承载静态资源访问动静分离核心用户访问页面 HTML、CSS、JS、图片、视频等静态 Web 资源时 OpenResty 直接读取本地 Web 静态文件返回给用户不经过后端 Java 微服务。 好处静态资源由高性能 Nginx 处理速度远快于 Java 服务减轻后端 7 个微服务的流量压力可以搭配 CDN、本地缓存大幅提升页面加载速度。2. 动态 API 请求转发到 Gateway 网关页面里的动态接口登录、下单、支付、库存查询等需要后端业务逻辑的请求OpenResty 通过 Lua 规则判断 URL反向代理转发到后端gateway微服务所有动态请求统一流入 Spring Cloud GatewayGateway 再根据路由分发到 account/order/storage/payment 等 6 个业务微服务业务微服务完成数据库、消息队列等操作后逐层把结果原路返回给用户。2启动然后就可以访问:http://localhost/web3可能遇到的问题:4开发用户模块3、开发用户模块⭐⭐用户模块已完成注册、登录功能本次迭代需要完成用户个人中心-密码修改功能。3.1任务目标1.完成用户模块相关代码2.完成修改密码功能的测试任务周期1 Day3.2执行与验收3.2.1完成用户模块相关代码开发以下代码完成用户的密码修改功能注意方法内部的每行注释。【提交代码完成的截图】3.2.2完成修改密码功能的测试通过前台页面先注册一个账户登录后在个人中心里找到修改密码完成对上述代码的测试。【提交测试通过的截图】51前端是怎么通过openrstry启动并运行的6parameterTypecom.heima.modules.po.AccountPO包名.类名另外SQL中: if中必须使用test进行判断7include refidBase_Column_List/?1. 核心作用MyBatis 的 SQL 片段复用标签作用是把提前定义好的通用字段列表直接引入到当前 select 语句中代替手写一长串字段。2. 配套结构说明第一步先定义通用字段片段一般写在当前 mapper 文件顶部xmlsql idBase_Column_List id, username, phone, password, create_time, update_time, status /sqlidBase_Column_List片段唯一标识就是后面refid引用的值里面写表t_account所有需要查询的常规字段替代select *。第二步在 select 中引用xmlselect idcheckLogin parameterTypeAccountPO resultMapBaseResultMap select include refidBase_Column_List/ from t_account where ... /where /selectMyBatis 解析时会自动把include替换成上面定义的字段字符串最终执行 SQL 等价于sqlselect id, username, phone, password, create_time, update_time, status from t_account ...8ResponseBody1. 核心作用标注在Controller 方法 / 类上作用 将方法返回的 Java 对象PO/VO/Map/List自动转为 JSON 字符串直接写入 HTTP 响应体返回给前端不再走页面跳转视图。2. 不加该注解的后果Spring MVC 默认逻辑返回值会被当成视图名称去寻找页面模板如 jsp/html会报 404。java运行// 无 ResponseBody RequestMapping(/login) public AccountVO login() { return vo; } // Spring 会尝试找名叫 AccountVO 的页面直接4043. 加了之后流程方法执行完毕得到返回对象Spring 使用内置 Jackson 序列化工具把对象转 JSON设置响应头Content-Type: application/jsonJSON 文本直接返回浏览器 / 前端 Axios。9如何实现延时自动取消功能10有些面试官问你怎么检测出来时间从 2s 优化到 300ms 的1. 代码埋点打印耗时在订单创建接口的入口、出口记录时间戳计算差值。RequestMapping(/createOrder) public Result createOrder(OrderDTO dto) { long start System.currentTimeMillis(); try { // 订单创建核心逻辑 return orderService.create(dto); } finally { // 打印接口总耗时 long cost System.currentTimeMillis() - start; log.info(订单创建接口总耗时{}ms, cost); } }优化前同步调用地图 API日志打印稳定 1800~2200ms平均 2s改成异步剥离地图调用后日志稳定 200~300ms直接看到下降。2. Postman / Apifox 工具测试发送创建订单请求工具自带请求耗时面板同一参数重复发 10 次取平均值优化前平均 2000ms异步改造后平均 300ms。二、测试环境压力测试模拟真实并发量化指标使用 JMeter / Gatling / Apifox 压测模拟多个用户同时下单统计平均响应时间。构造测试脚本循环调用创建订单接口设置并发数比如 50、100 并发用户持续压测 5 分钟查看压测报告指标Average(平均响应时间)同步版本平均响应 2000ms异步版本平均响应 300ms。 额外优势压测同时能发现同步模式下大量并发会出现请求超时异步改造后超时率直接归零对应模块里解决的 “订单创建超时” 问题。四、面试加分总结话术直接背本地开发时通过代码埋点日志 Apifox初步测出同步模式下单接口平均 2 秒然后用 JMeter 做并发压测模拟多用户下单确认高并发下平均响应稳定 2s还伴随大量超时完成异步改造后同样压测脚本复测平均响应降到 300ms上线后依靠 SkyWalking 链路追踪、Grafana 监控大盘观测真实用户流量线上平均耗时稳定 300ms 以内同时超时问题完全解决验证优化生效。11介绍你的项目以及遇到的问题与解决方案?### 项目介绍我参与的项目是 O2O同城顺风车平台 基于Spring Cloud微服务架构Spring Cloud Alibaba技术栈。项目包含7个核心微服务覆盖用户、行程、订单、支付、消息、存储等完整业务链路。我主要负责的模块包括 1. 用户中心 — 密码修改功能2. 车辆认证 — 百度AI图片识别车牌行驶证3. 行程中心 — 地图路径计算、装饰者模式计费、邀请超时自动取消4. 消息中心 — WebSocket即时通信系统### 模块一用户个人中心 - 密码修改功能实现 - 用户输入旧密码、新密码 → 验证旧密码正确性 → 校验新旧密码不能相同 → 更新数据库- 密码使用MD5加密存储遇到的问题 - 问题1 密码修改后用户Session中的信息未更新导致Token失效- 问题2 密码校验逻辑分散代码可读性差解决方案 1. Session同步更新 密码修改成功后调用 sessionTemplate.updateSessionUseralias() 同步更新Redis中的用户Session信息确保Token持续有效2. 参数校验优化 使用 StringUtils.isAnyEmpty() 进行参数非空校验使用枚举类 BusinessErrors 统一错误码管理性能提升 - 通过Redis缓存Session避免每次请求查询数据库响应时间从500ms优化到50ms以内### 模块二用户车辆信息上传与百度AI图片识别功能实现 - 用户上传车辆照片和行驶证照片 → 调用百度OCR接口识别车牌号 → 对比车辆识别结果与行驶证识别结果 → 一致则认证通过用户角色升级为车主遇到的问题 - 问题1 图片下载失败导致认证中断- 问题2 百度API调用频率限制高并发下认证失败- 问题3 图片Base64编码过大传输耗时解决方案 1. 图片下载异常处理 使用OkHttp下载图片对网络异常和HTTP错误进行捕获抛出 BusinessErrors.FAIL_IMG_DOWNLOAD 异常2. AccessToken缓存 获取的access_token缓存到Redis设置过期时间避免频繁调用获取接口3. 图片压缩优化 上传前前端对图片进行压缩后端接收后再次校验图片大小public String getLicense(VehiclePO vehiclePO) throws IOException { // 下载图片转Base64 String vehicleBase64 encodeBase64(downloadImage(vehiclePO.getCarFrontPhoto())); String licenseBase64 encodeBase64(downloadImage(vehiclePO.getCarBackPhoto())); // 获取access_token缓存处理 String accessToken getAccessToken(); // 识别车辆与行驶证 String plateFromVehicle recognizePlate(vehicleBase64, accessToken); String plateFromLicense recognizeLicensePlateFromLicenseDoc(licenseBase64, accessToken); // 对比车牌号 if (plateFromVehicle ! null plateFromVehicle.equalsIgnoreCase(plateFromLicense)) { return plateFromVehicle; } return null; }性能提升 - AccessToken缓存后减少90%的Token获取请求- 图片压缩后传输时间从3s优化到500ms以内### 模块三地图路径算法计算路径及耗时功能实现 - 用户发布行程后调用百度地图路径规划API → 获取起点到终点的距离和预估时间 → 用于订单计费和行程展示遇到的问题 - 问题1 百度API响应慢导致订单创建超时- 问题2 API调用失败后订单无法正常生成- 问题3 路径数据未缓存相同起点终点重复计算解决方案 1. 异步调用 将路径计算逻辑异步化订单创建先返回成功路径数据通过WebSocket推送2. 失败重试 使用重试机制API调用失败后重试3次每次间隔2秒3. 路径缓存 将起点终点组合作为Key路径结果缓存到Redis有效期30分钟public RoutePlanResultBO pathPlanning(String origins, String destinations) { // 优先从缓存获取 String cacheKey route: origins : destinations; RoutePlanResultBO cached redisHelper.get(cacheKey); if (cached ! null) return cached; // 调用百度API String url String.format(%s?origins%sdestinations%sak%s, api, origins, destinations, ak); Request request new Request.Builder().url(url).get().build(); try (Response response client.newCall(request).execute()) { String body response.body().string(); JSONObject route JSONObject.parseObject(body).getJSONArray(result).getJSONObject(0); RoutePlanResultBO resultBO parseRouteResult(route); // 缓存结果 redisHelper.set(cacheKey, resultBO, 30, TimeUnit.MINUTES); return resultBO; } catch (Exception e) { throw new BusinessRuntimeException(BusinessErrors.PATH_PLAN_ERROR); } }性能提升 - 缓存命中率达到60%响应时间从800ms优化到100ms以内- 异步化后订单创建接口响应时间从2s优化到300ms### 模块四装饰者模式完成计费算法功能实现 - 计费规则3公里以内起步价13元3公里以上2.3元/公里燃油附加费1元/次- 使用装饰者模式实现每个计费项独立封装遇到的问题 - 问题1 最初计费逻辑硬编码新增计费项需要修改大量代码- 问题2 计费参数无法动态配置修改价格需要重新部署解决方案 1. 装饰者模式重构 定义 Valuation 接口实现 BasicValuation 、 StartPriceValuation 、 FuelCostValuation 三个装饰类2. 链式组合 通过嵌套构造器实现计费项的叠加计算3. 配置化参数 将起步价、里程费率、燃油费等参数配置到Nacos配置中心// 装饰者模式实现 public interface Valuation { float calculation(float km); } public class BasicValuation implements Valuation { private Valuation valuation; public float calculation(float km) { return 0; } } public class StartPriceValuation implements Valuation { private Valuation valuation; public float calculation(float km) { float base valuation.calculation(km); if (km 3) return base 13f; else return base 13f (km - 3) * 2.3f; } } public class FuelCostValuation implements Valuation { private Valuation valuation; public float calculation(float km) { return valuation.calculation(km) 1f; } } // 使用 private static final Valuation valuation new FuelCostValuation( new StartPriceValuation(new BasicValuation(null)) ); float price valuation.calculation(km);性能提升 - 新增计费项只需添加一个装饰类代码改动量从50行减少到10行以内- 参数配置化后修改价格无需重新部署响应时间从小时级降到秒级### 模块五邀请超时自动取消功能实现 - 用户发起邀请后通过RabbitMQ死信队列实现延迟消息 → 超时后自动更新邀请状态为已超时 → 释放座位资源遇到的问题 - 问题1 延迟消息丢失导致超时逻辑未执行- 问题2 并发问题用户确认和超时消息同时处理- 问题3 超时时间固定无法动态调整解决方案 1. 消息持久化 RabbitMQ消息设置 DeliveryMode.PERSISTENT 队列设置 durable true 确保消息不丢失2. 乐观锁机制 超时处理前检查当前状态是否为未确认只有未确认状态才能更新为超时3. 超时时间配置化 将超时时间配置到Nacos支持动态调整// 发送延迟消息 public void sendOver(StrokeVO strokeVO) { String mqMessage JSON.toJSONString(strokeVO); rabbitTemplate.convertAndSend( RabbitConfig.STROKE_OVER_QUEUE_EXCHANGE, RabbitConfig.STROKE_OVER_KEY, mqMessage, message - { message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT); return message; } ); } // 超时处理乐观锁 public void timeoutHandel(StrokeVO strokeVO) { String tripeeStatus redisHelper.getHash(HtichConstants.STROKE_INVITE_PREFIX, inviteeTripId, inviterTripId); String triperStatus redisHelper.getHash(HtichConstants.STROKE_INVITE_PREFIX, inviterTripId, inviteeTripId); // 只有未确认状态才能更新为超时 if (String.valueOf(InviteState.UNCONFIRMED.getCode()).equals(tripeeStatus) String.valueOf(InviteState.UNCONFIRMED.getCode()).equals(triperStatus)) { redisHelper.addHash(HtichConstants.STROKE_INVITE_PREFIX, inviteeTripId, inviterTripId, String.valueOf(InviteState.TIMEOUT.getCode())); redisHelper.addHash(HtichConstants.STROKE_INVITE_PREFIX, inviterTripId, inviteeTripId, String.valueOf(InviteState.TIMEOUT.getCode())); } }性能提升 - 消息持久化后消息丢失率从1%降到0%- 乐观锁机制解决了并发问题数据一致性达到99.99%### 模块六站内WebSocket实现即时通信系统功能实现 - 用户登录后建立WebSocket连接 → 服务端维护在线用户连接池 → 行程状态变更时实时推送消息 → 用户消息实时收发遇到的问题 - 问题1 WebSocket连接数过多内存占用过高- 问题2 消息发送失败用户离线时消息丢失- 问题3 连接断开后用户状态未及时更新解决方案 1. 连接池优化 使用 ConcurrentHashMap 作为连接池支持高并发访问定期清理无效连接2. 消息持久化 消息发送前先保存到MongoDB用户上线后推送离线消息3. 心跳检测 前端定期发送心跳包服务端检测超时连接并清理Component ServerEndpoint(value /ws/socket) public class WebSocketServer { // 线程安全的连接池 public final static MapString, Session sessionPools new ConcurrentHashMap(); OnOpen public void onOpen(Session session) { String accountId getAccountId(session); if (accountId ! null) { sessionPools.put(accountId, session); } } OnClose public void onClose(Session session) { String accountId getAccountId(session); if (accountId ! null) { sessionPools.remove(accountId); } } OnMessage public void onMessage(Session session, String message) { String accountId getAccountId(session); NoticeVO noticeVO JSON.parseObject(message, NoticeVO.class); noticeVO.setSenderId(accountId); // 保存消息到MongoDB noticeHandler.saveNotice(noticeVO); // 推送消息给接收者 Session receiverSession sessionPools.get(noticeVO.getReceiverId()); if (receiverSession ! null) { receiverSession.getBasicRemote().sendText(message); } } }性能提升 - 连接池使用ConcurrentHashMap支持10000并发连接- 消息持久化后离线消息丢失率从5%降到0%### 技术亮点与总结技术亮点 1. 百度AI集成 实现车牌和行驶证的OCR识别自动化车辆认证流程2. 装饰者模式计费 灵活的计费规则扩展符合开闭原则3. Redis GEO匹配 基于地理位置的智能匹配算法4. RabbitMQ延迟队列 可靠的超时任务处理机制5. WebSocket实时通信 低延迟的消息推送系统项目经验收获 - 深入理解了微服务架构的设计和实现- 掌握了第三方API集成的最佳实践百度OCR、地图API- 学会了使用设计模式解决复杂业务问题- 理解了分布式系统中的一致性问题和解决方案- 掌握了高并发场景下的性能优化策略12怎么结合RDB和AOF一起实现Redis持久化生产环境同时开启 RDB 与 AOF 混合持久化开启 AOF 记录每条写入指令保障故障最多丢失 1 秒数据配置定时 RDB 快照作为全量数据备份开启aof-use-rdb-preambleAOF 重写时先导出 RDB 快照写入新 AOF 头部大幅缩减 AOF 文件体积同时加快重启加载速度Redis 重启优先加载 AOF 文件先解析头部 RDB 快速恢复基线数据再执行尾部增量 AOF 指令还原完整数据两者结合兼顾 AOF 的数据安全性和 RDB 体积小、恢复快的优势单一持久化无法同时满足这两点。13解决这几个问题1、项目包含哪些微服务你负责哪些2、调用第三方接口异常你是怎么处理的3、你们是对服务进行常见的容错处理的4、请求流量最大设置1W突然来2W请求多出来的1w怎么处理的5、购物车同步redis异步mysql场景中mysql数据一直写入不进去怎么办6、项目上线前你是怎么进行测试的7、自定义注解有用过吗说个你在开发中使用时的场景8、分布式锁有使用过吗9、说一下你们的微服务项目是怎么部署的10、如何在spring框架中解决多数据源的问题如何维护数据源14skyWalking怎么在项目中部署以及使用15你们项目中有没有做过限流怎么做的16为什么分布式锁一定要先于事务执行必须先加分布式锁再开启数据库事务如果先开事务再加锁会出现严重超卖、数据并发不一致问题。