ai

  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
// ...}
  1. 仓库接口(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);
}}
  1. 控制器层(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);
}}
  1. 前端页面设计
    登录页面(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>版权所有 &copy; 仓储管理系统</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>
  1. 安全配置(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
// ...}
  1. 仓库接口(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);
}}
  1. 控制器层(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);
}}
  1. 前端页面设计
    登录页面(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>版权所有 &copy; 仓储管理系统</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>
  1. 安全配置(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);
}}
  1. 主应用类(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
// ...}
  1. 仓库接口(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);
}}
  1. 控制器层(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);
}}
  1. 前端页面设计
    登录页面(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>版权所有 &copy; 仓储管理系统</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>
  1. 安全配置(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);
}}
  1. 主应用类(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);
}}
  1. 主应用类(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

posted @ 2025-03-05 20:03  龚恒。  阅读(43)  评论(0)    收藏  举报