在现代农业生产经营中,高效的库存管理是保障农产品流通效率、降低损耗的关键环节。传统的手工记录方式不仅效率低下,还容易导致数据不一致、库存更新不及时等问题。针对这一行业痛点,我们设计并实现了一套面向农产品流通领域的智能仓储管理平台,采用成熟的SSM技术栈构建,为企业提供从入库、出库到库存监控的全流程数字化解决方案。
系统架构与技术栈
该平台采用经典的三层架构设计,前端使用HTML、CSS和JavaScript构建用户界面,后端基于Spring+SpringMVC+MyBatis框架组合。Spring框架作为核心容器,管理业务逻辑层的对象生命周期和事务控制;SpringMVC负责Web请求的接收和响应处理;MyBatis则承担数据持久化职责,通过灵活的SQL映射实现高效的数据操作。
Maven作为项目构建工具,统一管理项目依赖。MySQL数据库存储业务数据,通过合理的表结构设计确保数据的一致性和完整性。整个系统采用模块化设计,各层之间职责分明,便于维护和扩展。
数据库设计亮点分析
物资表(goods)的设计优化
CREATE TABLE `goods` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`goods_name` varchar(200) DEFAULT NULL COMMENT '物品名字 Search111 ',
`goods_types` int(11) DEFAULT NULL COMMENT '物品种类 Search111 ',
`goods_number` int(11) DEFAULT NULL COMMENT '物资数量 Search111 ',
`goods_photo` varchar(200) DEFAULT NULL COMMENT '物品照片',
`danwei` varchar(200) DEFAULT NULL COMMENT '计量单位',
`goods_content` varchar(200) DEFAULT NULL COMMENT '物品详情',
`flag` int(11) DEFAULT NULL COMMENT '删除标志',
`create_time` timestamp NULL DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci COMMENT='物资'
该表设计体现了几个重要考量:首先使用flag字段实现逻辑删除,避免物理删除导致的数据丢失风险;goods_types字段通过字典表关联,实现物品种类的统一管理;goods_number字段实时记录库存数量,为库存预警提供数据基础。字符字段长度统一设置为200,既满足业务需求又避免过度分配存储空间。
出入库订单表(in_out_order)的业务逻辑设计
CREATE TABLE `in_out_order` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`order_name` varchar(200) DEFAULT NULL COMMENT '订单名 Search111 ',
`caozuo_name` varchar(200) DEFAULT NULL COMMENT '操作人姓名 Search111 ',
`caozuo_table` varchar(200) DEFAULT NULL COMMENT '操作人表名',
`order_types` int(11) DEFAULT NULL COMMENT '类型 Search111 ',
`insert_time` timestamp NULL DEFAULT NULL COMMENT '出入库时间 Search111 ',
`create_time` timestamp NULL DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci COMMENT='出入库订单'
该表通过order_types字段区分入库和出库操作,caozuo_name和caozuo_table记录了操作人信息,实现操作轨迹的完整追溯。时间戳字段的设计支持按时间范围查询,为统计分析提供便利。
字典表(dictionary)的系统扩展性设计
CREATE TABLE `dictionary` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`dic_code` varchar(200) DEFAULT NULL COMMENT '字典代码',
`dic_name` varchar(200) DEFAULT NULL COMMENT '字典名称',
`code_index` int(11) DEFAULT NULL COMMENT '编码索引',
`index_name` varchar(200) DEFAULT NULL COMMENT '索引名称',
`super_id` int(11) DEFAULT NULL COMMENT '父级ID',
`create_time` timestamp NULL DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci COMMENT='字典表'
字典表采用树形结构设计,通过super_id字段实现多级字典分类,支持系统的灵活扩展。这种设计使得新增业务类型时无需修改表结构,只需在字典表中添加相应记录即可。
核心功能实现
物资管理模块
物资管理是系统的核心功能之一,实现了农产品的全生命周期管理。管理员可以通过界面完成物资的添加、修改、查询和删除操作。

对应的实体类设计体现了业务对象的完整属性:
@Entity
@Table(name = "goods")
public class Goods implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "goods_name")
private String goodsName;
@Column(name = "goods_types")
private Integer goodsTypes;
@Column(name = "goods_number")
private Integer goodsNumber;
@Column(name = "goods_photo")
private String goodsPhoto;
private String danwei;
@Column(name = "goods_content")
private String goodsContent;
private Integer flag;
@Column(name = "create_time")
private Timestamp createTime;
// getter和setter方法
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getGoodsName() {
return goodsName;
}
public void setGoodsName(String goodsName) {
this.goodsName = goodsName;
}
// 其他getter和setter方法...
}
服务层代码实现了复杂的业务逻辑,包括库存校验、数量更新等:
@Service
public class GoodsService {
@Autowired
private GoodsMapper goodsMapper;
/**
* 更新物资数量
*/
@Transactional
public void updateGoodsNumber(Integer goodsId, Integer changeNumber, Integer operationType) {
Goods goods = goodsMapper.selectById(goodsId);
if (goods == null) {
throw new BusinessException("物资不存在");
}
Integer currentNumber = goods.getGoodsNumber();
Integer newNumber = currentNumber;
if (operationType == 1) { // 入库
newNumber = currentNumber + changeNumber;
} else if (operationType == 2) { // 出库
if (currentNumber < changeNumber) {
throw new BusinessException("库存不足");
}
newNumber = currentNumber - changeNumber;
}
goods.setGoodsNumber(newNumber);
goodsMapper.updateById(goods);
// 记录操作日志
recordOperationLog(goodsId, changeNumber, operationType);
}
private void recordOperationLog(Integer goodsId, Integer changeNumber, Integer operationType) {
// 记录详细的操作日志
}
}
出入库订单管理
出入库订单管理实现了农产品流通的精确追踪,每个操作都生成完整的订单记录。

控制器层处理前端请求,确保数据的完整性和一致性:
@RestController
@RequestMapping("/inOutOrder")
public class InOutOrderController {
@Autowired
private InOutOrderService inOutOrderService;
@PostMapping("/create")
public R createOrder(@RequestBody InOutOrder order, HttpServletRequest request) {
try {
// 设置操作人信息
String operator = getCurrentUser(request);
order.setCaozuoName(operator);
order.setCaozuoTable("yonghu");
order.setCreateTime(new Timestamp(System.currentTimeMillis()));
inOutOrderService.createOrder(order);
return R.ok().put("data", order);
} catch (Exception e) {
return R.error("创建订单失败: " + e.getMessage());
}
}
@GetMapping("/list")
public R getOrderList(@RequestParam Map<String, Object> params) {
PageUtils page = inOutOrderService.queryPage(params);
return R.ok().put("data", page);
}
private String getCurrentUser(HttpServletRequest request) {
// 从session或token中获取当前用户信息
return "admin"; // 示例代码
}
}
MyBatis的Mapper接口定义了数据操作的具体方法:
@Mapper
public interface InOutOrderMapper extends BaseMapper<InOutOrder> {
/**
* 自定义查询方法
*/
List<InOutOrder> selectByConditions(@Param("orderName") String orderName,
@Param("startTime") Date startTime,
@Param("endTime") Date endTime,
@Param("orderTypes") Integer orderTypes);
/**
* 分页查询
*/
List<InOutOrder> selectPageWithCustom(Map<String, Object> params);
}
对应的XML映射文件编写了灵活的SQL查询:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mapper.InOutOrderMapper">
<select id="selectByConditions" resultType="com.entity.InOutOrder">
SELECT * FROM in_out_order
WHERE 1=1
<if test="orderName != null and orderName != ''">
AND order_name LIKE CONCAT('%', #{orderName}, '%')
</if>
<if test="startTime != null">
AND insert_time >= #{startTime}
</if>
<if test="endTime != null">
AND insert_time <= #{endTime}
</if>
<if test="orderTypes != null">
AND order_types = #{orderTypes}
</if>
ORDER BY create_time DESC
</select>
</mapper>
委托出入库管理
委托出入库功能允许用户提交委托申请,管理员审核后执行实际操作,实现了权限分离和业务流程的规范化。

委托订单实体类扩展了基础订单功能:
@Entity
@Table(name = "entrust_in_out_order")
public class EntrustInOutOrder extends BaseEntity {
@Column(name = "yonghu_id")
private Integer yonghuId;
@Column(name = "order_name")
private String orderName;
@Column(name = "order_types")
private Integer orderTypes;
@Column(name = "insert_time")
private Timestamp insertTime;
@Column(name = "caozuo_name")
private String caozuoName;
@Column(name = "caozuo_table")
private String caozuoTable;
@Column(name = "caozuo_types")
private Integer caozuoTypes;
@Column(name = "update_time")
private Timestamp updateTime;
// 关联用户信息
@Transient
private String yonghuName;
@Transient
private String phone;
// getter和setter方法
}
用户管理与权限控制
系统支持多角色用户管理,不同角色具有不同的操作权限。

用户表设计包含了完整的个人信息字段:
CREATE TABLE `yonghu` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`username` varchar(200) DEFAULT NULL COMMENT '用户名',
`password` varchar(200) DEFAULT NULL COMMENT '密码',
`name` varchar(200) DEFAULT NULL COMMENT '姓名 Search111 ',
`phone` varchar(200) DEFAULT NULL COMMENT '手机号 Search111 ',
`id_number` varchar(200) DEFAULT NULL COMMENT '身份证号 Search111 ',
`sex_types` int(11) DEFAULT NULL COMMENT '性别',
`my_photo` varchar(200) DEFAULT NULL COMMENT '个人照片',
`nation` varchar(200) DEFAULT NULL COMMENT '民族',
`politics_types` int(11) DEFAULT NULL COMMENT '政治面貌',
`birthplace` varchar(200) DEFAULT NULL COMMENT '籍贯',
`create_time` timestamp NULL DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci COMMENT='用户'
Spring Security配置实现了基于角色的访问控制:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/user/**").hasAnyRole("USER", "ADMIN")
.antMatchers("/public/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
}
实体模型设计
系统采用领域驱动设计思想,实体类严格对应数据库表结构。基础实体类封装了通用属性:
public abstract class BaseEntity implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private Timestamp createTime;
private Timestamp updateTime;
// 通用方法
public boolean isNew() {
return this.id == null;
}
// getter和setter方法
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Timestamp getCreateTime() {
return createTime;
}
public void setCreateTime(Timestamp createTime) {
this.createTime = createTime;
}
public Timestamp getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Timestamp updateTime) {
this.updateTime = updateTime;
}
}
配置实体类展示了系统配置项的管理方式:
@TableName("config")
public class ConfigEntity implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(type = IdType.AUTO)
private Long id;
/**
* key
*/
private String name;
/**
* value
*/
private String value;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
功能展望与优化方向
1. 引入Redis缓存提升性能
当前系统在高并发场景下可能存在性能瓶颈。引入Redis作为缓存层,可以显著提升系统响应速度。
@Service
public class GoodsCacheService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private GoodsMapper goodsMapper;
private static final String GOODS_KEY_PREFIX = "goods:";
private static final long EXPIRATION_TIME = 3600; // 1小时
public Goods getGoodsById(Integer id) {
String key = GOODS_KEY_PREFIX + id;
Goods goods = (Goods) redisTemplate.opsForValue().get(key);
if (goods == null) {
goods = goodsMapper.selectById(id);
if (goods != null) {
redisTemplate.opsForValue().set(key, goods, EXPIRATION_TIME, TimeUnit.SECONDS);
}
}
return goods;
}
public void evictGoodsCache(Integer id) {
String key = GOODS_KEY_PREFIX + id;
redisTemplate.delete(key);
}
}
2. 消息队列实现异步处理
对于库存同步、报表生成等耗时操作,可以引入消息队列实现异步处理,提升用户体验。
@Component
public class InventoryMessageProducer {
@Autowired
private AmqpTemplate rabbitTemplate;
public void sendInventoryUpdateMessage(InventoryUpdateMessage message) {
rabbitTemplate.convertAndSend("inventory.exchange", "inventory.update", message);
}
}
@Component
public class InventoryMessageConsumer {
@Autowired
private InventoryService inventoryService;
@RabbitListener(queues = "inventory.update.queue")
public void processInventoryUpdate(InventoryUpdateMessage message) {
inventoryService.asyncUpdateInventory(message);
}
}
3. 微服务架构改造
随着业务复杂度增加,可以将单体应用拆分为微服务架构,提高系统的可维护性和扩展性。
# application.yml
spring:
application:
name: inventory-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
sentinel:
transport:
dashboard: localhost:8080
server:
port: 8081
# 库存服务配置
inventory:
update:
batch-size: 100
timeout: 5000
4. 移动端适配与PWA技术
开发移动端应用,支持PWA(渐进式Web应用)技术,提供接近原生应用的体验。
// service-worker.js
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open('inventory-v1').then((