基于Java的仓库管理系统设计与实现(二)
基于Java的仓库管理系统设计与实现(二)
1. 创建SpringBoot项目
IDEA创建SpringBoot项目,springBoot版本选择3.3.5,类型选择Maven项目,组和工件构成包名,这里分别写cn.xy21lin和wms_lin,java版本选择17,打包默认jar方式。
1.1 导入POM依赖
pom文件如下,注意依赖版本要对应,这里注释了SpringSecurity相关依赖,因为导入了SpringDoc,security可能会影响访问SpringDoc,后面做了相关配置再开启
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>cn.xy21lin</groupId>
<artifactId>wms_lin</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>wms_lin</name>
<description>wms_lin</description>
<url/>
<licenses>
<license/>
</licenses>
<developers>
<developer/>
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>
<properties>
<java.version>17</java.version>
<velocity.version>2.3</velocity.version>
<springdoc.version>2.2.0</springdoc.version>
<mybatis-plus.version>3.5.5</mybatis-plus.version>
<mysql-version>8.0.30</mysql-version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>${velocity.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.2.0</version>
</dependency>
<!-- <dependency> -->
<!-- <groupId>org.springframework.security</groupId> -->
<!-- <artifactId>spring-security-test</artifactId> -->
<!-- <scope>test</scope> -->
<!-- </dependency> -->
<!-- <dependency> -->
<!-- <groupId>org.springframework.boot</groupId> -->
<!-- <artifactId>spring-boot-starter-security</artifactId> -->
<!-- </dependency> -->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
1.2 生成代码-使用代码生成器
依赖导入了mybatis-plus相关依赖,所以直接使用mybatis-plus提供的代码生成器进行生成代码,这里在测试目录,也就是test/java/cn.xy21lin.wms_lin 下创建一个类进行代码生成。
- 创建代码生成器类:GenretorCode.java
package cn.xy21lin.wms_lin;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import javax.sql.DataSource;
import java.util.Collections;
@SpringBootTest
public class GenreatorCode {
// 作者
private static final String AUTHOR = "十一月的早晨";
/**
* 这里因为直接在yml文件里配置了数据源,所以直接依赖注入DataSource使用,也可以自己在这里再次进行配置
// JDBC配置
private static final String JDBC_URL = "jdbc:mysql://localhost:3306/wms_lin?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai";
// 账号
private static final String JDBC_USERNAME = "root";
// 密码
private static final String JDBC_PASSWORD = "";
*/
// 导出目录
private static final String OUT_FIR = ".\\src\\main\\java";
// 包名
private static final String PACKAGE_NAME = "cn.xy21lin.wms_lin";
// 数据库表
private static final String[] TABLES = {
"biz_category", "biz_client", "biz_inventory", "biz_product", "biz_stock_in",
"biz_stock_in_item", "biz_stock_out", "biz_stock_out_item",
"biz_supplier", "biz_warehouse", "sys_menu", "sys_role", "sys_user", "sys_role_menu"
};
// 过滤前缀
private static final String[] PREFIX = {"biz_","sys_"};
@Resource
DataSource dataSource;
@Test
void generator() {
// 创建代码生成器
FastAutoGenerator.create(new DataSourceConfig.Builder(dataSource))
.globalConfig(builder -> builder
// 设置作者
.author(AUTHOR)
// 启用Swagger注解,这里使用的SpringDoc,所以是这个命令,命令选不对,生成的注解不对应依赖,会报错
.enableSpringdoc()
// 设置输出目录
.outputDir(OUT_FIR)
)
.packageConfig(builder -> builder
// 设置父包名
.parent(PACKAGE_NAME)
// 设置Mapper XML文件输出路径
.pathInfo(Collections.singletonMap(OutputFile.xml, ".\\src\\main\\resources\\mapper"))
)
.strategyConfig(builder -> builder
// 添加需要生成的表
.addInclude(TABLES)
// 添加表前缀过滤
.addTablePrefix(PREFIX)
// 实体类配置
.entityBuilder()
// // 启用Lombok
.enableLombok()
// 启用链式模型
.enableChainModel()
// 控制器配置
.controllerBuilder()
// 启用REST风格
.enableRestStyle()
)
// 执行生成
.execute();
}
}
- 直接运行


编译通过,运行成功,这里我已经运行过了,所以提示文件已存在,还可以注意到生成的表biz_inventory和sys_role_menu存在多主键情况,所以需要对其进行修改。直接将表中@TableId注解修改为@TableField即可。
2. 配置yml文件
注意mysql依赖使用的是8.0版本,所以驱动名称为:
com.mysql.cj.jdbc.Driver
spring:
application:
name: wms
datasource:
url: jdbc:mysql://localhost:3306/数据库名?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
username: 帐号
password: 密码
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis-plus:
configuration:
# 开启sql日志记录
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 声明mapper.xml文件位置
mapper-locations: classpath*:mapper/**/*.xml
# 为实体类起别名,不需要去写全限定类名,直接使用category 这种别名
type-aliases-package: cn.xy21lin.wms_lin.entity
global-config:
db-config:
# 启用逻辑删除列
logic-delete-field: deleted
3. 配置Swagger3-openAPI
新建一个
config包,创建OpenAPIConfig类,用来编写Swagger3配置
@Configuration
public class OpenAPIConfig {
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.info(new Info()
.title("接口文档标题")
.description("SpringBoot3 集成 Swagger3接口文档")
.version("v1"))
.externalDocs(new ExternalDocumentation()
.description("项目API文档")
.url("/"));
}
}
4. 配置Mybatis-plus 分页插件
在
config包下,创建MybatisConfig类,编写分页插件,直接复制即可
package cn.xy21lin.wms_lin.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MybatisConfig {
/**
* 添加分页插件
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); // 如果配置多个插件, 切记分页最后添加
// 如果有多数据源可以不配具体类型, 否则都建议配上具体的 DbType
return interceptor;
}
}
5. 统一返回数据
新建
util包,创建ResultCode类,封装请求响应码,再创建Result类,统一返回数据格式。
ResultCode类
package cn.xy21lin.wms_lin.util;
public class ResultCode {
public static final int SUCCESS = 200; // 请求成功
public static final int ERROR = 400; // 请求错误,服务器无法理解
public static final int UNAUTHORIZED = 401; // 未授权,需要身份验证
public static final int FORBIDDEN = 403; // 禁止访问,权限不足
public static final int NOT_FOUND = 404; // 请求的资源不存在
public static final int METHOD_NOT_ALLOWED = 405; // 请求方法不被允许
public static final int REQUEST_TIMEOUT = 408; // 请求超时
public static final int INTERNAL_SERVER_ERROR = 500; // 服务器内部错误
}
Result类
package cn.xy21lin.wms_lin.util;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class Result<T> {
private Integer code;
private String message;
private T data;
private boolean success;
private Result(){}
// 只返回成功,适用于只关注操作结果,不关心返回数据
public static<T> Result<T> success(){
return new Result<T>().setCode(ResultCode.SUCCESS).setMessage("成功").setSuccess(true);
}
// 返回操作数据,关注操作结果和数据
public static<T> Result<T> success(T data){
return new Result<T>().setCode(ResultCode.SUCCESS).setMessage("成功").setSuccess(true).setData(data);
}
// 返回失败,失败消息可以自己调用后再进行填写
public static<T> Result<T> fail(){
return new Result<T>().setCode(ResultCode.ERROR).setMessage("失败").setSuccess(false);
}
}
6. 封装分页类
之前分页信息一直是在url显示,例如:/list?page=1&size=10,使用
@PostMapping("/{start}/{size}")配合@PathVariable int start, @PathVariable int size获取分页参数,这里不想采用这种方式,选择使用一个分页类,使用泛型,便于各实体类查询返回分页数据。
package cn.xy21lin.wms_lin.util;
import jakarta.validation.constraints.Min;
import lombok.Data;
@Data
public class PageUtil<T> {
// 确保合法输入
@Min(value = 1, message = "pageNum必须大于等于1")
private Integer pageNum;
// 确保合法输入
@Min(value = 1, message = "pageSize必须大于等于1")
private Integer pageSize;
// 使用泛型,增强代码复用性
private T data;
}
7. 测试分页
这里使用Category类,编写获取商品分类列表方法
- mapper
//获取商品分类列表
Page<Category> getCategoryList(Page<Category> page, Category category);
- service
//service接口
//获取商品分类列表
Page<Category> getCategoryList(Page<Category> page, Category category);
//service实现类
@Resource
CategoryMapper categoryMapper;
//返回商品分类列表
@Override
public Page<Category> getCategoryList(Page<Category> page, Category category) {
return categoryMapper.getCategoryList(page, category);
}
- controller
/**
* <p>
* 前端控制器
* </p>
*
* @author 十一月的早晨
* @since 2025-02-26
*/
@RestController
@RequestMapping("/category")
// 用于swagger文档显示
@Tag(description = "CategoryController", name = "类别管理")
public class CategoryController {
@Resource
ICategoryService categoryService;
// 使用post请求后,控制器接收并处理请求
@PostMapping("/list")
public Result getCategoryList(@Validated @RequestBody PageUtil<Category> category){
Page<Category> page = categoryService.getCategoryList(new Page<>(category.getPageNum(), category.getPageSize()), category.getData());
return Result.success().setMessage("获取成功").setData(page);
}
}
- 模拟请求发送
url : http://localhost:8080/category/list
post :
{
"pageNum": 1,
"pageSize": 2,
"data": {}
}
ua : content-type:application/json - 获取响应结果
{"code":200,"message":"获取成功","data":{"records":[{"id":1,"name":"食品","parentId":0,"level":1,"isDeleted":null},{"id":2,"name":"饮料","parentId":1,"level":2,"isDeleted":null}],"total":4,"size":2,"current":1,"pages":2},"success":true}
如果不想使用xml编写sql语句,简单的条件查询可以使用mybatis提供的QueryWrapper进行编写,例如:
public Page<Client> getClientList(Page<Client> page, Client client) {
QueryWrapper<Client> queryWrapper = new QueryWrapper<>();
queryWrapper.select("id","name","contact","phone","address","coop_start_date","coop_end_date")
.like(!StringUtils.isNullOrEmpty(client.getName()), "name", client.getName())
.like(!StringUtils.isNullOrEmpty(client.getContact()), "contact", client.getContact())
.like(!StringUtils.isNullOrEmpty(client.getPhone()), "phone", client.getPhone())
.like(!StringUtils.isNullOrEmpty(client.getAddress()), "address", client.getAddress());
return clientMapper.selectPage(page,queryWrapper);
}
注意:启动前,需要在启动类添加@MapperScan("cn.xy21lin.wms_lin")注解
这里再记录一个小问题,配置全部完成后,启动项目报错
Invalid bound statement (not found),很经典的错误,就是mapper映射问题,这里经过检查,发现是对应mapper.xml文件命名空间错误,因为之前生成包名为wms,重新修改后为wms_lin,但是由于文件已存在所以没有覆盖,导致xml文件命名空间中的包名和现存包名不一致,修改后即可成功运行。