目录
项目初始工程搭建:
不同项目需要的前后端环境也不同
前端项目搭建:
熟悉模块的方式
代码阅读
如何开发一个接口
Swagger(接口文档)
Api注解的说明
项目初始工程搭建:
公司项目分两种,新立项目(0-1)和已有项目开发(1-2)
熟悉项目结构,每个模块对应的作用,比如这个项目中web依赖service,service依赖common,他们都有共同的父工程
代码在企业中常常通过Git拉取和管理(不会的可以在我主页搜索相关文章)
不同项目需要的前后端环境也不同
第一步:安装JDK11
win10系统
https://blog.csdn.net/climber16/article/details/83242425
win11系统
https://blog.csdn.net/Li_Ya_Fei/article/details/131189321
mac系统
https://blog.51cto.com/u_15294985/5132958
第二步,将对应maven导入到自己容易查找的目录
第三步.在idea中导入项目,这里是复制粘贴,企业里根据git拉代码,(将代码上传至github管理,具体见我前面文章),配置idea到对应jdk,修改maven
第四步.使用内置datagrip导入数据库
第五步,修改配置文件,数据库连接池和密码
配置文件和启动类单独放在zzyl-web中
前端项目搭建:
拉取代码,放到非中文目录
下在node.js
cmd中用node-v检验
在管理员打开的cmd中用 npm install -g yarn下载yarn(另一个JavaScript资源管理包),用来解决早期npm的一些性能和安全问题
yarn -v 验证版本
-
现代 npm(v5+)的性能已显著提升,但 Yarn 仍因其特性(如离线缓存、
yarn.lock
文件)被广泛使用。
之后可以使用yarn install下载依赖,yarn的很多命令和npm是相似的,只改变了前缀
前端项目中,项目的根目录vite.config.ts文件中定义了访问后端接口的服务地址
最后在终端通过一下命令运行
yarn run dev
失败的可以试一下
npm run dev
熟悉模块的方式
1.阅读原型文档和需求文档
两种方式:(1).原型文档文件夹
(2).项目原型地址
在观察原型图时,找到需要开发的接口和对应的需求,严格按照需求开发功能
首先观察文档的全局说明,在有全局说明的情况下,很多接口是默认按照全局说明处理的,比如单页10条数据,超出自动分页
看原型文档需要看到什么程度:
1)了解产品的背景和定位,熟悉业务流程
2)了解功能描述和系统流程(大概知道有几个接口,每个接口的作用是什么)
3).和产品经理确认理解没有偏差
2.熟悉表结构
在DataGrip中有Modify Table(修改表)
里面包括表的名称,备注,主键,外键,唯一约束等等
3.页面点击访问感受(推测一下流程)
自己在测试功能时就可以熟悉功能,检验bug,比如我在测试图片上传功能时原代码就有bug,调错了构造方法,msg本来应该是返回一个友好消息,比如文件上传成功,用户创建成功等.
4.阅读对应模块代码
对于不熟悉的代码可以喂给AI去解读
代码阅读
1.查看浏览器http请求,F12调出开发者模式,通过网络查看接口请求和响应
2.控制层Controller
符合RESTful风格,Get查询,Post增加,Put修改,Delete删除
返回的格式:ResultResponse
继承了BaseController,BaseController封装了一些通用的方法(比如获取参数,日志打印,分页查询,返回封装结果,异常处理等)
DTO:Data Transfer Object 数据传输对象,接受前端传来的数据
VO:Value Object 展示对象:接口的出参
业务层:对象拷贝工具类BeanUtils(Hutool工具包,转化类型)
持久层
查看Sql语句类型
如何开发一个接口
1.根据原型图设计接口
2.制作接口文档
3.进行功能开发
其中:表结构设计,接口设计,测试缺陷过程是反复进行的,在开发过程中不断修正
接口设计大多由我们后端开发工程师完成,我们要遵循接口设计规范
1.粗粒度设计,根据原型图大致判断有几个接口,分别实现什么功能
2.细粒度设计,明确接口的功能
(1)需求分析:根据原型文档制作接口文档,并将不确定的接口与产品经理进行沟通
(2)接口四要素
- 请求路径:命名以模块的英文名称区分
- 请求方式(RESTful风格) Get(查),post(增),put(改),delete(查)
- 接口入参 路径参数(?以及Path(后端以Pathvariable注解接收)) Json格式请求体用DTO接受
- 返回参数 考虑全面,宁多不少,前端不需要的参数前端开发人员可以不出来(在不确定需要多少参数的时候)
我们在实现功能时,一些简单接口可以借助ai进行实现
第一步:获取表的建表语句
在数据库中new一个控制台
show create table "对应表名";粘贴查询到的查询语句
使用ai工具,将对应表结构复制到ai输入框,并补充要求:
例如:基于表结构,使用Springboot+mybatis生成CRUD操作,sql语句单独一个xml文件
ai会自动生成各个层次的代码:
但是我们要注意根据接口文档进行修改,比如:
controller层:传入参数是否全面?
service层:对表的逻辑处理是否到位?比如一些字段像创建时间修改时间这些逻辑需要我们手动添加
接口测试:
postman,apifox(问题是在工具里需要确定接口信息)
Swagger(接口文档)
为什么要有接口文档:现代企业开发通常采用前后端分离的架构,前后端沟通需要一个APi文档规范,而Swagger是一个动态变化的文档
Swagger是一个规范和完整的框架,用于生成,描述,调用和可视化Result风格的Web服务,它的作用是:
1.使前后端分离开发更加方便,有利于合作,因为前后端遵从同一个接口规范
2.接口的文档在线自动生成,降低后端开发人员编写接口文档的负担
3.功能测试,它可以模仿浏览器发送http请求
knife4j是JavaMVC继承Swagger生成Api文档的增强解决方案,kinife意思是像一把小刀一样小巧,轻量,强悍!现在开发中一般使用knife4j框架,它可以看 做Swagger文档的增强版
Api注解的说明
@Api 用在类上,描述Contoller的作用,比如这个controller是登录接口,用户接口?
@ApiOperation 用在方法上,说明方法的用途和作用
@ApiParam 用在方法的参数上,描述单个形参的含义(如路径参数,具体的参数)
@ApiImplicitParam 用在方法上,描述单个形参的含义,使用范围更广(哪些传入多个参数的请求参数,例如HttpRequest)(想具体了解区别可以在Ai搜索)
@ApiModel 用在类上,用对象来接受参数或者返回参数,描述类的含义(这个用在实体类例如User,UserDTO中)
@ApiModelProperty 用在类的属性上,用对象来接收参数或返回参数,描述字段的含义(同上,这个作用在类中的属性上)
举例
package com.zzyl.controller;import com.zzyl.base.ResponseResult;
import com.zzyl.dto.BedDto;
import com.zzyl.entity.Bed;
import com.zzyl.service.BedService;
import com.zzyl.utils.ObjectUtil;
import com.zzyl.vo.BedVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import java.util.List;@RestController
@RequestMapping("/bed")
@Api(tags = "床位管理相关接口")
public class BedController extends BaseController {@Autowiredprivate BedService bedService;@GetMapping("/read/room/{roomId}")@ApiOperation(value = "根据房间id查询床位", notes = "传入房间id")public ResponseResult<List<BedVo>> readBedByRoomId(@ApiParam(value = "房间ID", required = true) @PathVariable("roomId") Long roomId) {List<BedVo> beds = bedService.getBedsByRoomId(roomId);return success(beds);}/*** 创建床位* @param bedDto* @return*/@PostMapping("/create")@ApiOperation(value = "创建床位", notes = "传入床位信息")public ResponseResult createBed(@RequestBody BedDto bedDto) {bedService.createBed(bedDto);return success();}/*** 根据id查询床位* @param id* @return*/@GetMapping("/read/{id}")@ApiOperation(value = "根据id查询床位", notes = "传入床位id")public ResponseResult getBedById(@ApiParam (value = "床位ID", required = true)@PathVariable Long id) {BedVo bedVo = bedService.getBedById(id);if (ObjectUtil.isEmpty(bedVo)) {return ResponseResult.error("查询失败,床位信息为空");}return ResponseResult.success("操作成功",bedVo);}/*** 修改床位* @param bed* @return*/@PutMapping("/update")@ApiOperation(value = "修改床位", notes = "传入床位信息")public ResponseResult updateBed(@RequestBody Bed bed) {bedService.updateBed(bed);return success();}/*** 删除床位* @param id* @return*/@DeleteMapping("/delete/{id}")@ApiOperation(value = "删除床位", notes = "传入床位id")public ResponseResult deleteBed(@ApiParam (value = "床位ID", required = true) @PathVariable Long id) {bedService.deleteBed(id);return success();}}
package com.zzyl.entity;import com.zzyl.base.BaseEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;@Data
@ApiModel("床位")
public class Bed extends BaseEntity {/*** 床位编号*/@ApiModelProperty("床位编号")private String bedNumber;/*** 床位状态*/@ApiModelProperty(value = "床位状态: 未入住0, 已入住1",example = "0")private Integer bedStatus;/*** 房间ID*/@ApiModelProperty("房间ID")private Long roomId;/*** 排序号*/@ApiModelProperty(value = "排序号")private Integer sort;
}