欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

[摄政外卖]前端和后端分离开发、项目部署、Swagger

最编程 2024-05-22 18:03:32
...


文章目录

 

目录

​​文章目录​​

​​前言​​

​​1. 前后端分离开发​​

​​1.1 介绍​​

​​1.2 开发流程​​

​​1.3 前端技术栈​​

​​2. Yapi​​

​​2.1 介绍​​

​​2.2 使用​​

​​3. Swagger​​

​​3.1 介绍​​

​​3.2 使用方式​​

​​3.3 查看接口文档​​

​​3.4 常用注解​​

​​4. 项目部署​​

​​4.1 部署架构​​

​​4.2 环境说明​​

​​4.3 前端部署​​

​​4.4 反向代理配置​​

​​4.5 服务端部署​​

​​4.6 图片展示问题处理​​

前言

当前项目中,前端代码和后端代码混合在一起,是存在问题的,存在什么问题呢?

【瑞吉外卖】前后端分离开发、项目部署、Swagger_java

 

主要存在以下几点问题:

1). 开发人员同时负责前端和后端代码开发,分工不明确

2). 开发效率低

3). 前后端代码混合在一个工程中,不便于管理

4). 对开发人员要求高(既会前端,又会后端),人员招聘困难

为了解决上述提到的问题,现在比较主流的开发方式,就是前后端分离开发,前端人员开发前端的代码,后端开发人员开发服务端的业务功能,分工明确,各司其职。我们本章节,就是需要将之前的项目进行优化改造,变成前后端分离开发的项目。

1. 前后端分离开发

1.1 介绍

前后端分离开发,就是在项目开发过程中,对于前端代码的开发由专门的前端开发人员负责,后端代码则由后端开发人员负责,这样可以做到分工明确、各司其职,提高开发效率,前后端代码并行开发,可以加快项目开发进度。

目前,前后端分离开发方式已经被越来越多的公司所采用,成为当前项目开发的主流开发方式。

前后端分离开发后,从工程结构上也会发生变化,即前后端代码不再混合在同一个maven工程中,而是分为 前端工程后端工程

【瑞吉外卖】前后端分离开发、项目部署、Swagger_java_02

 

前后端分离之后,不仅工程结构变化,后期项目上线部署时,与之前也不同:

1). 之前: 前后端代码都混合在一起,我们只需要将前端和后端的代码统一打成jar包,直接运行就可以了。

2). 现在: 拆分为前后端分离的项目后,最终部署时,后端工程会打成一个jar包,运行在Tomcat中(springboot内嵌的tomcat)。前端工程的静态资源,会直接部署在Nginx中进行访问。

1.2 开发流程

前后端分离开发后,面临一个问题,就是前端开发人员和后端开发人员如何进行配合来共同开发一个项目?可以按照如下流程进行:

【瑞吉外卖】前后端分离开发、项目部署、Swagger_spring boot_03

 

1). 定制接口: 这里所说的接口不是我们之前在service, mapper层定义的interface; 这里的接口(API接口)就是一个http的请求地址,主要就是去定义:请求路径、请求方式、请求参数、响应数据等内容。(具体接口文档描述的信息, 如上图)

2). 前后端并行开发: 依据定义好的接口信息,前端人员开发前端的代码,服务端人员开发服务端的接口; 在开发中前后端都需要进行测试,后端需要通过对应的工具来进行接口的测试,前端需要根据接口定义的参数进行Mock数据模拟测试。

3). 联调: 当前后端都开发完毕并且自测通过之后,就可以进行前后端的联调测试了,在这一阶段主要就是校验接口的参数格式。

4). 提测: 前后端联调测试通过之后,就可以将项目部署到测试服务器,进行自动化测试了。

1.3 前端技术栈

1). 开发工具

Visual Studio Code (简称VsCode)

Hbuilder

2). 技术框架

A. Node.js: Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。(类似于java语言中的JDK)。

B. Vue : 目前最火的的一个前端javaScript框架。

C. ElementUI: 一套为开发者、设计师和产品经理准备的基于 Vue 2.0 的桌面端组件库,通过ElementUI组件可以快速构建项目页面。

D. Mock: 生成随机数据,拦截 Ajax 请求,前端可以借助于Mock生成测试数据进行功能测试。

E. Webpack: webpack 是一个现代 JavaScript 应用程序的模块打包器(module bundler),分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Sass,TypeScript等),并将其转换和打包为合适的格式供浏览器使用。

2. Yapi

2.1 介绍

【瑞吉外卖】前后端分离开发、项目部署、Swagger_java_04

YApi 是高效、易用、功能强大的 api 管理平台,旨在为开发、产品、测试人员提供更优雅的接口管理服务。可以帮助开发者轻松创建、发布、维护 API,YApi 还为用户提供了优秀的交互体验,开发人员只需利用平台提供的接口数据写入工具以及简单的点击操作就可以实现接口的管理。

YApi让接口开发更简单高效,让接口的管理更具可读性、可维护性,让团队协作更合理。

源码地址: ​​https://github.com/YMFE/yapi​

官方文档: ​​YApi 接口管理平台​

要使用YApi,项目组需要自己进行部署,在本项目中我们可以使用课程提供的平台进行测试,域名: ​​YApi-高效、易用、功能强大的可视化接口管理平台​

2.2 使用

2.2.1 准备

注册账号,登录平台

【瑞吉外卖】前后端分离开发、项目部署、Swagger_java_05

 

 

2.2.2 定义接口

登录到Yapi平台之后,我们可以创建项目,在项目下创建接口分类,在对应的分类中添加接口。

1). 创建项目

【瑞吉外卖】前后端分离开发、项目部署、Swagger_项目_06

【瑞吉外卖】前后端分离开发、项目部署、Swagger_项目_07

 

【瑞吉外卖】前后端分离开发、项目部署、Swagger_前端_08

2). 添加分类

在当前项目中,有针对于员工、菜品、套餐、订单的操作,我们在进行接口维护时,可以针对接口进行分类,如果没有对应的分类,我们自己添加分类。

【瑞吉外卖】前后端分离开发、项目部署、Swagger_前端_09

3). 添加接口

【瑞吉外卖】前后端分离开发、项目部署、Swagger_spring boot_10

 

接口基本信息录入之后,添加提交,就可以看到该接口的基本信息:

【瑞吉外卖】前后端分离开发、项目部署、Swagger_spring boot_11

 

但是目前,接口中我们并未指定请求参数,响应数据等信息,我们可以进一步点击编辑,对该接口 详情进行编辑处理。

【瑞吉外卖】前后端分离开发、项目部署、Swagger_前端_12

【瑞吉外卖】前后端分离开发、项目部署、Swagger_spring boot_13

 

4). 运行接口

Yapi也提供了接口测试功能,当我们接口编辑完毕后,后端服务的代码开发完毕,启动服务,就可以使用Yapi进行接口测试了。

【瑞吉外卖】前后端分离开发、项目部署、Swagger_java_14

注意: 由于菜品分页查询接口,是需要登录后才可以访问的,所以在测试该接口时,需要先请求员工管理接口中的登录接口,登录完成后,再访问该接口。

在Yapi平台中,将接口文档定义好了之后,前后端开发人员就需要根据接口文档中关于接口的描述进行前端和后端功能的开发。

2.2.3 导出接口文档

在Yapi平台中我们不仅可以在线阅读文档,还可以将Yapi中维护的文档直接导出来,可以导出md,json,html格式,在导出时自行选择即可 。

【瑞吉外卖】前后端分离开发、项目部署、Swagger_spring boot_15

 

而在导出的html文件或md文件中,主要描述的就是接口的基本信息, 包括: 请求路径、请求方式、接口描述、请求参数、返回数据等信息。展示形式如下:

【瑞吉外卖】前后端分离开发、项目部署、Swagger_前端_16

 

2.2.4 导入接口文档

上述我们讲解了接口文档的导出,我们也可以将外部的接口文档导入到Yapi的平台中,这样我们就不用一个接口一个接口的添加了。我们可以将课程资料中提供的json格式的接口文档直接导入Yapi平台中来。

【瑞吉外卖】前后端分离开发、项目部署、Swagger_spring boot_17

 

导入过程中出现的确认弹窗,选择"确认"。

【瑞吉外卖】前后端分离开发、项目部署、Swagger_前端_18

 

导入成功之后,我们就可以在Yapi平台查看到已导入的接口。

【瑞吉外卖】前后端分离开发、项目部署、Swagger_前端_19

3. Swagger

3.1 介绍

官网:​​API Documentation & Design Tools for Teams | Swagger​

【瑞吉外卖】前后端分离开发、项目部署、Swagger_毕设_20

 

Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。功能主要包含以下几点:

A. 使得前后端分离开发更加方便,有利于团队协作

B. 接口文档在线自动生成,降低后端开发人员编写接口文档的负担

C. 接口功能测试

使用Swagger只需要按照它的规范去定义接口及接口相关的信息,再通过Swagger衍生出来的一系列项目和工具,就可以做到生成各种格式的接口文档,以及在线接口调试页面等等。

直接使用Swagger, 需要按照Swagger的规范定义接口, 实际上就是编写Json文件,编写起来比较繁琐、并不方便, 。而在项目中使用,我们一般会选择一些现成的框架来简化文档的编写,而这些框架是基于Swagger的,如knife4j。knife4j是为Java MVC框架集成Swagger生成Api文档的增强解决方案。而我们要使用kinfe4j,需要在pom.xml中引入如下依赖即可:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#117700"><</span><span style="color:#117700">dependency</span><span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">groupId</span><span style="color:#117700">></span>com.github.xiaoymin<span style="color:#117700"></</span><span style="color:#117700">groupId</span><span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">artifactId</span><span style="color:#117700">></span>knife4j-spring-boot-starter<span style="color:#117700"></</span><span style="color:#117700">artifactId</span><span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">version</span><span style="color:#117700">></span>3.0.2<span style="color:#117700"></</span><span style="color:#117700">version</span><span style="color:#117700">></span>
<span style="color:#117700"></</span><span style="color:#117700">dependency</span><span style="color:#117700">></span></span></span>

3.2 使用方式

接下来,我们就将我们的项目集成Knife4j,来自动生成接口文档。这里我们还是需要再创建一个新的分支v1.2,在该分支中进行knife4j的集成,集成测试完毕之后,没有问题,我们再将v1.2分支合并到master。

使用knife4j,主要需要操作以下几步:

1). 导入knife4j的maven坐标

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#117700"><</span><span style="color:#117700">dependency</span><span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">groupId</span><span style="color:#117700">></span>com.github.xiaoymin<span style="color:#117700"></</span><span style="color:#117700">groupId</span><span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">artifactId</span><span style="color:#117700">></span>knife4j-spring-boot-starter<span style="color:#117700"></</span><span style="color:#117700">artifactId</span><span style="color:#117700">></span>
<span style="color:#117700"><</span><span style="color:#117700">version</span><span style="color:#117700">></span>3.0.2<span style="color:#117700"></</span><span style="color:#117700">version</span><span style="color:#117700">></span>
<span style="color:#117700"></</span><span style="color:#117700">dependency</span><span style="color:#117700">></span></span></span>

2). 导入knife4j相关配置类

这里我们就不需要再创建一个新的配置类了,我们直接在WebMvcConfig配置类中声明即可。

A. 在该配置类中加上两个注解 @EnableSwagger2 @EnableKnife4j ,开启Swagger和Knife4j的功能。

B. 在配置类中声明一个Docket类型的bean, 通过该bean来指定生成文档的信息。

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#555555">@Slf4j</span>
<span style="color:#555555">@Configuration</span>
<span style="color:#555555">@EnableSwagger2</span>
<span style="color:#555555">@EnableKnife4j</span>
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">WebMvcConfig</span> <span style="color:#770088">extends</span> <span style="color:#000000">WebMvcConfigurationSupport</span> {

<span style="color:#aa5500">/**</span>
<span style="color:#aa5500">* 设置静态资源映射</span>
<span style="color:#aa5500">* @param registry</span>
<span style="color:#aa5500">*/</span>
<span style="color:#555555">@Override</span>
<span style="color:#770088">protected</span> <span style="color:#008855">void</span> <span style="color:#000000">addResourceHandlers</span>(<span style="color:#000000">ResourceHandlerRegistry</span> <span style="color:#000000">registry</span>) {
<span style="color:#000000">log</span>.<span style="color:#000000">info</span>(<span style="color:#aa1111">"开始进行静态资源映射..."</span>);
<span style="color:#000000">registry</span>.<span style="color:#000000">addResourceHandler</span>(<span style="color:#aa1111">"/backend/**"</span>).<span style="color:#000000">addResourceLocations</span>(<span style="color:#aa1111">"classpath:/backend/"</span>);
<span style="color:#000000">registry</span>.<span style="color:#000000">addResourceHandler</span>(<span style="color:#aa1111">"/front/**"</span>).<span style="color:#000000">addResourceLocations</span>(<span style="color:#aa1111">"classpath:/front/"</span>);
}

<span style="color:#aa5500">/**</span>
<span style="color:#aa5500">* 扩展mvc框架的消息转换器</span>
<span style="color:#aa5500">* @param converters</span>
<span style="color:#aa5500">*/</span>
<span style="color:#555555">@Override</span>
<span style="color:#770088">protected</span> <span style="color:#008855">void</span> <span style="color:#000000">extendMessageConverters</span>(<span style="color:#000000">List</span><span style="color:#981a1a"><</span><span style="color:#000000">HttpMessageConverter</span><span style="color:#981a1a"><?>></span> <span style="color:#000000">converters</span>) {
<span style="color:#000000">log</span>.<span style="color:#000000">info</span>(<span style="color:#aa1111">"扩展消息转换器..."</span>);
<span style="color:#aa5500">//创建消息转换器对象</span>
<span style="color:#000000">MappingJackson2HttpMessageConverter</span> <span style="color:#000000">messageConverter</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">MappingJackson2HttpMessageConverter</span>();
<span style="color:#aa5500">//设置对象转换器,底层使用Jackson将Java对象转为json</span>
<span style="color:#000000">messageConverter</span>.<span style="color:#000000">setObjectMapper</span>(<span style="color:#770088">new</span> <span style="color:#000000">JacksonObjectMapper</span>());
<span style="color:#aa5500">//将上面的消息转换器对象追加到mvc框架的转换器集合中</span>
<span style="color:#000000">converters</span>.<span style="color:#000000">add</span>(<span style="color:#116644">0</span>,<span style="color:#000000">messageConverter</span>);
}

<span style="color:#555555">@Bean</span>
<span style="color:#770088">public</span> <span style="color:#000000">Docket</span> <span style="color:#000000">createRestApi</span>() {
<span style="color:#aa5500">// 文档类型</span>
<span style="color:#770088">return</span> <span style="color:#770088">new</span> <span style="color:#000000">Docket</span>(<span style="color:#000000">DocumentationType</span>.<span style="color:#000000">SWAGGER_2</span>)
.<span style="color:#000000">apiInfo</span>(<span style="color:#000000">apiInfo</span>())
.<span style="color:#000000">select</span>()
.<span style="color:#000000">apis</span>(<span style="color:#000000">RequestHandlerSelectors</span>.<span style="color:#000000">basePackage</span>(<span style="color:#aa1111">"com.itheima.reggie.controller"</span>))
.<span style="color:#000000">paths</span>(<span style="color:#000000">PathSelectors</span>.<span style="color:#000000">any</span>())
.<span style="color:#000000">build</span>();
}

<span style="color:#770088">private</span> <span style="color:#000000">ApiInfo</span> <span style="color:#000000">apiInfo</span>() {
<span style="color:#770088">return</span> <span style="color:#770088">new</span> <span style="color:#000000">ApiInfoBuilder</span>()
.<span style="color:#000000">title</span>(<span style="color:#aa1111">"瑞吉外卖"</span>)
.<span style="color:#000000">version</span>(<span style="color:#aa1111">"1.0"</span>)
.<span style="color:#000000">description</span>(<span style="color:#aa1111">"瑞吉外卖接口文档"</span>)
.<span style="color:#000000">build</span>();
}
}</span></span>

注意: Docket声明时,指定的有一个包扫描的路径,该路径指定的是Controller所在包的路径。因为Swagger在生成接口文档时,就是根据这里指定的包路径,自动的扫描该包下的@Controller, @RestController, @RequestMapping等SpringMVC的注解,依据这些注解来生成对应的接口文档。

3). 设置静态资源映射

由于Swagger生成的在线文档中,涉及到很多静态资源,这些静态资源需要添加静态资源映射,否则接口文档页面无法访问。因此需要在 WebMvcConfig类中的addResourceHandlers方法中增加如下配置。

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#000000">registry</span>.<span style="color:#000000">addResourceHandler</span>(<span style="color:#aa1111">"doc.html"</span>).<span style="color:#000000">addResourceLocations</span>(<span style="color:#aa1111">"classpath:/META-INF/resources/"</span>);
<span style="color:#000000">registry</span>.<span style="color:#000000">addResourceHandler</span>(<span style="color:#aa1111">"/webjars/**"</span>).<span style="color:#000000">addResourceLocations</span>(<span style="color:#aa1111">"classpath:/META-INF/resources/webjars/"</span>);</span></span>

4). 在LoginCheckFilter中设置不需要处理的请求路径

需要将Swagger及Knife4j相关的静态资源直接放行,无需登录即可访问,否则我们就需要登录之后,才可以访问接口文档的页面。

在原有的不需要处理的请求路径中,再增加如下链接:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#aa1111">"/doc.html"</span>,
<span style="color:#aa1111">"/webjars/**"</span>,
<span style="color:#aa1111">"/swagger-resources"</span>,
<span style="color:#aa1111">"/v2/api-docs"</span></span></span>

【瑞吉外卖】前后端分离开发、项目部署、Swagger_项目_21

 

3.3 查看接口文档

经过上面的集成配置之后,我们的项目集成Swagger及Knife4j就已经完成了,接下来我们可以重新启动项目,访问接口文档,访问链接为: ​​http://localhost:8080/doc.html​​

【瑞吉外卖】前后端分离开发、项目部署、Swagger_毕设_22

 

我们可以看到,在所有的Controller中提供的所有的业务增删改查的接口,全部都已经自动生成了,我们通过接口文档可以看到请求的url、请求方式、请求参数、请求实例、响应的参数,响应的示例。 并且呢,我们也可以通过这份在线的接口文档,对接口进行测试。

【瑞吉外卖】前后端分离开发、项目部署、Swagger_项目_23

 

注意: 由于我们服务端的Controller中的业务增删改查的方法,都是必须登录之后才可以访问的,所以,我们在测试时候,也是需要先访问登录接口。登录完成之后,我们可以再访问其他接口进行测试。

我们不仅可以在浏览器浏览生成的接口文档,Knife4j还支持离线文档,对接口文档进行下载,支持下载的格式有:markdown、html、word、openApi。

【瑞吉外卖】前后端分离开发、项目部署、Swagger_项目_24

 

3.4 常用注解

3.4.1 问题说明

在上面我们直接访问Knife4j的接口文档页面,可以查看到所有的接口文档信息,但是我们发现,这些接口文档分类及接口描述都是Controller的类名(驼峰命名转换而来)及方法名,而且在接口文档中,所有的请求参数,响应数据,都没有中文的描述,并不知道里面参数的含义,接口文档的可读性很差。

【瑞吉外卖】前后端分离开发、项目部署、Swagger_java_25

 

3.4.2 注解介绍

为了解决上述的问题,Swagger提供了很多的注解,通过这些注解,我们可以更好更清晰的描述我们的接口,包含接口的请求参数、响应数据、数据模型等。核心的注解,主要包含以下几个:

注解

位置

说明

@Api


加载Controller类上,表示对类的说明

@ApiModel

类(通常是实体类)

描述实体类的作用

@ApiModelProperty

属性

描述实体类的属性

@ApiOperation

方法

说明方法的用途、作用

@ApiImplicitParams

方法

表示一组参数说明

@ApiImplicitParam

方法

用在@ApiImplicitParams注解中,指定一个请求参数的各个方面的属性

3.4.3 注解测试

1). 实体类

可以通过 @ApiModel , @ApiModelProperty 来描述实体类及属性

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#555555">@Data</span>
<span style="color:#555555">@ApiModel</span>(<span style="color:#aa1111">"套餐"</span>)
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Setmeal</span> <span style="color:#770088">implements</span> <span style="color:#000000">Serializable</span> {
<span style="color:#770088">private</span> <span style="color:#770088">static</span> <span style="color:#770088">final</span> <span style="color:#008855">long</span> <span style="color:#000000">serialVersionUID</span> <span style="color:#981a1a">=</span> <span style="color:#116644">1L</span>;
<span style="color:#555555">@ApiModelProperty</span>(<span style="color:#aa1111">"主键"</span>)
<span style="color:#770088">private</span> <span style="color:#008855">Long</span> <span style="color:#000000">id</span>;

<span style="color:#aa5500">//分类id</span>
<span style="color:#555555">@ApiModelProperty</span>(<span style="color:#aa1111">"分类id"</span>)
<span style="color:#770088">private</span> <span style="color:#008855">Long</span> <span style="color:#000000">categoryId</span>;

<span style="color:#aa5500">//套餐名称</span>
<span style="color:#555555">@ApiModelProperty</span>(<span style="color:#aa1111">"套餐名称"</span>)
<span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">name</span>;

<span style="color:#aa5500">//套餐价格</span>
<span style="color:#555555">@ApiModelProperty</span>(<span style="color:#aa1111">"套餐价格"</span>)
<span style="color:#770088">private</span> <span style="color:#000000">BigDecimal</span> <span style="color:#000000">price</span>;

<span style="color:#aa5500">//状态 0:停用 1:启用</span>
<span style="color:#555555">@ApiModelProperty</span>(<span style="color:#aa1111">"状态"</span>)
<span style="color:#770088">private</span> <span style="color:#008855">Integer</span> <span style="color:#000000">status</span>;

<span style="color:#aa5500">//编码</span>
<span style="color:#555555">@ApiModelProperty</span>(<span style="color:#aa1111">"套餐编号"</span>)
<span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">code</span>;

<span style="color:#aa5500">//描述信息</span>
<span style="color:#555555">@ApiModelProperty</span>(<span style="color:#aa1111">"描述信息"</span>)
<span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">description</span>;

<span style="color:#aa5500">//图片</span>
<span style="color:#555555">@ApiModelProperty</span>(<span style="color:#aa1111">"图片"</span>)
<span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">image</span>;

<span style="color:#555555">@TableField</span>(<span style="color:#000000">fill</span> <span style="color:#981a1a">=</span> <span style="color:#000000">FieldFill</span>.<span style="color:#000000">INSERT</span>)
<span style="color:#770088">private</span> <span style="color:#000000">LocalDateTime</span> <span style="color:#000000">createTime</span>;

<span style="color:#555555">@TableField</span>(<span style="color:#000000">fill</span> <span style="color:#981a1a">=</span> <span style="color:#000000">FieldFill</span>.<span style="color:#000000">INSERT_UPDATE</span>)
<span style="color:#770088">private</span> <span style="color:#000000">LocalDateTime</span> <span style="color:#000000">updateTime</span>;

<span style="color:#555555">@TableField</span>(<span style="color:#000000">fill</span> <span style="color:#981a1a">=</span> <span style="color:#000000">FieldFill</span>.<span style="color:#000000">INSERT</span>)
<span style="color:#770088">private</span> <span style="color:#008855">Long</span> <span style="color:#000000">createUser</span>;

<span style="color:#555555">@TableField</span>(<span style="color:#000000">fill</span> <span style="color:#981a1a">=</span> <span style="color:#000000">FieldFill</span>.<span style="color:#000000">INSERT_UPDATE</span>)
<span style="color:#770088">private</span> <span style="color:#008855">Long</span> <span style="color:#000000">updateUser</span>;
}</span></span>

2). 响应实体R

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#555555">@Data</span>
<span style="color:#555555">@ApiModel</span>(<span style="color:#aa1111">"返回结果"</span>)
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">R</span><span style="color:#981a1a"><</span><span style="color:#000000">T</span><span style="color:#981a1a">></span> <span style="color:#770088">implements</span> <span style="color:#000000">Serializable</span>{

<span style="color:#555555">@ApiModelProperty</span>(<span style="color:#aa1111">"编码"</span>)
<span style="color:#770088">private</span> <span style="color:#008855">Integer</span> <span style="color:#000000">code</span>; <span style="color:#aa5500">//编码:1成功,0和其它数字为失败</span>

<span style="color:#555555">@ApiModelProperty</span>(<span style="color:#aa1111">"错误信息"</span>)
<span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">msg</span>; <span style="color:#aa5500">//错误信息</span>

<span style="color:#555555">@ApiModelProperty</span>(<span style="color:#aa1111">"数据"</span>)
<span style="color:#770088">private</span> <span style="color:#000000">T</span> <span style="color:#000000">data</span>; <span style="color:#aa5500">//数据</span>

<span style="color:#555555">@ApiModelProperty</span>(<span style="color:#aa1111">"动态数据"</span>)
<span style="color:#770088">private</span> <span style="color:#000000">Map</span> <span style="color:#000000">map</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">HashMap</span>(); <span style="color:#aa5500">//动态数据</span>

<span style="color:#aa5500">//省略静态方法 ....</span>
} </span></span>

3). Controller类及其中的方法

描述Controller、方法及其方法参数,可以通过注解: @Api, @APIOperation, @ApiImplicitParams, @ApiImplicitParam

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#555555">@RestController</span>
<span style="color:#555555">@RequestMapping</span>(<span style="color:#aa1111">"/setmeal"</span>)
<span style="color:#555555">@Slf4j</span>
<span style="color:#555555">@Api</span>(<span style="color:#000000">tags</span> <span style="color:#981a1a">=</span> <span style="color:#aa1111">"套餐相关接口"</span>)
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">SetmealController</span> {

<span style="color:#555555">@Autowired</span>
<span style="color:#770088">private</span> <span style="color:#000000">SetmealService</span> <span style="color:#000000">setmealService</span>;
<span style="color:#555555">@Autowired</span>
<span style="color:#770088">private</span> <span style="color:#000000">CategoryService</span> <span style="color:#000000">categoryService</span>;
<span style="color:#555555">@Autowired</span>
<span style="color:#770088">private</span> <span style="color:#000000">SetmealDishService</span> <span style="color:#000000">setmealDishService</span>;

<span style="color:#aa5500">/**</span>
<span style="color:#aa5500">* 新增套餐</span>
<span style="color:#aa5500">* @param setmealDto</span>
<span style="color:#aa5500">* @return</span>
<span style="color:#aa5500">*/</span>
<span style="color:#555555">@PostMapping</span>
<span style="color:#555555">@CacheEvict</span>(<span style="color:#000000">value</span> <span style="color:#981a1a">=</span> <span style="color:#aa1111">"setmealCache"</span>,<span style="color:#000000">allEntries</span> <span style="color:#981a1a">=</span> <span style="color:#221199">true</span>)
<span style="color:#555555">@ApiOperation</span>(<span style="color:#000000">value</span> <span style="color:#981a1a">=</span> <span style="color:#aa1111">"新增套餐接口"</span>)
<span style="color:#770088">public</span> <span style="color:#000000">R</span><span style="color:#981a1a"><</span><span style="color:#008855">String</span><span style="color:#981a1a">></span> <span style="color:#000000">save</span>(<span style="color:#555555">@RequestBody</span> <span style="color:#000000">SetmealDto</span> <span style="color:#000000">setmealDto</span>){
<span style="color:#000000">log</span>.<span style="color:#000000">info</span>(<span style="color:#aa1111">"套餐信息:{}"</span>,<span style="color:#000000">setmealDto</span>);

<span style="color:#000000">setmealService</span>.<span style="color:#000000">saveWithDish</span>(<span style="color:#000000">setmealDto</span>);

<span style="color:#770088">return</span> <span style="color:#000000">R</span>.<span style="color:#000000">success</span>(<span style="color:#aa1111">"新增套餐成功"</span>);
}

<span style="color:#aa5500">/**</span>
<span style="color:#aa5500">* 套餐分页查询</span>
<span style="color:#aa5500">* @param page</span>
<span style="color:#aa5500">* @param pageSize</span>
<span style="color:#aa5500">* @param name</span>
<span style="color:#aa5500">* @return</span>
<span style="color:#aa5500">*/</span>
<span style="color:#555555">@GetMapping</span>(<span style="color:#aa1111">"/page"</span>)
<span style="color:#555555">@ApiOperation</span>(<span style="color:#000000">value</span> <span style="color:#981a1a">=</span> <span style="color:#aa1111">"套餐分页查询接口"</span>)
<span style="color:#555555">@ApiImplicitParams</span>({
<span style="color:#555555">@ApiImplicitParam</span>(<span style="color:#000000">name</span> <span style="color:#981a1a">=</span> <span style="color:#aa1111">"page"</span>,<span style="color:#000000">value</span> <span style="color:#981a1a">=</span> <span style="color:#aa1111">"页码"</span>,<span style="color:#000000">required</span> <span style="color:#981a1a">=</span> <span style="color:#221199">true</span>),
<span style="color:#555555">@ApiImplicitParam</span>(<span style="color:#000000">name</span> <span style="color:#981a1a">=</span> <span style="color:#aa1111">"pageSize"</span>,<span style="color:#000000">value</span> <span style="color:#981a1a">=</span> <span style="color:#aa1111">"每页记录数"</span>,<span style="color:#000000">required</span> <span style="color:#981a1a">=</span> <span style="color:#221199">true</span>),
<span style="color:#555555">@ApiImplicitParam</span>(<span style="color:#000000">name</span> <span style="color:#981a1a">=</span> <span style="color:#aa1111">"name"</span>,<span style="color:#000000">value</span> <span style="color:#981a1a">=</span> <span style="color:#aa1111">"套餐名称"</span>,<span style="color:#000000">required</span> <span style="color:#981a1a">=</span> <span style="color:#221199">false</span>)
})
<span style="color:#770088">public</span> <span style="color:#000000">R</span><span style="color:#981a1a"><</span><span style="color:#000000">Page</span><span style="color:#981a1a">></span> <span style="color:#000000">page</span>(<span style="color:#008855">int</span> <span style="color:#000000">page</span>,<span style="color:#008855">int</span> <span style="color:#000000">pageSize</span>,<span style="color:#008855">String</span> <span style="color:#000000">name</span>){
<span style="color:#aa5500">//分页构造器对象</span>
<span style="color:#000000">Page</span><span style="color:#981a1a"><</span><span style="color:#000000">Setmeal</span><span style="color:#981a1a">></span> <span style="color:#000000">pageInfo</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Page</span><span style="color:#981a1a"><></span>(<span style="color:#000000">page</span>,<span style="color:#000000">pageSize</span>);
<span style="color:#000000">Page</span><span style="color:#981a1a"><</span><span style="color:#000000">SetmealDto</span><span style="color:#981a1a">></span> <span style="color:#000000">dtoPage</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Page</span><span style="color:#981a1a"><></span>();

<span style="color:#000000">LambdaQueryWrapper</span><span style="color:#981a1a"><</span><span style="color:#000000">Setmeal</span><span style="color:#981a1a">></span> <span style="color:#000000">queryWrapper</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">LambdaQueryWrapper</span><span style="color:#981a1a"><></span>();
<span style="color:#aa5500">//添加查询条件,根据name进行like模糊查询</span>
<span style="color:#000000">queryWrapper</span>.<span style="color:#000000">like</span>(<span style="color:#000000">name</span> <span style="color:#981a1a">!=</span> <span style="color:#221199">null</span>,<span style="color:#000000">Setmeal</span>::<span style="color:#000000">getName</span>,<span style="color:#000000">name</span>);
<span style="color:#aa5500">//添加排序条件,根据更新时间降序排列</span>
<span style="color:#000000">queryWrapper</span>.<span style="color:#000000">orderByDesc</span>(<span style="color:#000000">Setmeal</span>::<span style="color:#000000">getUpdateTime</span>);

<span style="color:#000000">setmealService</span>.<span style="color:#000000">page</span>(<span style="color:#000000">pageInfo</span>,<span style="color:#000000">queryWrapper</span>);

<span style="color:#aa5500">//对象拷贝</span>
<span style="color:#000000">BeanUtils</span>.<span style="color:#000000">copyProperties</span>(<span style="color:#000000">pageInfo</span>,<span style="color:#000000">dtoPage</span>,<span style="color:#aa1111">"records"</span>);
<span style="color:#000000">List</span><span style="color:#981a1a"><</span><span style="color:#000000">Setmeal</span><span style="color:#981a1a">></span> <span style="color:#000000">records</span> <span style="color:#981a1a">=</span> <span style="color:#000000">pageInfo</span>.<span style="color:#000000">getRecords</span>();

<span style="color:#000000">List</span><span style="color:#981a1a"><</span><span style="color:#000000">SetmealDto</span><span style="color:#981a1a">></span> <span style="co

推荐阅读