ai
- 创建 Spring Boot 项目
可以使用 Spring Initializr(https://start.spring.io/) 来创建一个新的 Spring Boot 项目,添加以下依赖:
Spring Web
Spring Data JPA
MySQL Driver
Spring Boot DevTools(可选)
Thymeleaf(用于前端页面模板)
Spring Security(用于用户认证和授权)
2. 数据库设计
仓库表(Warehouse)
收起
sql
CREATE TABLE warehouse (
warehouse_id VARCHAR(20) PRIMARY KEY,
warehouse_name VARCHAR(100) NOT NULL,
address VARCHAR(200));
物资台账明细表(MaterialLedger)
收起
sql
CREATE TABLE material_ledger (
ledger_id VARCHAR(20) PRIMARY KEY,
material_code VARCHAR(20) NOT NULL,
material_name VARCHAR(100) NOT NULL,
specification VARCHAR(50),
material VARCHAR(50),
supplier VARCHAR(100),
brand VARCHAR(50),
category_id VARCHAR(20) NOT NULL,
operation_type ENUM('入库', '出库') NOT NULL,
quantity DECIMAL(10, 2) NOT NULL,
unit VARCHAR(10) NOT NULL,
warehouse_id VARCHAR(20) NOT NULL,
operation_date DATE NOT NULL,
FOREIGN KEY (warehouse_id) REFERENCES warehouse(warehouse_id),
FOREIGN KEY (category_id) REFERENCES material_category(category_id));
物资类别表(MaterialCategory)
收起
sql
CREATE TABLE material_category (
category_id VARCHAR(20) PRIMARY KEY,
material_name VARCHAR(100) NOT NULL,
specification VARCHAR(50),
material VARCHAR(50),
UNIQUE (material_name, specification, material));
3. 实体类设计
Warehouse.java
收起
java
import javax.persistence.Entity;import javax.persistence.Id;import javax.persistence.Table;
@Entity@Table(name = "warehouse")public class Warehouse {
@Id
private String warehouse_id;
private String warehouse_name;
private String address;
// Getters and Setters
public String getWarehouse_id() {
return warehouse_id;
}
public void setWarehouse_id(String warehouse_id) {
this.warehouse_id = warehouse_id;
}
public String getWarehouse_name() {
return warehouse_name;
}
public void setWarehouse_name(String warehouse_name) {
this.warehouse_name = warehouse_name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}}
MaterialLedger.java
收起
java
import javax.persistence.Entity;import javax.persistence.Id;import javax.persistence.JoinColumn;import javax.persistence.ManyToOne;import javax.persistence.Table;import java.math.BigDecimal;import java.util.Date;
@Entity@Table(name = "material_ledger")public class MaterialLedger {
@Id
private String ledger_id;
private String material_code;
private String material_name;
private String specification;
private String material;
private String supplier;
private String brand;
private String category_id;
private String operation_type;
private BigDecimal quantity;
private String unit;
private String warehouse_id;
private Date operation_date;
@ManyToOne
@JoinColumn(name = "warehouse_id")
private Warehouse warehouse;
// Getters and Setters
// ...}
MaterialCategory.java
收起
java
import javax.persistence.Entity;import javax.persistence.Id;import javax.persistence.Table;
@Entity@Table(name = "material_category")public class MaterialCategory {
@Id
private String category_id;
private String material_name;
private String specification;
private String material;
// Getters and Setters
// ...}
- 仓库接口(Repository)
WarehouseRepository.java
收起
java
import org.springframework.data.jpa.repository.JpaRepository;
public interface WarehouseRepository extends JpaRepository<Warehouse, String> {}
MaterialLedgerRepository.java
收起
java
import org.springframework.data.jpa.repository.JpaRepository;import org.springframework.data.jpa.repository.Query;import org.springframework.data.repository.query.Param;
import java.math.BigDecimal;
public interface MaterialLedgerRepository extends JpaRepository<MaterialLedger, String> {
@Query("SELECT SUM(CASE WHEN ml.operation_type = '入库' THEN ml.quantity ELSE -ml.quantity END) " +
"FROM MaterialLedger ml WHERE ml.material_code = :materialCode AND ml.warehouse_id = :warehouseId")
BigDecimal getInventoryBalance(@Param("materialCode") String materialCode, @Param("warehouseId") String warehouseId);
boolean existsByWarehouse_id(String warehouseId);
boolean existsByCategory_id(String categoryId);}
MaterialCategoryRepository.java
收起
java
import org.springframework.data.jpa.repository.JpaRepository;
public interface MaterialCategoryRepository extends JpaRepository<MaterialCategory, String> {
boolean existsByCategory_id(String categoryId);
boolean existsByMaterial_nameAndSpecificationAndMaterial(String materialName, String specification, String material);}
5. 服务层(Service)
WarehouseService.java
收起
java
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;
import java.util.List;
@Servicepublic class WarehouseService {
@Autowired
private WarehouseRepository warehouseRepository;
@Autowired
private MaterialLedgerRepository materialLedgerRepository;
public List<Warehouse> getAllWarehouses() {
return warehouseRepository.findAll();
}
public Warehouse getWarehouseById(String id) {
return warehouseRepository.findById(id).orElse(null);
}
public Warehouse saveWarehouse(Warehouse warehouse) {
return warehouseRepository.save(warehouse);
}
public void deleteWarehouse(String id) {
if (!materialLedgerRepository.existsByWarehouse_id(id)) {
warehouseRepository.deleteById(id);
} else {
throw new RuntimeException("该仓库中存在相关物资,不允许删除。");
}
}
public Warehouse updateWarehouse(Warehouse warehouse) {
if (!materialLedgerRepository.existsByWarehouse_id(warehouse.getWarehouse_id())) {
return warehouseRepository.save(warehouse);
} else {
throw new RuntimeException("该仓库中存在相关物资,不允许修改。");
}
}}
MaterialCategoryService.java
收起
java
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;
import java.util.List;
@Servicepublic class MaterialCategoryService {
@Autowired
private MaterialCategoryRepository materialCategoryRepository;
@Autowired
private MaterialLedgerRepository materialLedgerRepository;
public List<MaterialCategory> getAllMaterialCategories() {
return materialCategoryRepository.findAll();
}
public MaterialCategory getMaterialCategoryById(String id) {
return materialCategoryRepository.findById(id).orElse(null);
}
public MaterialCategory saveMaterialCategory(MaterialCategory category) {
if (materialCategoryRepository.existsByCategory_id(category.getCategory_id()) ||
materialCategoryRepository.existsByMaterial_nameAndSpecificationAndMaterial(
category.getMaterial_name(), category.getSpecification(), category.getMaterial())) {
throw new RuntimeException("物资分类编码已存在或物资名称、规格、材质组合重复,不允许添加。");
}
return materialCategoryRepository.save(category);
}
public void deleteMaterialCategory(String id) {
if (!materialLedgerRepository.existsByCategory_id(id)) {
materialCategoryRepository.deleteById(id);
} else {
throw new RuntimeException("物资台账明细表中存在该类物资,不允许删除。");
}
}
public MaterialCategory updateMaterialCategory(MaterialCategory category) {
if (!materialLedgerRepository.existsByCategory_id(category.getCategory_id())) {
return materialCategoryRepository.save(category);
} else {
throw new RuntimeException("物资台账明细表中存在该类物资,不允许修改。");
}
}}
MaterialLedgerService.java
收起
java
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;
import java.math.BigDecimal;
@Servicepublic class MaterialLedgerService {
@Autowired
private MaterialLedgerRepository materialLedgerRepository;
public MaterialLedger saveMaterialLedger(MaterialLedger ledger) {
return materialLedgerRepository.save(ledger);
}
public BigDecimal getInventoryBalance(String materialCode, String warehouseId) {
return materialLedgerRepository.getInventoryBalance(materialCode, warehouseId);
}}
- 控制器层(Controller)
WarehouseController.java
收起
java
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController@RequestMapping("/warehouses")public class WarehouseController {
@Autowired
private WarehouseService warehouseService;
@GetMapping
public List<Warehouse> getAllWarehouses() {
return warehouseService.getAllWarehouses();
}
@GetMapping("/{id}")
public Warehouse getWarehouseById(@PathVariable String id) {
return warehouseService.getWarehouseById(id);
}
@PostMapping
public Warehouse saveWarehouse(@RequestBody Warehouse warehouse) {
return warehouseService.saveWarehouse(warehouse);
}
@DeleteMapping("/{id}")
public void deleteWarehouse(@PathVariable String id) {
warehouseService.deleteWarehouse(id);
}
@PutMapping("/{id}")
public Warehouse updateWarehouse(@PathVariable String id, @RequestBody Warehouse warehouse) {
warehouse.setWarehouse_id(id);
return warehouseService.updateWarehouse(warehouse);
}}
MaterialCategoryController.java
收起
java
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController@RequestMapping("/material-categories")public class MaterialCategoryController {
@Autowired
private MaterialCategoryService materialCategoryService;
@GetMapping
public List<MaterialCategory> getAllMaterialCategories() {
return materialCategoryService.getAllMaterialCategories();
}
@GetMapping("/{id}")
public MaterialCategory getMaterialCategoryById(@PathVariable String id) {
return materialCategoryService.getMaterialCategoryById(id);
}
@PostMapping
public MaterialCategory saveMaterialCategory(@RequestBody MaterialCategory category) {
return materialCategoryService.saveMaterialCategory(category);
}
@DeleteMapping("/{id}")
public void deleteMaterialCategory(@PathVariable String id) {
materialCategoryService.deleteMaterialCategory(id);
}
@PutMapping("/{id}")
public MaterialCategory updateMaterialCategory(@PathVariable String id, @RequestBody MaterialCategory category) {
category.setCategory_id(id);
return materialCategoryService.updateMaterialCategory(category);
}}
MaterialLedgerController.java
收起
java
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
@RestController@RequestMapping("/material-ledgers")public class MaterialLedgerController {
@Autowired
private MaterialLedgerService materialLedgerService;
@PostMapping
public MaterialLedger saveMaterialLedger(@RequestBody MaterialLedger ledger) {
return materialLedgerService.saveMaterialLedger(ledger);
}
@GetMapping("/balance/{materialCode}/{warehouseId}")
public BigDecimal getInventoryBalance(@PathVariable String materialCode, @PathVariable String warehouseId) {
return materialLedgerService.getInventoryBalance(materialCode, warehouseId);
}}
- 前端页面设计
登录页面(login.html)
收起
html
<meta charset="UTF-8">
<title>登录</title>
<link rel="stylesheet" href="styles.css"></head><body>
<h1>仓储管理系统登录</h1>
<form action="#" th:action="@{/login}" method="post">
<label for="username">用户名:</label>
<input type="text" id="username" name="username" required><br>
<label for="password">密码:</label>
<input type="password" id="password" name="password" required><br>
<input type="submit" value="登录">
</form></body></html>
模板页面(layout.html)
收起
html
<meta charset="UTF-8">
<title>仓储管理系统</title>
<link rel="stylesheet" href="styles.css"></head><body>
<header>
<h1>仓储管理系统</h1>
<nav>
<ul>
<li th:if="${role == 'ADMIN'}"><a href="/warehouses">仓库管理</a></li>
<li th:if="${role == 'ADMIN'}"><a href="/material-categories">物资类别管理</a></li>
<li th:if="${role == 'WAREHOUSE_MANAGER'}"><a href="/incoming">入库操作</a></li>
<li th:if="${role == 'WAREHOUSE_MANAGER'}"><a href="/outgoing">出库操作</a></li>
<li th:if="${role == 'WAREHOUSE_MANAGER'}"><a href="/statistics">统计查询</a></li>
</ul>
</nav>
</header>
<main th:replace="${content}">
<!-- 内容将被替换 -->
</main>
<footer>
<p>版权所有 © 仓储管理系统</p>
</footer></body></html>
仓库管理页面(warehouses.html)
收起
html
<meta charset="UTF-8">
<title>仓库管理</title></head><body>
<h2>仓库管理</h2>
<a href="#" th:href="@{/warehouses/new}">新增仓库</a>
<table>
<thead>
<tr>
<th>仓库编号</th>
<th>仓库名称</th>
<th>仓库地址</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr th:each="warehouse : ${warehouses}">
<td th:text="${warehouse.warehouse_id}"></td>
<td th:text="${warehouse.warehouse_name}"></td>
<td th:text="${warehouse.address}"></td>
<td>
<a href="#" th:href="@{/warehouses/edit/{id}(id=${warehouse.warehouse_id})}">修改</a>
<a href="#" th:href="@{/warehouses/delete/{id}(id=${warehouse.warehouse_id})}">删除</a>
</td>
</tr>
</tbody>
</table></body></html>
- 安全配置(SecurityConfig.java)
收起
java
import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.security.config.annotation.web.builders.HttpSecurity;import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;import org.springframework.security.core.userdetails.User;import org.springframework.security.core.userdetails.UserDetails;import org.springframework.security.core.userdetails.UserDetailsService;import org.springframework.security.provisioning.InMemoryUserDetailsManager;import org.springframework.security.web.SecurityFilterChain;
@Configuration@EnableWebSecuritypublic class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/login").permitAll()
.antMatchers("/warehouses/**", "/material-categories/**").hasRole("ADMIN")
.antMatchers("/incoming", "/outgoing", "/statistics").hasRole("WAREHOUSE_MANAGER")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/")
.permitAll()
.and()
.logout()
.permitAll();
return http.build();
}
@Bean
public UserDetailsService userDetailsService() {
UserDetails admin = User.withDefaultPasswordEncoder()
.username("admin")
.password("admin")
.roles("ADMIN")1. 创建 Spring Boot 项目
可以使用 Spring Initializr(https://start.spring.io/) 来创建一个新的 Spring Boot 项目,添加以下依赖:
Spring Web
Spring Data JPA
MySQL Driver
Spring Boot DevTools(可选)
Thymeleaf(用于前端页面模板)
Spring Security(用于用户认证和授权)
2. 数据库设计
仓库表(Warehouse)
收起
sql
CREATE TABLE warehouse (
warehouse_id VARCHAR(20) PRIMARY KEY,
warehouse_name VARCHAR(100) NOT NULL,
address VARCHAR(200));
物资台账明细表(MaterialLedger)
收起
sql
CREATE TABLE material_ledger (
ledger_id VARCHAR(20) PRIMARY KEY,
material_code VARCHAR(20) NOT NULL,
material_name VARCHAR(100) NOT NULL,
specification VARCHAR(50),
material VARCHAR(50),
supplier VARCHAR(100),
brand VARCHAR(50),
category_id VARCHAR(20) NOT NULL,
operation_type ENUM('入库', '出库') NOT NULL,
quantity DECIMAL(10, 2) NOT NULL,
unit VARCHAR(10) NOT NULL,
warehouse_id VARCHAR(20) NOT NULL,
operation_date DATE NOT NULL,
FOREIGN KEY (warehouse_id) REFERENCES warehouse(warehouse_id),
FOREIGN KEY (category_id) REFERENCES material_category(category_id));
物资类别表(MaterialCategory)
收起
sql
CREATE TABLE material_category (
category_id VARCHAR(20) PRIMARY KEY,
material_name VARCHAR(100) NOT NULL,
specification VARCHAR(50),
material VARCHAR(50),
UNIQUE (material_name, specification, material));
3. 实体类设计
Warehouse.java
收起
java
import javax.persistence.Entity;import javax.persistence.Id;import javax.persistence.Table;
@Entity@Table(name = "warehouse")public class Warehouse {
@Id
private String warehouse_id;
private String warehouse_name;
private String address;
// Getters and Setters
public String getWarehouse_id() {
return warehouse_id;
}
public void setWarehouse_id(String warehouse_id) {
this.warehouse_id = warehouse_id;
}
public String getWarehouse_name() {
return warehouse_name;
}
public void setWarehouse_name(String warehouse_name) {
this.warehouse_name = warehouse_name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}}
MaterialLedger.java
收起
java
import javax.persistence.Entity;import javax.persistence.Id;import javax.persistence.JoinColumn;import javax.persistence.ManyToOne;import javax.persistence.Table;import java.math.BigDecimal;import java.util.Date;
@Entity@Table(name = "material_ledger")public class MaterialLedger {
@Id
private String ledger_id;
private String material_code;
private String material_name;
private String specification;
private String material;
private String supplier;
private String brand;
private String category_id;
private String operation_type;
private BigDecimal quantity;
private String unit;
private String warehouse_id;
private Date operation_date;
@ManyToOne
@JoinColumn(name = "warehouse_id")
private Warehouse warehouse;
// Getters and Setters
// ...}
MaterialCategory.java
收起
java
import javax.persistence.Entity;import javax.persistence.Id;import javax.persistence.Table;
@Entity@Table(name = "material_category")public class MaterialCategory {
@Id
private String category_id;
private String material_name;
private String specification;
private String material;
// Getters and Setters
// ...}
- 仓库接口(Repository)
WarehouseRepository.java
收起
java
import org.springframework.data.jpa.repository.JpaRepository;
public interface WarehouseRepository extends JpaRepository<Warehouse, String> {}
MaterialLedgerRepository.java
收起
java
import org.springframework.data.jpa.repository.JpaRepository;import org.springframework.data.jpa.repository.Query;import org.springframework.data.repository.query.Param;
import java.math.BigDecimal;
public interface MaterialLedgerRepository extends JpaRepository<MaterialLedger, String> {
@Query("SELECT SUM(CASE WHEN ml.operation_type = '入库' THEN ml.quantity ELSE -ml.quantity END) " +
"FROM MaterialLedger ml WHERE ml.material_code = :materialCode AND ml.warehouse_id = :warehouseId")
BigDecimal getInventoryBalance(@Param("materialCode") String materialCode, @Param("warehouseId") String warehouseId);
boolean existsByWarehouse_id(String warehouseId);
boolean existsByCategory_id(String categoryId);}
MaterialCategoryRepository.java
收起
java
import org.springframework.data.jpa.repository.JpaRepository;
public interface MaterialCategoryRepository extends JpaRepository<MaterialCategory, String> {
boolean existsByCategory_id(String categoryId);
boolean existsByMaterial_nameAndSpecificationAndMaterial(String materialName, String specification, String material);}
5. 服务层(Service)
WarehouseService.java
收起
java
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;
import java.util.List;
@Servicepublic class WarehouseService {
@Autowired
private WarehouseRepository warehouseRepository;
@Autowired
private MaterialLedgerRepository materialLedgerRepository;
public List<Warehouse> getAllWarehouses() {
return warehouseRepository.findAll();
}
public Warehouse getWarehouseById(String id) {
return warehouseRepository.findById(id).orElse(null);
}
public Warehouse saveWarehouse(Warehouse warehouse) {
return warehouseRepository.save(warehouse);
}
public void deleteWarehouse(String id) {
if (!materialLedgerRepository.existsByWarehouse_id(id)) {
warehouseRepository.deleteById(id);
} else {
throw new RuntimeException("该仓库中存在相关物资,不允许删除。");
}
}
public Warehouse updateWarehouse(Warehouse warehouse) {
if (!materialLedgerRepository.existsByWarehouse_id(warehouse.getWarehouse_id())) {
return warehouseRepository.save(warehouse);
} else {
throw new RuntimeException("该仓库中存在相关物资,不允许修改。");
}
}}
MaterialCategoryService.java
收起
java
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;
import java.util.List;
@Servicepublic class MaterialCategoryService {
@Autowired
private MaterialCategoryRepository materialCategoryRepository;
@Autowired
private MaterialLedgerRepository materialLedgerRepository;
public List<MaterialCategory> getAllMaterialCategories() {
return materialCategoryRepository.findAll();
}
public MaterialCategory getMaterialCategoryById(String id) {
return materialCategoryRepository.findById(id).orElse(null);
}
public MaterialCategory saveMaterialCategory(MaterialCategory category) {
if (materialCategoryRepository.existsByCategory_id(category.getCategory_id()) ||
materialCategoryRepository.existsByMaterial_nameAndSpecificationAndMaterial(
category.getMaterial_name(), category.getSpecification(), category.getMaterial())) {
throw new RuntimeException("物资分类编码已存在或物资名称、规格、材质组合重复,不允许添加。");
}
return materialCategoryRepository.save(category);
}
public void deleteMaterialCategory(String id) {
if (!materialLedgerRepository.existsByCategory_id(id)) {
materialCategoryRepository.deleteById(id);
} else {
throw new RuntimeException("物资台账明细表中存在该类物资,不允许删除。");
}
}
public MaterialCategory updateMaterialCategory(MaterialCategory category) {
if (!materialLedgerRepository.existsByCategory_id(category.getCategory_id())) {
return materialCategoryRepository.save(category);
} else {
throw new RuntimeException("物资台账明细表中存在该类物资,不允许修改。");
}
}}
MaterialLedgerService.java
收起
java
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;
import java.math.BigDecimal;
@Servicepublic class MaterialLedgerService {
@Autowired
private MaterialLedgerRepository materialLedgerRepository;
public MaterialLedger saveMaterialLedger(MaterialLedger ledger) {
return materialLedgerRepository.save(ledger);
}
public BigDecimal getInventoryBalance(String materialCode, String warehouseId) {
return materialLedgerRepository.getInventoryBalance(materialCode, warehouseId);
}}
- 控制器层(Controller)
WarehouseController.java
收起
java
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController@RequestMapping("/warehouses")public class WarehouseController {
@Autowired
private WarehouseService warehouseService;
@GetMapping
public List<Warehouse> getAllWarehouses() {
return warehouseService.getAllWarehouses();
}
@GetMapping("/{id}")
public Warehouse getWarehouseById(@PathVariable String id) {
return warehouseService.getWarehouseById(id);
}
@PostMapping
public Warehouse saveWarehouse(@RequestBody Warehouse warehouse) {
return warehouseService.saveWarehouse(warehouse);
}
@DeleteMapping("/{id}")
public void deleteWarehouse(@PathVariable String id) {
warehouseService.deleteWarehouse(id);
}
@PutMapping("/{id}")
public Warehouse updateWarehouse(@PathVariable String id, @RequestBody Warehouse warehouse) {
warehouse.setWarehouse_id(id);
return warehouseService.updateWarehouse(warehouse);
}}
MaterialCategoryController.java
收起
java
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController@RequestMapping("/material-categories")public class MaterialCategoryController {
@Autowired
private MaterialCategoryService materialCategoryService;
@GetMapping
public List<MaterialCategory> getAllMaterialCategories() {
return materialCategoryService.getAllMaterialCategories();
}
@GetMapping("/{id}")
public MaterialCategory getMaterialCategoryById(@PathVariable String id) {
return materialCategoryService.getMaterialCategoryById(id);
}
@PostMapping
public MaterialCategory saveMaterialCategory(@RequestBody MaterialCategory category) {
return materialCategoryService.saveMaterialCategory(category);
}
@DeleteMapping("/{id}")
public void deleteMaterialCategory(@PathVariable String id) {
materialCategoryService.deleteMaterialCategory(id);
}
@PutMapping("/{id}")
public MaterialCategory updateMaterialCategory(@PathVariable String id, @RequestBody MaterialCategory category) {
category.setCategory_id(id);
return materialCategoryService.updateMaterialCategory(category);
}}
MaterialLedgerController.java
收起
java
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
@RestController@RequestMapping("/material-ledgers")public class MaterialLedgerController {
@Autowired
private MaterialLedgerService materialLedgerService;
@PostMapping
public MaterialLedger saveMaterialLedger(@RequestBody MaterialLedger ledger) {
return materialLedgerService.saveMaterialLedger(ledger);
}
@GetMapping("/balance/{materialCode}/{warehouseId}")
public BigDecimal getInventoryBalance(@PathVariable String materialCode, @PathVariable String warehouseId) {
return materialLedgerService.getInventoryBalance(materialCode, warehouseId);
}}
- 前端页面设计
登录页面(login.html)
收起
html
<meta charset="UTF-8">
<title>登录</title>
<link rel="stylesheet" href="styles.css"></head><body>
<h1>仓储管理系统登录</h1>
<form action="#" th:action="@{/login}" method="post">
<label for="username">用户名:</label>
<input type="text" id="username" name="username" required><br>
<label for="password">密码:</label>
<input type="password" id="password" name="password" required><br>
<input type="submit" value="登录">
</form></body></html>
模板页面(layout.html)
收起
html
<meta charset="UTF-8">
<title>仓储管理系统</title>
<link rel="stylesheet" href="styles.css"></head><body>
<header>
<h1>仓储管理系统</h1>
<nav>
<ul>
<li th:if="${role == 'ADMIN'}"><a href="/warehouses">仓库管理</a></li>
<li th:if="${role == 'ADMIN'}"><a href="/material-categories">物资类别管理</a></li>
<li th:if="${role == 'WAREHOUSE_MANAGER'}"><a href="/incoming">入库操作</a></li>
<li th:if="${role == 'WAREHOUSE_MANAGER'}"><a href="/outgoing">出库操作</a></li>
<li th:if="${role == 'WAREHOUSE_MANAGER'}"><a href="/statistics">统计查询</a></li>
</ul>
</nav>
</header>
<main th:replace="${content}">
<!-- 内容将被替换 -->
</main>
<footer>
<p>版权所有 © 仓储管理系统</p>
</footer></body></html>
仓库管理页面(warehouses.html)
收起
html
<meta charset="UTF-8">
<title>仓库管理</title></head><body>
<h2>仓库管理</h2>
<a href="#" th:href="@{/warehouses/new}">新增仓库</a>
<table>
<thead>
<tr>
<th>仓库编号</th>
<th>仓库名称</th>
<th>仓库地址</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr th:each="warehouse : ${warehouses}">
<td th:text="${warehouse.warehouse_id}"></td>
<td th:text="${warehouse.warehouse_name}"></td>
<td th:text="${warehouse.address}"></td>
<td>
<a href="#" th:href="@{/warehouses/edit/{id}(id=${warehouse.warehouse_id})}">修改</a>
<a href="#" th:href="@{/warehouses/delete/{id}(id=${warehouse.warehouse_id})}">删除</a>
</td>
</tr>
</tbody>
</table></body></html>
- 安全配置(SecurityConfig.java)
收起
java
import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.security.config.annotation.web.builders.HttpSecurity;import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;import org.springframework.security.core.userdetails.User;import org.springframework.security.core.userdetails.UserDetails;import org.springframework.security.core.userdetails.UserDetailsService;import org.springframework.security.provisioning.InMemoryUserDetailsManager;import org.springframework.security.web.SecurityFilterChain;
@Configuration@EnableWebSecuritypublic class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/login").permitAll()
.antMatchers("/warehouses/**", "/material-categories/**").hasRole("ADMIN")
.antMatchers("/incoming", "/outgoing", "/statistics").hasRole("WAREHOUSE_MANAGER")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/")
.permitAll()
.and()
.logout()
.permitAll();
return http.build();
}
@Bean
public UserDetailsService userDetailsService() {
UserDetails admin = User.withDefaultPasswordEncoder()
.username("admin")
.password("admin")
.roles("ADMIN")
.build();
UserDetails warehouseManager = User.withDefaultPasswordEncoder()
.username("manager")
.password("manager")
.roles("WAREHOUSE_MANAGER")
.build();
return new InMemoryUserDetailsManager(admin, warehouseManager);
}}
- 主应用类(WarehouseManagementSystemApplication.java)
收起
java
import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplicationpublic class WarehouseManagementSystemApplication {
public static void main(String[] args) {
SpringApplication.run(W1. 创建 Spring Boot 项目
可以使用 Spring Initializr(https://start.spring.io/) 来创建一个新的 Spring Boot 项目,添加以下依赖:
Spring Web
Spring Data JPA
MySQL Driver
Spring Boot DevTools(可选)
Thymeleaf(用于前端页面模板)
Spring Security(用于用户认证和授权)
2. 数据库设计
仓库表(Warehouse)
收起
sql
CREATE TABLE warehouse (
warehouse_id VARCHAR(20) PRIMARY KEY,
warehouse_name VARCHAR(100) NOT NULL,
address VARCHAR(200));
物资台账明细表(MaterialLedger)
收起
sql
CREATE TABLE material_ledger (
ledger_id VARCHAR(20) PRIMARY KEY,
material_code VARCHAR(20) NOT NULL,
material_name VARCHAR(100) NOT NULL,
specification VARCHAR(50),
material VARCHAR(50),
supplier VARCHAR(100),
brand VARCHAR(50),
category_id VARCHAR(20) NOT NULL,
operation_type ENUM('入库', '出库') NOT NULL,
quantity DECIMAL(10, 2) NOT NULL,
unit VARCHAR(10) NOT NULL,
warehouse_id VARCHAR(20) NOT NULL,
operation_date DATE NOT NULL,
FOREIGN KEY (warehouse_id) REFERENCES warehouse(warehouse_id),
FOREIGN KEY (category_id) REFERENCES material_category(category_id));
物资类别表(MaterialCategory)
收起
sql
CREATE TABLE material_category (
category_id VARCHAR(20) PRIMARY KEY,
material_name VARCHAR(100) NOT NULL,
specification VARCHAR(50),
material VARCHAR(50),
UNIQUE (material_name, specification, material));
3. 实体类设计
Warehouse.java
收起
java
import javax.persistence.Entity;import javax.persistence.Id;import javax.persistence.Table;
@Entity@Table(name = "warehouse")public class Warehouse {
@Id
private String warehouse_id;
private String warehouse_name;
private String address;
// Getters and Setters
public String getWarehouse_id() {
return warehouse_id;
}
public void setWarehouse_id(String warehouse_id) {
this.warehouse_id = warehouse_id;
}
public String getWarehouse_name() {
return warehouse_name;
}
public void setWarehouse_name(String warehouse_name) {
this.warehouse_name = warehouse_name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}}
MaterialLedger.java
收起
java
import javax.persistence.Entity;import javax.persistence.Id;import javax.persistence.JoinColumn;import javax.persistence.ManyToOne;import javax.persistence.Table;import java.math.BigDecimal;import java.util.Date;
@Entity@Table(name = "material_ledger")public class MaterialLedger {
@Id
private String ledger_id;
private String material_code;
private String material_name;
private String specification;
private String material;
private String supplier;
private String brand;
private String category_id;
private String operation_type;
private BigDecimal quantity;
private String unit;
private String warehouse_id;
private Date operation_date;
@ManyToOne
@JoinColumn(name = "warehouse_id")
private Warehouse warehouse;
// Getters and Setters
// ...}
MaterialCategory.java
收起
java
import javax.persistence.Entity;import javax.persistence.Id;import javax.persistence.Table;
@Entity@Table(name = "material_category")public class MaterialCategory {
@Id
private String category_id;
private String material_name;
private String specification;
private String material;
// Getters and Setters
// ...}
- 仓库接口(Repository)
WarehouseRepository.java
收起
java
import org.springframework.data.jpa.repository.JpaRepository;
public interface WarehouseRepository extends JpaRepository<Warehouse, String> {}
MaterialLedgerRepository.java
收起
java
import org.springframework.data.jpa.repository.JpaRepository;import org.springframework.data.jpa.repository.Query;import org.springframework.data.repository.query.Param;
import java.math.BigDecimal;
public interface MaterialLedgerRepository extends JpaRepository<MaterialLedger, String> {
@Query("SELECT SUM(CASE WHEN ml.operation_type = '入库' THEN ml.quantity ELSE -ml.quantity END) " +
"FROM MaterialLedger ml WHERE ml.material_code = :materialCode AND ml.warehouse_id = :warehouseId")
BigDecimal getInventoryBalance(@Param("materialCode") String materialCode, @Param("warehouseId") String warehouseId);
boolean existsByWarehouse_id(String warehouseId);
boolean existsByCategory_id(String categoryId);}
MaterialCategoryRepository.java
收起
java
import org.springframework.data.jpa.repository.JpaRepository;
public interface MaterialCategoryRepository extends JpaRepository<MaterialCategory, String> {
boolean existsByCategory_id(String categoryId);
boolean existsByMaterial_nameAndSpecificationAndMaterial(String materialName, String specification, String material);}
5. 服务层(Service)
WarehouseService.java
收起
java
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;
import java.util.List;
@Servicepublic class WarehouseService {
@Autowired
private WarehouseRepository warehouseRepository;
@Autowired
private MaterialLedgerRepository materialLedgerRepository;
public List<Warehouse> getAllWarehouses() {
return warehouseRepository.findAll();
}
public Warehouse getWarehouseById(String id) {
return warehouseRepository.findById(id).orElse(null);
}
public Warehouse saveWarehouse(Warehouse warehouse) {
return warehouseRepository.save(warehouse);
}
public void deleteWarehouse(String id) {
if (!materialLedgerRepository.existsByWarehouse_id(id)) {
warehouseRepository.deleteById(id);
} else {
throw new RuntimeException("该仓库中存在相关物资,不允许删除。");
}
}
public Warehouse updateWarehouse(Warehouse warehouse) {
if (!materialLedgerRepository.existsByWarehouse_id(warehouse.getWarehouse_id())) {
return warehouseRepository.save(warehouse);
} else {
throw new RuntimeException("该仓库中存在相关物资,不允许修改。");
}
}}
MaterialCategoryService.java
收起
java
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;
import java.util.List;
@Servicepublic class MaterialCategoryService {
@Autowired
private MaterialCategoryRepository materialCategoryRepository;
@Autowired
private MaterialLedgerRepository materialLedgerRepository;
public List<MaterialCategory> getAllMaterialCategories() {
return materialCategoryRepository.findAll();
}
public MaterialCategory getMaterialCategoryById(String id) {
return materialCategoryRepository.findById(id).orElse(null);
}
public MaterialCategory saveMaterialCategory(MaterialCategory category) {
if (materialCategoryRepository.existsByCategory_id(category.getCategory_id()) ||
materialCategoryRepository.existsByMaterial_nameAndSpecificationAndMaterial(
category.getMaterial_name(), category.getSpecification(), category.getMaterial())) {
throw new RuntimeException("物资分类编码已存在或物资名称、规格、材质组合重复,不允许添加。");
}
return materialCategoryRepository.save(category);
}
public void deleteMaterialCategory(String id) {
if (!materialLedgerRepository.existsByCategory_id(id)) {
materialCategoryRepository.deleteById(id);
} else {
throw new RuntimeException("物资台账明细表中存在该类物资,不允许删除。");
}
}
public MaterialCategory updateMaterialCategory(MaterialCategory category) {
if (!materialLedgerRepository.existsByCategory_id(category.getCategory_id())) {
return materialCategoryRepository.save(category);
} else {
throw new RuntimeException("物资台账明细表中存在该类物资,不允许修改。");
}
}}
MaterialLedgerService.java
收起
java
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;
import java.math.BigDecimal;
@Servicepublic class MaterialLedgerService {
@Autowired
private MaterialLedgerRepository materialLedgerRepository;
public MaterialLedger saveMaterialLedger(MaterialLedger ledger) {
return materialLedgerRepository.save(ledger);
}
public BigDecimal getInventoryBalance(String materialCode, String warehouseId) {
return materialLedgerRepository.getInventoryBalance(materialCode, warehouseId);
}}
- 控制器层(Controller)
WarehouseController.java
收起
java
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController@RequestMapping("/warehouses")public class WarehouseController {
@Autowired
private WarehouseService warehouseService;
@GetMapping
public List<Warehouse> getAllWarehouses() {
return warehouseService.getAllWarehouses();
}
@GetMapping("/{id}")
public Warehouse getWarehouseById(@PathVariable String id) {
return warehouseService.getWarehouseById(id);
}
@PostMapping
public Warehouse saveWarehouse(@RequestBody Warehouse warehouse) {
return warehouseService.saveWarehouse(warehouse);
}
@DeleteMapping("/{id}")
public void deleteWarehouse(@PathVariable String id) {
warehouseService.deleteWarehouse(id);
}
@PutMapping("/{id}")
public Warehouse updateWarehouse(@PathVariable String id, @RequestBody Warehouse warehouse) {
warehouse.setWarehouse_id(id);
return warehouseService.updateWarehouse(warehouse);
}}
MaterialCategoryController.java
收起
java
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController@RequestMapping("/material-categories")public class MaterialCategoryController {
@Autowired
private MaterialCategoryService materialCategoryService;
@GetMapping
public List<MaterialCategory> getAllMaterialCategories() {
return materialCategoryService.getAllMaterialCategories();
}
@GetMapping("/{id}")
public MaterialCategory getMaterialCategoryById(@PathVariable String id) {
return materialCategoryService.getMaterialCategoryById(id);
}
@PostMapping
public MaterialCategory saveMaterialCategory(@RequestBody MaterialCategory category) {
return materialCategoryService.saveMaterialCategory(category);
}
@DeleteMapping("/{id}")
public void deleteMaterialCategory(@PathVariable String id) {
materialCategoryService.deleteMaterialCategory(id);
}
@PutMapping("/{id}")
public MaterialCategory updateMaterialCategory(@PathVariable String id, @RequestBody MaterialCategory category) {
category.setCategory_id(id);
return materialCategoryService.updateMaterialCategory(category);
}}
MaterialLedgerController.java
收起
java
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
@RestController@RequestMapping("/material-ledgers")public class MaterialLedgerController {
@Autowired
private MaterialLedgerService materialLedgerService;
@PostMapping
public MaterialLedger saveMaterialLedger(@RequestBody MaterialLedger ledger) {
return materialLedgerService.saveMaterialLedger(ledger);
}
@GetMapping("/balance/{materialCode}/{warehouseId}")
public BigDecimal getInventoryBalance(@PathVariable String materialCode, @PathVariable String warehouseId) {
return materialLedgerService.getInventoryBalance(materialCode, warehouseId);
}}
- 前端页面设计
登录页面(login.html)
收起
html
<meta charset="UTF-8">
<title>登录</title>
<link rel="stylesheet" href="styles.css"></head><body>
<h1>仓储管理系统登录</h1>
<form action="#" th:action="@{/login}" method="post">
<label for="username">用户名:</label>
<input type="text" id="username" name="username" required><br>
<label for="password">密码:</label>
<input type="password" id="password" name="password" required><br>
<input type="submit" value="登录">
</form></body></html>
模板页面(layout.html)
收起
html
<meta charset="UTF-8">
<title>仓储管理系统</title>
<link rel="stylesheet" href="styles.css"></head><body>
<header>
<h1>仓储管理系统</h1>
<nav>
<ul>
<li th:if="${role == 'ADMIN'}"><a href="/warehouses">仓库管理</a></li>
<li th:if="${role == 'ADMIN'}"><a href="/material-categories">物资类别管理</a></li>
<li th:if="${role == 'WAREHOUSE_MANAGER'}"><a href="/incoming">入库操作</a></li>
<li th:if="${role == 'WAREHOUSE_MANAGER'}"><a href="/outgoing">出库操作</a></li>
<li th:if="${role == 'WAREHOUSE_MANAGER'}"><a href="/statistics">统计查询</a></li>
</ul>
</nav>
</header>
<main th:replace="${content}">
<!-- 内容将被替换 -->
</main>
<footer>
<p>版权所有 © 仓储管理系统</p>
</footer></body></html>
仓库管理页面(warehouses.html)
收起
html
<meta charset="UTF-8">
<title>仓库管理</title></head><body>
<h2>仓库管理</h2>
<a href="#" th:href="@{/warehouses/new}">新增仓库</a>
<table>
<thead>
<tr>
<th>仓库编号</th>
<th>仓库名称</th>
<th>仓库地址</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr th:each="warehouse : ${warehouses}">
<td th:text="${warehouse.warehouse_id}"></td>
<td th:text="${warehouse.warehouse_name}"></td>
<td th:text="${warehouse.address}"></td>
<td>
<a href="#" th:href="@{/warehouses/edit/{id}(id=${warehouse.warehouse_id})}">修改</a>
<a href="#" th:href="@{/warehouses/delete/{id}(id=${warehouse.warehouse_id})}">删除</a>
</td>
</tr>
</tbody>
</table></body></html>
- 安全配置(SecurityConfig.java)
收起
java
import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.security.config.annotation.web.builders.HttpSecurity;import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;import org.springframework.security.core.userdetails.User;import org.springframework.security.core.userdetails.UserDetails;import org.springframework.security.core.userdetails.UserDetailsService;import org.springframework.security.provisioning.InMemoryUserDetailsManager;import org.springframework.security.web.SecurityFilterChain;
@Configuration@EnableWebSecuritypublic class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/login").permitAll()
.antMatchers("/warehouses/**", "/material-categories/**").hasRole("ADMIN")
.antMatchers("/incoming", "/outgoing", "/statistics").hasRole("WAREHOUSE_MANAGER")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/")
.permitAll()
.and()
.logout()
.permitAll();
return http.build();
}
@Bean
public UserDetailsService userDetailsService() {
UserDetails admin = User.withDefaultPasswordEncoder()
.username("admin")
.password("admin")
.roles("ADMIN")
.build();
UserDetails warehouseManager = User.withDefaultPasswordEncoder()
.username("manager")
.password("manager")
.roles("WAREHOUSE_MANAGER")
.build();
return new InMemoryUserDetailsManager(admin, warehouseManager);
}}
- 主应用类(WarehouseManagementSystemApplication.java)
收起
java
import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplicationpublic class WarehouseManagementSystemApplication {
public static void main(String[] args) {
SpringApplication.run(W
.build();
UserDetails warehouseManager = User.withDefaultPasswordEncoder()
.username("manager")
.password("manager")
.roles("WAREHOUSE_MANAGER")
.build();
return new InMemoryUserDetailsManager(admin, warehouseManager);
}}
- 主应用类(WarehouseManagementSystemApplication.java)
收起
java
import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplicationpublic class WarehouseManagementSystemApplication {
public static void main(String[] args) {
SpringApplication.run(W
浙公网安备 33010602011771号