Java票据案例

wen java案例 3

本文目录导读:

Java票据案例

  1. 票据管理系统架构设计
  2. 系统特点
  3. 使用场景

我来为您设计一个完整的Java票据(发票)管理系统案例,包含核心功能模块和代码实现。

票据管理系统架构设计

项目结构

ticket-system/
├── src/main/java/com/example/ticket/
│   ├── model/          # 实体类
│   ├── dao/            # 数据访问层
│   ├── service/        # 业务逻辑层
│   ├── controller/     # 控制层
│   └── util/           # 工具类
└── src/main/resources/ # 配置文件

核心实体类设计

1 票据实体类(Ticket)

package com.example.ticket.model;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
/**
 * 票据实体类
 */
public class Ticket {
    // 票据ID
    private Long id;
    // 票据编号
    private String ticketNo;
    // 票据类型
    private TicketType type;
    // 开票方
    private String issuer;
    // 收票方
    private String payer;
    // 票据金额
    private BigDecimal amount;
    // 税率
    private BigDecimal taxRate;
    // 税额
    private BigDecimal taxAmount;
    // 价税合计
    private BigDecimal totalAmount;
    // 开票日期
    private LocalDateTime issueDate;
    // 有效期
    private LocalDateTime validDate;
    // 状态
    private TicketStatus status;
    // 备注
    private String remark;
    // 创建时间
    private LocalDateTime createTime;
    // 更新时间
    private LocalDateTime updateTime;
    // 票据明细
    private List<TicketItem> items;
    // 构造函数
    public Ticket() {
        this.createTime = LocalDateTime.now();
        this.updateTime = LocalDateTime.now();
        this.status = TicketStatus.PENDING;
    }
    // Getter和Setter方法
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getTicketNo() {
        return ticketNo;
    }
    public void setTicketNo(String ticketNo) {
        this.ticketNo = ticketNo;
    }
    public TicketType getType() {
        return type;
    }
    public void setType(TicketType type) {
        this.type = type;
    }
    public String getIssuer() {
        return issuer;
    }
    public void setIssuer(String issuer) {
        this.issuer = issuer;
    }
    public String getPayer() {
        return payer;
    }
    public void setPayer(String payer) {
        this.payer = payer;
    }
    public BigDecimal getAmount() {
        return amount;
    }
    public void setAmount(BigDecimal amount) {
        this.amount = amount;
        calculateTax();
    }
    public BigDecimal getTaxRate() {
        return taxRate;
    }
    public void setTaxRate(BigDecimal taxRate) {
        this.taxRate = taxRate;
        calculateTax();
    }
    public BigDecimal getTaxAmount() {
        return taxAmount;
    }
    public void setTaxAmount(BigDecimal taxAmount) {
        this.taxAmount = taxAmount;
    }
    public BigDecimal getTotalAmount() {
        return totalAmount;
    }
    public void setTotalAmount(BigDecimal totalAmount) {
        this.totalAmount = totalAmount;
    }
    public LocalDateTime getIssueDate() {
        return issueDate;
    }
    public void setIssueDate(LocalDateTime issueDate) {
        this.issueDate = issueDate;
    }
    public LocalDateTime getValidDate() {
        return validDate;
    }
    public void setValidDate(LocalDateTime validDate) {
        this.validDate = validDate;
    }
    public TicketStatus getStatus() {
        return status;
    }
    public void setStatus(TicketStatus status) {
        this.status = status;
    }
    public String getRemark() {
        return remark;
    }
    public void setRemark(String remark) {
        this.remark = remark;
    }
    public LocalDateTime getCreateTime() {
        return createTime;
    }
    public void setCreateTime(LocalDateTime createTime) {
        this.createTime = createTime;
    }
    public LocalDateTime getUpdateTime() {
        return updateTime;
    }
    public void setUpdateTime(LocalDateTime updateTime) {
        this.updateTime = updateTime;
    }
    public List<TicketItem> getItems() {
        return items;
    }
    public void setItems(List<TicketItem> items) {
        this.items = items;
    }
    // 计算税额和总金额
    private void calculateTax() {
        if (amount != null && taxRate != null) {
            this.taxAmount = amount.multiply(taxRate);
            this.totalAmount = amount.add(taxAmount);
        }
    }
}

2 票据明细类(TicketItem)

package com.example.ticket.model;
import java.math.BigDecimal;
/**
 * 票据明细实体类
 */
public class TicketItem {
    // 明细ID
    private Long id;
    // 票据ID
    private Long ticketId;
    // 项目名称
    private String itemName;
    // 规格型号
    private String specification;
    // 单位
    private String unit;
    // 数量
    private Integer quantity;
    // 单价
    private BigDecimal price;
    // 金额
    private BigDecimal amount;
    // 税率
    private BigDecimal taxRate;
    // 税额
    private BigDecimal taxAmount;
    // 构造函数
    public TicketItem() {
    }
    public TicketItem(String itemName, Integer quantity, BigDecimal price, BigDecimal taxRate) {
        this.itemName = itemName;
        this.quantity = quantity;
        this.price = price;
        this.taxRate = taxRate;
        calculateAmount();
    }
    // 计算金额和税额
    private void calculateAmount() {
        if (quantity != null && price != null) {
            this.amount = price.multiply(BigDecimal.valueOf(quantity));
            if (taxRate != null) {
                this.taxAmount = amount.multiply(taxRate);
            }
        }
    }
    // Getter和Setter方法
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public Long getTicketId() {
        return ticketId;
    }
    public void setTicketId(Long ticketId) {
        this.ticketId = ticketId;
    }
    public String getItemName() {
        return itemName;
    }
    public void setItemName(String itemName) {
        this.itemName = itemName;
    }
    public String getSpecification() {
        return specification;
    }
    public void setSpecification(String specification) {
        this.specification = specification;
    }
    public String getUnit() {
        return unit;
    }
    public void setUnit(String unit) {
        this.unit = unit;
    }
    public Integer getQuantity() {
        return quantity;
    }
    public void setQuantity(Integer quantity) {
        this.quantity = quantity;
        calculateAmount();
    }
    public BigDecimal getPrice() {
        return price;
    }
    public void setPrice(BigDecimal price) {
        this.price = price;
        calculateAmount();
    }
    public BigDecimal getAmount() {
        return amount;
    }
    public void setAmount(BigDecimal amount) {
        this.amount = amount;
    }
    public BigDecimal getTaxRate() {
        return taxRate;
    }
    public void setTaxRate(BigDecimal taxRate) {
        this.taxRate = taxRate;
        calculateAmount();
    }
    public BigDecimal getTaxAmount() {
        return taxAmount;
    }
    public void setTaxAmount(BigDecimal taxAmount) {
        this.taxAmount = taxAmount;
    }
}

3 枚举类型定义

package com.example.ticket.model;
/**
 * 票据类型枚举
 */
public enum TicketType {
    INVOICE("发票"),
    RECEIPT("收据"),
    VOUCHER("凭证"),
    TICKET("车票"),
    CHECK("支票");
    private String description;
    TicketType(String description) {
        this.description = description;
    }
    public String getDescription() {
        return description;
    }
}
/**
 * 票据状态枚举
 */
public enum TicketStatus {
    PENDING("待审核"),
    APPROVED("已通过"),
    REJECTED("已拒绝"),
    CANCELLED("已作废"),
    EXPIRED("已过期");
    private String description;
    TicketStatus(String description) {
        this.description = description;
    }
    public String getDescription() {
        return description;
    }
}

数据访问层(DAO)

package com.example.ticket.dao;
import com.example.ticket.model.Ticket;
import com.example.ticket.model.TicketStatus;
import com.example.ticket.model.TicketType;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
/**
 * 票据数据访问层(使用内存存储模拟数据库)
 */
public class TicketDao {
    // 使用ConcurrentHashMap模拟数据库存储
    private static final Map<Long, Ticket> ticketStore = new ConcurrentHashMap<>();
    private static long idGenerator = 1;
    // 保存票据
    public Ticket save(Ticket ticket) {
        if (ticket.getId() == null) {
            ticket.setId(idGenerator++);
        }
        ticket.setUpdateTime(java.time.LocalDateTime.now());
        ticketStore.put(ticket.getId(), ticket);
        return ticket;
    }
    // 根据ID查询票据
    public Ticket findById(Long id) {
        return ticketStore.get(id);
    }
    // 查询所有票据
    public List<Ticket> findAll() {
        return new ArrayList<>(ticketStore.values());
    }
    // 根据状态查询
    public List<Ticket> findByStatus(TicketStatus status) {
        return ticketStore.values().stream()
                .filter(ticket -> ticket.getStatus() == status)
                .collect(Collectors.toList());
    }
    // 根据类型查询
    public List<Ticket> findByType(TicketType type) {
        return ticketStore.values().stream()
                .filter(ticket -> ticket.getType() == type)
                .collect(Collectors.toList());
    }
    // 根据票据编号查询
    public Ticket findByTicketNo(String ticketNo) {
        return ticketStore.values().stream()
                .filter(ticket -> ticket.getTicketNo().equals(ticketNo))
                .findFirst()
                .orElse(null);
    }
    // 删除票据
    public boolean delete(Long id) {
        return ticketStore.remove(id) != null;
    }
    // 更新票据
    public Ticket update(Ticket ticket) {
        if (ticketStore.containsKey(ticket.getId())) {
            ticket.setUpdateTime(java.time.LocalDateTime.now());
            ticketStore.put(ticket.getId(), ticket);
            return ticket;
        }
        return null;
    }
    // 条件查询
    public List<Ticket> search(TicketQuery query) {
        return ticketStore.values().stream()
                .filter(ticket -> {
                    if (query.getType() != null && ticket.getType() != query.getType()) {
                        return false;
                    }
                    if (query.getStatus() != null && ticket.getStatus() != query.getStatus()) {
                        return false;
                    }
                    if (query.getIssuer() != null && !ticket.getIssuer().contains(query.getIssuer())) {
                        return false;
                    }
                    if (query.getStartDate() != null && ticket.getIssueDate().isBefore(query.getStartDate())) {
                        return false;
                    }
                    if (query.getEndDate() != null && ticket.getIssueDate().isAfter(query.getEndDate())) {
                        return false;
                    }
                    return true;
                })
                .collect(Collectors.toList());
    }
    // 统计数量
    public long count() {
        return ticketStore.size();
    }
    // 统计金额
    public java.math.BigDecimal sumAmount() {
        return ticketStore.values().stream()
                .map(Ticket::getTotalAmount)
                .reduce(java.math.BigDecimal.ZERO, java.math.BigDecimal::add);
    }
}
/**
 * 票据查询条件类
 */
class TicketQuery {
    private TicketType type;
    private TicketStatus status;
    private String issuer;
    private java.time.LocalDateTime startDate;
    private java.time.LocalDateTime endDate;
    // Getter和Setter方法
    public TicketType getType() {
        return type;
    }
    public void setType(TicketType type) {
        this.type = type;
    }
    public TicketStatus getStatus() {
        return status;
    }
    public void setStatus(TicketStatus status) {
        this.status = status;
    }
    public String getIssuer() {
        return issuer;
    }
    public void setIssuer(String issuer) {
        this.issuer = issuer;
    }
    public java.time.LocalDateTime getStartDate() {
        return startDate;
    }
    public void setStartDate(java.time.LocalDateTime startDate) {
        this.startDate = startDate;
    }
    public java.time.LocalDateTime getEndDate() {
        return endDate;
    }
    public void setEndDate(java.time.LocalDateTime endDate) {
        this.endDate = endDate;
    }
}

业务逻辑层(Service)

package com.example.ticket.service;
import com.example.ticket.dao.TicketDao;
import com.example.ticket.model.Ticket;
import com.example.ticket.model.TicketStatus;
import com.example.ticket.model.TicketType;
import com.example.ticket.util.TicketNumberGenerator;
import com.example.ticket.util.ValidationUtil;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
/**
 * 票据业务逻辑层
 */
public class TicketService {
    private final TicketDao ticketDao;
    private final TicketNumberGenerator numberGenerator;
    public TicketService() {
        this.ticketDao = new TicketDao();
        this.numberGenerator = new TicketNumberGenerator();
    }
    /**
     * 创建票据
     */
    public Ticket createTicket(Ticket ticket) {
        // 验证票据数据
        ValidationUtil.validateTicket(ticket);
        // 生成票据编号
        ticket.setTicketNo(numberGenerator.generateTicketNo(ticket.getType()));
        // 设置默认状态
        if (ticket.getStatus() == null) {
            ticket.setStatus(TicketStatus.PENDING);
        }
        // 设置开票日期
        if (ticket.getIssueDate() == null) {
            ticket.setIssueDate(LocalDateTime.now());
        }
        // 设置有效期(默认一年)
        if (ticket.getValidDate() == null) {
            ticket.setValidDate(LocalDateTime.now().plusYears(1));
        }
        return ticketDao.save(ticket);
    }
    /**
     * 更新票据
     */
    public Ticket updateTicket(Ticket ticket) {
        ValidationUtil.validateTicket(ticket);
        Ticket existingTicket = ticketDao.findById(ticket.getId());
        if (existingTicket == null) {
            throw new RuntimeException("票据不存在");
        }
        // 检查状态
        if (existingTicket.getStatus() == TicketStatus.CANCELLED) {
            throw new RuntimeException("已作废的票据不能修改");
        }
        return ticketDao.update(ticket);
    }
    /**
     * 获取所有票据
     */
    public List<Ticket> getAllTickets() {
        return ticketDao.findAll();
    }
    /**
     * 根据ID获取票据
     */
    public Ticket getTicketById(Long id) {
        Ticket ticket = ticketDao.findById(id);
        if (ticket == null) {
            throw new RuntimeException("票据不存在");
        }
        return ticket;
    }
    /**
     * 审核通过
     */
    public boolean approveTicket(Long id) {
        Ticket ticket = ticketDao.findById(id);
        if (ticket == null) {
            throw new RuntimeException("票据不存在");
        }
        if (ticket.getStatus() == TicketStatus.CANCELLED) {
            throw new RuntimeException("已作废的票据不能审核");
        }
        // 检查是否过期
        if (ticket.getValidDate().isBefore(LocalDateTime.now())) {
            ticket.setStatus(TicketStatus.EXPIRED);
            ticketDao.update(ticket);
            throw new RuntimeException("票据已过期");
        }
        ticket.setStatus(TicketStatus.APPROVED);
        ticketDao.update(ticket);
        return true;
    }
    /**
     * 拒绝票据
     */
    public boolean rejectTicket(Long id, String reason) {
        Ticket ticket = ticketDao.findById(id);
        if (ticket == null) {
            throw new RuntimeException("票据不存在");
        }
        ticket.setStatus(TicketStatus.REJECTED);
        if (reason != null) {
            ticket.setRemark(reason);
        }
        ticketDao.update(ticket);
        return true;
    }
    /**
     * 作废票据
     */
    public boolean cancelTicket(Long id) {
        Ticket ticket = ticketDao.findById(id);
        if (ticket == null) {
            throw new RuntimeException("票据不存在");
        }
        ticket.setStatus(TicketStatus.CANCELLED);
        ticketDao.update(ticket);
        return true;
    }
    /**
     * 删除票据
     */
    public boolean deleteTicket(Long id) {
        return ticketDao.delete(id);
    }
    /**
     * 检查票据过期
     */
    public void checkExpiration() {
        List<Ticket> tickets = ticketDao.findAll();
        LocalDateTime now = LocalDateTime.now();
        for (Ticket ticket : tickets) {
            if (ticket.getStatus() == TicketStatus.PENDING && 
                ticket.getValidDate().isBefore(now)) {
                ticket.setStatus(TicketStatus.EXPIRED);
                ticketDao.update(ticket);
            }
        }
    }
    /**
     * 获取票据统计信息
     */
    public TicketStatistics getStatistics() {
        List<Ticket> tickets = ticketDao.findAll();
        TicketStatistics stats = new TicketStatistics();
        stats.setTotalCount(tickets.size());
        stats.setTotalAmount(tickets.stream()
                .map(Ticket::getTotalAmount)
                .reduce(BigDecimal.ZERO, BigDecimal::add));
        // 统计各状态数量
        for (TicketStatus status : TicketStatus.values()) {
            long count = tickets.stream()
                    .filter(t -> t.getStatus() == status)
                    .count();
            stats.getStatusCounts().put(status, count);
        }
        // 统计各类型数量
        for (TicketType type : TicketType.values()) {
            long count = tickets.stream()
                    .filter(t -> t.getType() == type)
                    .count();
            stats.getTypeCounts().put(type, count);
        }
        return stats;
    }
}

工具类

package com.example.ticket.util;
import com.example.ticket.model.Ticket;
import com.example.ticket.model.TicketType;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Random;
/**
 * 票据编号生成器
 */
public class TicketNumberGenerator {
    private static final DateTimeFormatter DATE_FORMAT = 
        DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
    private static final Random RANDOM = new Random();
    /**
     * 生成票据编号
     */
    public String generateTicketNo(TicketType type) {
        StringBuilder sb = new StringBuilder();
        // 添加类型前缀
        String typePrefix = getTypePrefix(type);
        sb.append(typePrefix);
        // 添加日期时间
        sb.append(LocalDateTime.now().format(DATE_FORMAT));
        // 添加随机数
        sb.append(String.format("%04d", RANDOM.nextInt(10000)));
        return sb.toString();
    }
    /**
     * 获取类型前缀
     */
    private String getTypePrefix(TicketType type) {
        switch (type) {
            case INVOICE: return "INV";
            case RECEIPT: return "RCT";
            case VOUCHER: return "VCH";
            case TICKET:  return "TKT";
            case CHECK:   return "CHK";
            default:      return "TIC";
        }
    }
}
package com.example.ticket.util;
import com.example.ticket.model.Ticket;
import java.math.BigDecimal;
import java.util.List;
/**
 * 数据验证工具类
 */
public class ValidationUtil {
    /**
     * 验证票据数据
     */
    public static void validateTicket(Ticket ticket) {
        if (ticket == null) {
            throw new IllegalArgumentException("票据不能为空");
        }
        // 验证必填字段
        if (ticket.getType() == null) {
            throw new IllegalArgumentException("票据类型不能为空");
        }
        if (ticket.getIssuer() == null || ticket.getIssuer().trim().isEmpty()) {
            throw new IllegalArgumentException("开票方不能为空");
        }
        if (ticket.getPayer() == null || ticket.getPayer().trim().isEmpty()) {
            throw new IllegalArgumentException("收票方不能为空");
        }
        if (ticket.getAmount() == null || ticket.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
            throw new IllegalArgumentException("票据金额必须大于0");
        }
        if (ticket.getTaxRate() == null || 
            ticket.getTaxRate().compareTo(BigDecimal.ZERO) < 0 || 
            ticket.getTaxRate().compareTo(new BigDecimal("1")) > 0) {
            throw new IllegalArgumentException("税率必须在0到1之间");
        }
    }
    /**
     * 验证票据列表
     */
    public static void validateTickets(List<Ticket> tickets) {
        if (tickets == null || tickets.isEmpty()) {
            throw new IllegalArgumentException("票据列表不能为空");
        }
        for (Ticket ticket : tickets) {
            validateTicket(ticket);
        }
    }
}

主程序测试类

package com.example.ticket;
import com.example.ticket.model.Ticket;
import com.example.ticket.model.TicketItem;
import com.example.ticket.model.TicketType;
import com.example.ticket.service.TicketService;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
/**
 * 票据管理系统主程序
 */
public class Main {
    public static void main(String[] args) {
        TicketService ticketService = new TicketService();
        System.out.println("========== 票据管理系统演示 ==========");
        // 创建票据
        try {
            // 创建一张发票
            Ticket invoice = new Ticket();
            invoice.setType(TicketType.INVOICE);
            invoice.setIssuer("科技公司");
            invoice.setPayer("客户A");
            invoice.setAmount(new BigDecimal("1000.00"));
            invoice.setTaxRate(new BigDecimal("0.13"));
            // 创建票据明细
            List<TicketItem> items = new ArrayList<>();
            items.add(new TicketItem("软件服务", 10, new BigDecimal("100"), new BigDecimal("0.13")));
            invoice.setItems(items);
            Ticket createdInvoice = ticketService.createTicket(invoice);
            System.out.println("创建发票成功:" + createdInvoice.getTicketNo());
            // 审核通过
            ticketService.approveTicket(createdInvoice.getId());
            System.out.println("票据审核通过");
            // 创建一张收据
            Ticket receipt = new Ticket();
            receipt.setType(TicketType.RECEIPT);
            receipt.setIssuer("咨询公司");
            receipt.setPayer("客户B");
            receipt.setAmount(new BigDecimal("500.00"));
            receipt.setTaxRate(new BigDecimal("0.06"));
            Ticket createdReceipt = ticketService.createTicket(receipt);
            System.out.println("创建收据成功:" + createdReceipt.getTicketNo());
            // 获取所有票据
            System.out.println("\n所有票据列表:");
            ticketService.getAllTickets().forEach(t -> {
                System.out.println("- " + t.getTicketNo() + " | " + 
                    t.getType().getDescription() + " | " + 
                    t.getIssuer() + " | " + 
                    t.getTotalAmount() + "元 | " + 
                    t.getStatus().getDescription());
            });
            // 获取统计信息
            var stats = ticketService.getStatistics();
            System.out.println("\n统计分析:");
            System.out.println("- 票据总数:" + stats.getTotalCount());
            System.out.println("- 总金额:" + stats.getTotalAmount() + "元");
            System.out.println("- 各状态统计:" + stats.getStatusCounts());
            System.out.println("- 各类型统计:" + stats.getTypeCounts());
        } catch (Exception e) {
            System.err.println("错误:" + e.getMessage());
        }
        System.out.println("\n========== 演示结束 ==========");
    }
}

统计类

package com.example.ticket.service;
import com.example.ticket.model.TicketStatus;
import com.example.ticket.model.TicketType;
import java.math.BigDecimal;
import java.util.EnumMap;
import java.util.Map;
/**
 * 票据统计信息类
 */
public class TicketStatistics {
    private long totalCount;
    private BigDecimal totalAmount;
    private Map<TicketStatus, Long> statusCounts = new EnumMap<>(TicketStatus.class);
    private Map<TicketType, Long> typeCounts = new EnumMap<>(TicketType.class);
    // Getters and Setters
    public long getTotalCount() {
        return totalCount;
    }
    public void setTotalCount(long totalCount) {
        this.totalCount = totalCount;
    }
    public BigDecimal getTotalAmount() {
        return totalAmount;
    }
    public void setTotalAmount(BigDecimal totalAmount) {
        this.totalAmount = totalAmount;
    }
    public Map<TicketStatus, Long> getStatusCounts() {
        return statusCounts;
    }
    public void setStatusCounts(Map<TicketStatus, Long> statusCounts) {
        this.statusCounts = statusCounts;
    }
    public Map<TicketType, Long> getTypeCounts() {
        return typeCounts;
    }
    public void setTypeCounts(Map<TicketType, Long> typeCounts) {
        this.typeCounts = typeCounts;
    }
}

系统特点

  1. 完整性:覆盖票据的创建、审核、作废、查询、统计等完整生命周期
  2. 可扩展性:采用分层架构,便于扩展和维护
  3. 业务规则:包含税率计算、有效期检查、状态管理等业务规则
  4. 数据验证:提供完善的数据验证机制
  5. 统计功能:支持多维度统计分析

使用场景

  • 企业财务管理系统
  • 电商平台发票管理
  • 票据扫描识别系统
  • 报销管理系统

这个案例可以作为票据管理系统的核心框架,您可以根据实际需求在此基础上扩展数据库集成、Web界面、报表生成等功能。

上一篇Java打印案例

下一篇UReport2案例

抱歉,评论功能暂时关闭!