一、工作内容
继续CURD,和前端对接口。(需求不明确而且没有接口文档真的很难顶)
二、功能实现
由于有比较多的相互关联的表,并且表都使用的逻辑删除(设置is_deleted标志位)所以需要的逻辑判断比较多,以及一些重复字段的存储、获取、联表等就会比较麻烦,所以需要设计好数据库表,最好明确需求。
注意HTTP请求参数的区别:
【接口测试】params传参与body传参区别-CSDN博客
各种优化方向:先和前端对接好吧啊啊啊啊啊啊啊。
三、工具使用
Jenkins(用于部署)
Jenkins 是一个开源的持续集成(Continuous Integration,CI)和持续交付(Continuous Delivery,CD)服务器,主要用于自动化软件开发过程中的各种任务,如构建、测试和部署。它最初由 Kohsuke Kawaguchi 在 2004 年创建,并在 2011 年从 Hudson 项目分叉出来,由于 Oracle 收购了 Sun Microsystems(Hudson 的初始托管者)后,Jenkins 社区决定独立发展。
Jenkins 的主要特点包括:
插件生态系统:Jenkins 拥有庞大的插件生态系统,支持几乎所有的构建、部署和自动化任务。这些插件可以扩展 Jenkins 的功能,让它能够与各种工具和服务集成,如版本控制系统(如 Git、Subversion)、构建工具(如 Maven、Gradle)、测试框架(如 JUnit、TestNG)、云服务提供商(如 AWS、Azure)等。
灵活性:Jenkins 可以运行在任何操作系统上,如 Windows、Linux 和 macOS,并且可以被配置为一个简单的服务器或一个分布式系统,使用多个节点进行大规模并行构建。
可扩展性:除了插件之外,Jenkins 还可以被扩展和定制,以适应特定的开发流程和需求。它支持使用 Jenkins Pipeline as Code 来定义构建流程,允许开发者使用 Groovy 脚本来描述整个 CI/CD 流程。
持续集成与持续交付:Jenkins 支持持续集成,即频繁地合并代码到主分支并自动构建和测试,以尽早发现集成问题。同时,它还支持持续交付,即在每次成功的构建后,将软件自动部署到测试或生产环境中,加速软件发布周期。
安全性:Jenkins 提供了多种安全特性,如用户权限管理、SSL/TLS 加密通信、防火墙规则等,以保护构建和部署过程的安全。
监控和报告:Jenkins 提供了详细的构建和测试报告,以及构建历史和趋势图表,帮助团队监控项目健康状况和性能。
Jenkins 的使用涉及创建项目(称为“Jobs”),配置源代码仓库、构建触发器、构建步骤、测试步骤和部署步骤。它还可以与 Slack、邮件通知等工具集成,以在构建状态变化时通知团队成员。
总的来说,Jenkins 是一个强大的工具,广泛应用于软件开发行业,帮助团队自动化和标准化软件开发流程,提高软件质量和开发效率。
YApi(用于接口编辑)
当接口文档用了
YApi 是一款强大的 API 管理工具,主要用于 API 的开发、测试、文档管理和版本控制。它提供了一个简洁的界面,允许开发者快速定义、编辑和管理 API 接口。YApi 支持前后端分离的开发模式,使得前端和后端开发人员可以协同工作,提高开发效率。
YApi 的主要特点:
API 文档自动生成: YApi 可以根据你定义的接口自动生成文档,包括请求参数、响应数据、示例请求和响应等,省去了手动编写文档的繁琐工作。
Mock 服务: YApi 内置了 Mock 服务,允许开发者在后端接口尚未完成时,使用模拟数据进行前端开发和测试,从而加速开发流程。
接口测试: YApi 提供了接口测试功能,可以直接在平台上发起请求,测试接口的正确性和性能,支持多种请求类型和参数格式。
团队协作: YApi 支持多人协作,可以创建项目和团队,实现接口的共享和权限管理。团队成员可以对 API 进行评论、点赞和收藏,促进团队沟通和知识分享。
版本控制: YApi 支持接口版本管理,可以创建和切换不同的版本,方便进行接口迭代和维护。
导出与导入: YApi 支持将项目数据导出为 JSON 文件,也可以从 JSON 文件导入数据,便于数据备份和迁移。
插件系统: YApi 提供了插件系统,可以安装和使用各种插件来扩展功能,如代码生成、数据校验等。
自定义主题: YApi 允许用户自定义界面主题,满足个性化需求。
使用场景:
API 开发与维护:YApi 作为 API 的开发平台,可以用于定义、测试和维护 API。
前后端协作:YApi 为前后端开发人员提供了一个共享平台,可以实时查看和更新 API 状态。
API 文档管理:YApi 自动生成的文档可以作为产品和开发团队之间的沟通桥梁。
测试与调试:YApi 的测试功能可以帮助 QA 和开发人员快速定位问题。
技术栈:
YApi 主要使用 Node.js 和 MongoDB 构建,前端使用 React 和 Redux。它支持在本地部署,也可以部署到云服务器上,为团队提供服务。
总之,YApi 是一款集 API 设计、开发、测试和文档管理于一体的工具,尤其适用于追求高效协作和敏捷开发的团队。
EasyCode
可以从database的table直接GenerateCode Spring格式的代码(包括dao、entity、service、controller)数据库访问层(Dao)与数据库访问实现是分开的,sql查询在resources/mapper.xml文件中,请注意sql语句是错误的需要修改!!!Dao层可以改为注解开发。
第三周新增:
手改sql语句好久才知道有模板可以直接解决的,不使用模板生成的sql语句没有逗号,
参考解决:EasyCode生成的SQL语句中无逗号分隔_easycode生成的xml没有逗号-CSDN博客
Easy Code的使用教程:Easy Code的使用教程(带模板)-CSDN博客
EasyCode 是阿里云推出的一款低代码开发平台,它通过可视化拖拽的方式帮助开发者快速构建应用,减少了传统编码的工作量,使得应用程序的开发更加高效和便捷。EasyCode 适合那些需要快速搭建应用原型或者完成轻量级项目的企业和个人开发者,特别是对于非技术背景的业务人员,他们可以通过 EasyCode 快速实现自己的业务逻辑而无需深入学习编程语言。
EasyCode 的主要特点:
可视化开发:EasyCode 提供了丰富的组件库,用户可以通过简单的拖拽操作来设计界面布局,无需编写复杂的代码。
自动代码生成:基于用户的设计和配置,EasyCode 能够自动生成相应的代码,大大简化了开发过程。
灵活的业务逻辑编辑器:EasyCode 提供了业务逻辑编辑器,用户可以使用简单的脚本语言来定制业务规则,处理数据流和事件。
集成阿里云服务:EasyCode 紧密集成阿里云的各项服务,如数据库、存储、安全、消息推送等,方便开发者使用这些服务来增强应用功能。
多端适配:EasyCode 支持开发跨平台的应用,包括 Web 应用、移动应用(Android 和 iOS)以及小程序,实现一次开发多端运行。
团队协作:EasyCode 支持团队协作开发,可以进行版本控制、权限管理和团队成员间的实时沟通。
模板和组件市场:EasyCode 拥有模板和组件市场,用户可以从中选择预设的模板和组件来加速开发过程。
数据分析与监控:EasyCode 提供应用的数据分析和监控功能,帮助开发者了解应用的运行状况和用户行为。
API 集成:除了内置的功能,EasyCode 还支持外部 API 的集成,可以调用第三方服务来扩展应用能力。
使用场景:
企业内部应用:EasyCode 可以用来快速开发企业内部管理应用,如 CRM、OA、项目管理等。
电商应用:可以利用 EasyCode 快速搭建电商平台、商品展示、购物车等功能。
数据报表和仪表盘:EasyCode 可以用于构建数据可视化仪表盘,帮助企业进行数据分析。
教育行业应用:如在线课程平台、学生管理系统等。
营销活动页面:EasyCode 也适用于创建营销活动的落地页,快速响应市场变化。
总之,EasyCode 旨在降低开发门槛,让不具备专业编程技能的人也能参与到应用开发中,同时为专业开发者提供一个高效的开发框架,加快项目交付速度。
四、问题记录
好消息:好多问题
坏消息:解决了所以一个都没记住
由此最大的问题就是应该及时形成书面文档记录问题
2024.08.11新增:
不同类的自动映射
想起来了一个问题,由于数据库的输入输出不需要所有的表字段,所以对不同表做了inputvo与outputvo,但是其中的字段映射都是纯手写的,后来发现有自动映射函数:
//UsersInputVo映射成Users
BeanUtils.copyProperties(UsersInputVo,Users);
//Users映射成UsersOutputVo
BeanUtils.copyProperties(Users,UsersOutputVo);
Page不分页
原本使用的pageinfo对查询到的数据进行分页处理,后来发现出现不分页的情况,参考博文PageInfo对处理过的list进行分页_pageinfo对list分页-CSDN博客发现是因为数据库查询语句与分页语句必须相邻:
但是由于查询出来的结果中间涉及到一个转为Output类的操作,所以必不可能相连,而且PageInfo中的许多字段是没有用的,所以自定义了一个PageBean类来返回 ,我的做法是直接参考PageInfo源码,复制一份删除不需要的字段,PageInfo源码如下:
package com.github.pagehelper;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
/**
* 对Page<E>结果进行包装
* <p/>
* 新增分页的多项属性,主要参考:http://bbs.csdn.net/topics/360010907
*
* @author liuzh/abel533/isea533
* @version 3.3.0
* @since 3.2.2
* 项目地址 : http://git.oschina.net/free/Mybatis_PageHelper
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public class PageInfo<T> implements Serializable {
private static final long serialVersionUID = 1L;
//当前页
private int pageNum;
//每页的数量
private int pageSize;
//当前页的数量
private int size;
//由于startRow和endRow不常用,这里说个具体的用法
//可以在页面中"显示startRow到endRow 共size条数据"
//当前页面第一个元素在数据库中的行号
private int startRow;
//当前页面最后一个元素在数据库中的行号
private int endRow;
//总记录数
private long total;
//总页数
private int pages;
//结果集
private List<T> list;
//前一页
private int prePage;
//下一页
private int nextPage;
//是否为第一页
private boolean isFirstPage = false;
//是否为最后一页
private boolean isLastPage = false;
//是否有前一页
private boolean hasPreviousPage = false;
//是否有下一页
private boolean hasNextPage = false;
//导航页码数
private int navigatePages;
//所有导航页号
private int[] navigatepageNums;
//导航条上的第一页
private int navigateFirstPage;
//导航条上的最后一页
private int navigateLastPage;
public PageInfo() {
}
/**
* 包装Page对象
*
* @param list
*/
public PageInfo(List<T> list) {
this(list, 8);
}
/**
* 包装Page对象
*
* @param list page结果
* @param navigatePages 页码数量
*/
public PageInfo(List<T> list, int navigatePages) {
if (list instanceof Page) {
Page page = (Page) list;
this.pageNum = page.getPageNum();
this.pageSize = page.getPageSize();
this.pages = page.getPages();
this.list = page;
this.size = page.size();
this.total = page.getTotal();
//由于结果是>startRow的,所以实际的需要+1
if (this.size == 0) {
this.startRow = 0;
this.endRow = 0;
} else {
this.startRow = page.getStartRow() + 1;
//计算实际的endRow(最后一页的时候特殊)
this.endRow = this.startRow - 1 + this.size;
}
} else if (list instanceof Collection) {
this.pageNum = 1;
this.pageSize = list.size();
this.pages = this.pageSize > 0 ? 1 : 0;
this.list = list;
this.size = list.size();
this.total = list.size();
this.startRow = 0;
this.endRow = list.size() > 0 ? list.size() - 1 : 0;
}
if (list instanceof Collection) {
this.navigatePages = navigatePages;
//计算导航页
calcNavigatepageNums();
//计算前后页,第一页,最后一页
calcPage();
//判断页面边界
judgePageBoudary();
}
}
/**
* 计算导航页
*/
private void calcNavigatepageNums() {
//当总页数小于或等于导航页码数时
if (pages <= navigatePages) {
navigatepageNums = new int[pages];
for (int i = 0; i < pages; i++) {
navigatepageNums[i] = i + 1;
}
} else { //当总页数大于导航页码数时
navigatepageNums = new int[navigatePages];
int startNum = pageNum - navigatePages / 2;
int endNum = pageNum + navigatePages / 2;
if (startNum < 1) {
startNum = 1;
//(最前navigatePages页
for (int i = 0; i < navigatePages; i++) {
navigatepageNums[i] = startNum++;
}
} else if (endNum > pages) {
endNum = pages;
//最后navigatePages页
for (int i = navigatePages - 1; i >= 0; i--) {
navigatepageNums[i] = endNum--;
}
} else {
//所有中间页
for (int i = 0; i < navigatePages; i++) {
navigatepageNums[i] = startNum++;
}
}
}
}
/**
* 计算前后页,第一页,最后一页
*/
private void calcPage() {
if (navigatepageNums != null && navigatepageNums.length > 0) {
navigateFirstPage = navigatepageNums[0];
navigateLastPage = navigatepageNums[navigatepageNums.length - 1];
if (pageNum > 1) {
prePage = pageNum - 1;
}
if (pageNum < pages) {
nextPage = pageNum + 1;
}
}
}
/**
* 判定页面边界
*/
private void judgePageBoudary() {
isFirstPage = pageNum == 1;
isLastPage = pageNum == pages || pages == 0;;
hasPreviousPage = pageNum > 1;
hasNextPage = pageNum < pages;
}
public int getPageNum() {
return pageNum;
}
public void setPageNum(int pageNum) {
this.pageNum = pageNum;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public int getStartRow() {
return startRow;
}
public void setStartRow(int startRow) {
this.startRow = startRow;
}
public int getEndRow() {
return endRow;
}
public void setEndRow(int endRow) {
this.endRow = endRow;
}
public long getTotal() {
return total;
}
public void setTotal(long total) {
this.total = total;
}
public int getPages() {
return pages;
}
public void setPages(int pages) {
this.pages = pages;
}
public List<T> getList() {
return list;
}
public void setList(List<T> list) {
this.list = list;
}
@Deprecated
// firstPage就是1, 此函数获取的是导航条上的第一页, 容易产生歧义
public int getFirstPage() {
return navigateFirstPage;
}
@Deprecated
public void setFirstPage(int firstPage) {
this.navigateFirstPage = firstPage;
}
public int getPrePage() {
return prePage;
}
public void setPrePage(int prePage) {
this.prePage = prePage;
}
public int getNextPage() {
return nextPage;
}
public void setNextPage(int nextPage) {
this.nextPage = nextPage;
}
@Deprecated
// 请用getPages()来获取最后一页, 此函数获取的是导航条上的最后一页, 容易产生歧义.
public int getLastPage() {
return navigateLastPage;
}
@Deprecated
public void setLastPage(int lastPage) {
this.navigateLastPage = lastPage;
}
public boolean isIsFirstPage() {
return isFirstPage;
}
public void setIsFirstPage(boolean isFirstPage) {
this.isFirstPage = isFirstPage;
}
public boolean isIsLastPage() {
return isLastPage;
}
public void setIsLastPage(boolean isLastPage) {
this.isLastPage = isLastPage;
}
public boolean isHasPreviousPage() {
return hasPreviousPage;
}
public void setHasPreviousPage(boolean hasPreviousPage) {
this.hasPreviousPage = hasPreviousPage;
}
public boolean isHasNextPage() {
return hasNextPage;
}
public void setHasNextPage(boolean hasNextPage) {
this.hasNextPage = hasNextPage;
}
public int getNavigatePages() {
return navigatePages;
}
public void setNavigatePages(int navigatePages) {
this.navigatePages = navigatePages;
}
public int[] getNavigatepageNums() {
return navigatepageNums;
}
public void setNavigatepageNums(int[] navigatepageNums) {
this.navigatepageNums = navigatepageNums;
}
public int getNavigateFirstPage() {
return navigateFirstPage;
}
public int getNavigateLastPage() {
return navigateLastPage;
}
public void setNavigateFirstPage(int navigateFirstPage) {
this.navigateFirstPage = navigateFirstPage;
}
public void setNavigateLastPage(int navigateLastPage) {
this.navigateLastPage = navigateLastPage;
}
@Override
public String toString() {
final StringBuffer sb = new StringBuffer("PageInfo{");
sb.append("pageNum=").append(pageNum);
sb.append(", pageSize=").append(pageSize);
sb.append(", size=").append(size);
sb.append(", startRow=").append(startRow);
sb.append(", endRow=").append(endRow);
sb.append(", total=").append(total);
sb.append(", pages=").append(pages);
sb.append(", list=").append(list);
sb.append(", prePage=").append(prePage);
sb.append(", nextPage=").append(nextPage);
sb.append(", isFirstPage=").append(isFirstPage);
sb.append(", isLastPage=").append(isLastPage);
sb.append(", hasPreviousPage=").append(hasPreviousPage);
sb.append(", hasNextPage=").append(hasNextPage);
sb.append(", navigatePages=").append(navigatePages);
sb.append(", navigateFirstPage=").append(navigateFirstPage);
sb.append(", navigateLastPage=").append(navigateLastPage);
sb.append(", navigatepageNums=");
if (navigatepageNums == null) sb.append("null");
else {
sb.append('[');
for (int i = 0; i < navigatepageNums.length; ++i)
sb.append(i == 0 ? "" : ", ").append(navigatepageNums[i]);
sb.append(']');
}
sb.append('}');
return sb.toString();
}
}
service层使用如下:
Users users = buildUsers(usersInputVo);
//范围查询
List<Users> usersList= usersDao.queryAllByLimit(users, (pageNum - 1) * pageSize, pageSize);
//users转usersOutputVo
List<UsersOutputVo> outputVoList = usersList.stream()
.map(this::convertToUsersOutputVo)
.collect(Collectors.toList());
PageBean<UsersOutputVo> pages= new PageBean<>(outputVoList);
long total=usersDao.count(users);
//总数据条数
pages.setTotal(total);
//总页数
pages.setPages((int)Math.ceil((double)total/pageSize));