ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Java 项目实战: 外卖平台优化-前后端分离开发模式与工程拆分

Java 项目实战: 外卖平台优化-前后端分离开发模式与工程拆分 前后端分离: 开发模式、协作流程与工程结构拆分纲要前后端分离开发解决当前工程的一个结构性问题现状问题reggie_take_out一个Maven工程里既有Java代码又有backend/front两个目录的前端页面四个痛点分工不明确、开发效率低、不便于管理、招聘困难分离后的变化工程拆成前端工程与后端工程部署时后端打jar上Tomcat前端打包上Nginx协作流程定制接口 → 并行开发 → 前后端自测 → 联调 → 提测什么是接口一个HTTP请求的完整约定地址、方法、参数、响应前端技术栈VSCode/HBuilder、NodeJS、Vue、ElementUI、Mock、Webpack否是定制接口★ 最关键环节并行开发后端自测Postman / Swagger前端自测Mock 模拟数据前后端联调校验数据格式格式是否符合约定?提交测试一、当前工程的问题现状打开reggie_take_out工程目录构成是reggie_take_out/ ├── src/main/java/ # 后端 Java 代码 ├── src/main/resources/ │ ├── application.yml │ ├── mapper/ │ ├── static/ # 静态资源 │ │ ├── backend/ # 后台管理页面HTML/JS/CSS │ │ └── front/ # 移动端页面 │ └── templates/ └── pom.xmlsrc/main/resources/static下的backend与front两个目录装着全部前端代码——HTML、JS、CSS、图片。前后端代码混合在同一个Maven工程里。四个痛点分工不明确。同一个开发人员既要写Java后端又要写HTML/JS前端。职责边界模糊出了问题容易互相甩锅。开发效率低。一会儿写前端一会儿写后端上下文频繁切换。人的大脑切换任务是有成本的来回跳转会显著降低效率。不便于管理。很多时候只改了前端的一个按钮样式后端一行没动却必须打开整个Maven工程重新打包部署整个应用。一个小改动引发一次全量发布这在小版本中尤其浪费。招聘困难。要求一个人既精通Java生态Spring Boot、MyBatis、Redis、MySQL又精通前端Vue、Webpack、CSS这样的人极少即便有也成本高昂。混合开发的其他问题补充课程未展开但实践中同样突出的几点构建耦合前端改一个字也要跑一遍Maven打包构建时间从秒级变成分钟级无法独立扩缩容前端是静态资源本该由Nginx高效处理现在却要占用Tomcat的连接与JVM内存技术栈升级困难想换前端框架就得动后端工程风险外溢二、前后端分离开发定义前端代码交给专门的前端开发人员负责后端代码交给专门的后端开发人员负责。分工明确各司其职。三个收益提高效率——让合适的人做擅长的事。前端人员专注交互与体验后端人员专注业务与数据。可以并行开发——这是最大的收益。接口定好后前端与后端同时开工而不是前端等后端接口写完才能动。项目周期显著缩短。便于管理与维护——两个工程独立版本控制、独立构建、独立部署。工程结构的变化分离后从一个Maven工程拆成两个工程拆分前 拆分后 reggie_take_out/ reggie-backend/ reggie-front/ ├── src/main/java/ ├── src/main/java/ ├── public/ ├── src/main/resources/ ├── src/main/resources/ ├── src/ │ ├── static/ │ ├── application.yml │ ├── api/ │ │ ├── backend/ ← 前端 │ ├── mapper/ │ ├── views/ │ │ └── front/ ← 前端 │ └── static/已清空 │ ├── router/ │ └── templates/ └── pom.xml │ └── utils/ └── pom.xml ├── package.json └── vue.config.js后端工程只有Java代码与配置文件不再包含任何HTML/CSS/JS。前端工程只有前端代码没有任何Java。部署方式的变化这是容易被忽略但非常重要的一点分离前Maven 工程前后端混合打成一个 jar部署到 TomcatTomcat 同时处理静态资源 动态请求分离后后端工程打包成 jar前端工程Webpack 打包dist 目录部署到 Tomcat/Spring Boot部署到 Nginx只处理动态请求只处理静态资源后端代码打包部署到Tomcat服务器或Spring Boot内置容器前端工程打包后部署到Nginx。前端产物HTML/CSS/JS本质就是静态资源而Nginx处理静态资源的能力远强于Tomcatsendfile零拷贝、epoll高并发、不占JVM。这正是上一篇Nginx部署静态资源要解决的问题。注意分离后前端请求后端会涉及跨域问题需要配CORS或Nginx反向代理。这是下一篇Swagger与后续部署章节要处理的。三、协作流程完整流程分离后最核心的问题是前后端人员如何配合。标准流程五步第一步定制接口前后端坐下来或通过接口管理平台约定每个功能的请求细节。第二步并行开发双方按约定各自写代码互不阻塞。第三步各自自测后端用Postman、Swagger测试自己的接口前端用Mock造模拟数据验证页面渲染第四步联调前端请求真正打到后端主要校验数据格式是否符合约定。第五步提测交给专门的测试人员做完整验证。为什么定制接口是关键课程里特别强调了这个环节——如果接口没定义好就开始开发很可能联调时对接不上请求地址不对、参数不符合要求导致返工。联调阶段的典型事故约定返回JSON后端实际返回了XML或纯文本前端完全无法解析。这类问题在接口约定清晰时根本不会发生。接口的具体含义这里的接口不是Java的interface而是一个HTTP请求的完整约定包括要素说明示例接口名称功能描述新增用户请求方法GET/POST/PUT/DELETEPOST请求路径URL路径/user/add请求头Header要求Content-Type: application/json请求参数请求体或Query参数nameString、ageInteger参数约束是否必填、类型、示例name必填示例张三响应数据返回结构与示例{code:1,message:ok}完整接口示例新增用户接口接口名称新增用户 请求方式POST 请求路径/user/add 请求头 Content-Type: application/json 请求体application/json { name: 张三, // String必填 age: 25 // Integer必填 } 响应数据application/json { code: 1, message: ok }对应到外卖平台的实际接口例如菜品分页查询接口名称菜品分页查询 请求方式GET 请求路径/dish/page 请求参数Query page Integer 必填 示例 1 pageSize Integer 必填 示例 10 name String 非必填 示例 鱼香肉丝 响应数据application/json { code: 1, msg: null, data: { records: [ { id: 1397849739276890114, name: 鱼香肉丝, categoryId: 1397844263642378242, categoryName: 川菜, price: 3800, image: dish-xxx.jpg, status: 1 } ], total: 24, size: 10, current: 1, pages: 3 }, map: {} }注意id是字符串而非数字——这正是前面雪花ID精度丢失那一节的结果JacksonObjectMapper把Long序列化成String避免JS的2^53截断。这类细节必须在接口文档里写清楚否则前端按数字类型解析ID会踩坑。前端为什么能用 Mock 并行开发Mock即模拟数据。前端开发一个分页列表页面时不需要后端真的就绪只要按接口约定造一份假数据// mock/dish.jsexportdefault{GET /dish/page:{code:1,msg:null,data:{records:[{id:1397849739276890114,name:鱼香肉丝,categoryName:川菜,price:3800,status:1},{id:1397849739276890115,name:宫保鸡丁,categoryName:川菜,price:3600,status:1}],total:24,size:10,current:1,pages:3},map:{}}}关键前提Mock数据的结构必须与接口约定完全一致。这样页面在Mock下能正常渲染切到真实后端时因为数据格式一致自然也能渲染。这也是为什么接口约定必须先于开发——Mock数据就是接口约定的第一份可执行实现。四、前端技术栈后端工程师不需要写前端代码但要了解对方用什么才能高效协作。开发工具工具说明Visual Studio CodeVSCode目前最主流的前端编辑器插件生态丰富HBuilder国产前端IDE对uni-app支持好技术框架技术作用后端类比NodeJS前端运行基石类似JDKJDKVue前端MVVM框架Spring MVCElementUIUI组件库表格、下拉框、菜单Bootstrap/ 各种UI库Mock造模拟数据支持并行开发Postman Mock ServerWebpack前端打包工具MavenNodeJS的定位值得一说它之于前端就像JDK之于Java。前端的现代构建工具Webpack、Vite、开发服务器、包管理器npm、yarn全部运行在NodeJS之上。但它只用于开发期和构建期——最终产物是纯静态文件运行时不需要NodeJS。Webpack的产物不是jar/war而是一堆经过压缩、混淆、合并的JS/CSS/HTML通常输出到dist/目录。这个dist目录就是部署到Nginx的东西。前后端技术对照环节前端后端运行环境NodeJSJDK包管理npm/yarnMaven/Gradle依赖声明package.jsonpom.xml主框架VueSpring BootUI组件ElementUI—构建工具WebpackMaven构建产物dist/静态文件*.jar部署位置NginxTomcat/Spring Boot自测工具MockPostman/Swagger五、分离后的跨域问题分离开发带来一个新问题前端在Nginx80端口后端在Tomcat8080端口域名或端口不同即构成跨域浏览器的同源策略会拦截请求。解法一后端配置 CORSpackagecom.itheima.reggie.config;importorg.springframework.context.annotation.Configuration;importorg.springframework.web.servlet.config.annotation.CorsRegistry;importorg.springframework.web.servlet.config.annotation.WebMvcConfigurer;/** * 跨域配置 */ConfigurationpublicclassCorsConfigimplementsWebMvcConfigurer{OverridepublicvoidaddCorsMappings(CorsRegistryregistry){registry.addMapping(/**).allowedOriginPatterns(*).allowedMethods(GET,POST,PUT,DELETE,OPTIONS).allowedHeaders(*).allowCredentials(true).maxAge(3600);}}注意allowCredentials(true)与allowedOrigins(*)不能同时使用——CORS规范规定允许携带凭证时Origin不能用通配符。所以上面用的是allowedOriginPatterns(*)Spring 5.3支持或者显式列出允许的域名。解法二Nginx 反向代理推荐让前后端对外同一个域名同一个端口从根上消除跨域server { listen 80; server_name localhost; # 前端静态资源 location / { root html; index index.html; try_files $uri $uri/ /index.html; } # 后端接口转发到 8080 location /api/ { proxy_pass http://192.168.138.101:8080/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }前端所有请求都发到/api/**同源由Nginx转发到后端。浏览器看到的是同源请求不存在跨域。生产推荐这种方案——同源不仅避免了CORS的复杂配置还省去了预检请求OPTIONS带来的额外往返。六、接口文档的三种形态形态工具特点独立管理平台YApi需自行部署支持团队协作、Mock、测试代码自动生成Swagger/Knife4j注解驱动与代码同步后端友好静态文件Markdown/HTML离线可看但易与代码脱节下一篇讲YApi的具体使用再下一篇讲Swagger——后者是后端工程师更常用的方式因为它用注解写在代码里代码改了文档自动跟着变。API 速览概念 / 工具作用接口API一个HTTP请求的完整约定方法、路径、参数、响应Mock模拟数据让前端在后端未就绪时也能开发NodeJS前端构建期运行环境类比JDKVue前端MVVM框架ElementUIVue的UI组件库Webpack前端打包工具产物在dist/目录VSCode/HBuilder前端开发IDECORS跨域资源共享分离部署后必须处理allowedOriginPatternsSpring 5.3的跨域来源匹配可配合allowCredentialstry_filesNginx指令SPA前端路由回退到index.html官方文档Vue.js官方文档https://cn.vuejs.org/Element UI组件库https://element.eleme.cn/Node.js官网https://nodejs.org/Webpack文档https://webpack.docschina.org/MDNCORS说明https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORSSpringCORS支持https://docs.spring.io/spring-framework/reference/web/webmvc-cors.html总结前后端混合开发的本质问题是耦合分工、构建、部署、扩缩容全绑在一起。分离后前端工程与后端工程独立演进各自用最合适的工具链。分离不只是目录拆分部署方式也变了后端打jar上Tomcat/Spring Boot前端Webpack打包成dist上Nginx。前端产物本质是静态资源交给Nginx处理能获得sendfile零拷贝和epoll高并发的收益同时不占用宝贵的JVM资源。协作流程中最关键的是定制接口。这里的接口不是Java的interface而是一个HTTP请求的完整约定——方法、路径、请求头、参数含是否必填与示例、响应结构与示例。接口定清楚了前后端才能并行开发定不清楚联调阶段必然返工。前端能并行开发靠的是Mock而Mock数据必须与接口约定结构完全一致——所以接口文档实际上是Mock数据、前端代码、后端代码三方共同的输入。分离后出现跨域问题推荐用Nginx反向代理让前后端同源/api/**转发到后端比配置CORS更彻底既不用处理预检请求也避免了allowCredentials与通配符Origin的冲突。下一篇讲YApi——API管理平台的部署与使用包括创建项目、添加分类、定义接口、导出与批量导入接口文档。
返回列表