提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
36选7福利彩票抽奖系统
运行说明
一、环境
- jar包运行:电脑安装JDK8及以上,配置好环境变量
二、启动方法
- jar启动:在此文件夹打开CMD,输入 java -jar Lottery.jar 回车
三、功能说明
-
用户注册:填写用户名、密码、手机号、账户余额注册
-
用户登录:登录时自动检测当期开奖,弹窗提示是否中奖
-
购彩:支持机选随机号码、手动自选,自定义投注注数,自动扣余额(单注2元)
-
抽奖动画:点击开始滚动数字,停止后生成开奖号码;7码全中特等奖,命中6码一等奖
-
批量测试:一键生成10万测试用户并自动购彩,控制台输出全部中奖用户ID及中奖等级 四、备注 程序数据存内存,关闭程序所有数据清空;批量生成10万用户会短暂卡顿,属于正常现象。
一、entity/User.java 用户实体
package entity;
import java.util.ArrayList;
import java.util.Set;
public class User {
private int userId;
private String username;
private String password;
private double balance;
private String phone;
// 用户所有彩票订单,每注为7个号码集合
private ArrayList<Set<Integer>> tickets;
public User(int userId, String username, String password, double balance, String phone) {
this.userId = userId;
this.username = username;
this.password = password;
this.balance = balance;
this.phone = phone;
this.tickets = new ArrayList<>();
}
// getter & setter
public int getUserId() { return userId; }
public void setUserId(int userId) { this.userId = userId; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
public double getBalance() { return balance; }
public void setBalance(double balance) { this.balance = balance; }
public String getPhone() { return phone; }
public void setPhone(String phone) { this.phone = phone; }
public ArrayList<Set<Integer>> getTickets() { return tickets; }
public void setTickets(ArrayList<Set<Integer>> tickets) { this.tickets = tickets; }
}
二、dao/DataStore.java 全局内存数据库
package dao;
import entity.User;
import java.util.HashMap;
import java.util.Set;
public class DataStore {
// 单例全局存储
private static DataStore instance = new DataStore();
private DataStore(){}
public static DataStore getInstance(){return instance;}
// 用户库 key=userId
public HashMap<Integer, User> userMap = new HashMap<>();
// 当前开奖号码
public Set<Integer> drawResult = null;
// 自增用户ID
public int nextUserId = 1;
// 单注彩票价格
public final int TICKET_PRICE = 2;
}
三util/LotteryUtil.java 号码、中奖工具类
package util;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
public class LotteryUtil {
private static Random random = new Random();
/**
* 生成一注36选7不重复号码
*/
public static Set<Integer> createRandomTicket(){
Set<Integer> nums = new HashSet<>();
while(nums.size() < 7){
int num = random.nextInt(36)+1;
nums.add(num);
}
return nums;
}
/**
* 排序号码转字符串展示
*/
public static String sortNumToString(Set<Integer> set){
ArrayList<Integer> list = new ArrayList<>(set);
Collections.sort(list);
StringBuilder sb = new StringBuilder();
for(int n : list){
sb.append(String.format("%02d ",n));
}
return sb.toString().trim();
}
/**
* 判断一注彩票中奖档位
* 返回值:0未中奖 1一等奖(6中) 2特等奖(7中)
*/
public static int checkWinLevel(Set<Integer> ticket, Set<Integer> draw){
int hit = 0;
for(int n : ticket){
if(draw.contains(n)) hit++;
}
if(hit ==7) return 2;
if(hit ==6) return 1;
return 0;
}
}
四util/BatchTest.java 批量 10 万用户自动注册购彩测试工具
package util;
import dao.DataStore;
import entity.User;
import java.util.Set;
public class BatchTest {
private DataStore store = DataStore.getInstance();
/**
* 批量注册count个用户,自动为每个用户随机购买3注彩票
*/
public void batchRegisterAndBuy(int count){
System.out.println("开始批量生成"+count+"个用户...");
long start = System.currentTimeMillis();
for(int i=0;i<count;i++){
int uid = store.nextUserId++;
String name = "autoUser_"+uid;
String pwd = "123456";
String phone = "138"+String.format("%08d",uid);
User user = new User(uid,name,pwd,200,phone);
// 自动买3注机选
for(int j=0;j<3;j++){
Set<Integer> ticket = LotteryUtil.createRandomTicket();
user.getTickets().add(ticket);
}
// 扣款3*2=6元
user.setBalance(user.getBalance()-6);
store.userMap.put(uid,user);
}
long cost = System.currentTimeMillis()-start;
System.out.println("批量生成完成!耗时"+cost+"ms");
}
/**
* 遍历全部用户,统计所有中奖用户
*/
public void scanAllWinner(){
Set<Integer> draw = store.drawResult;
if(draw == null){
System.out.println("暂无开奖结果!");
return;
}
System.out.println("===== 全部中奖用户汇总 =====");
for(User u : store.userMap.values()){
boolean hasWin = false;
for(Set<Integer> t : u.getTickets()){
int level = LotteryUtil.checkWinLevel(t,draw);
if(level !=0){
hasWin = true;
String levelStr = level==2 ? "特等奖(7全中)" : "一等奖(6中)";
System.out.println("用户ID:"+u.getUserId()+" 用户名:"+u.getUsername()+" 中奖档位:"+levelStr);
}
}
}
}
}
五view/RegisterFrame.java 注册窗口
package view;
import dao.DataStore;
import entity.User;
import javax.swing.*;
import java.awt.*;
public class RegisterFrame extends JFrame {
private JTextField tfUser,tfPhone,tfBalance;
private JPasswordField tfPwd;
private DataStore store = DataStore.getInstance();
public RegisterFrame(){
setTitle("用户注册");
setSize(320,260);
setLocationRelativeTo(null);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setLayout(new GridLayout(5,2,8,8));
setResizable(false);
add(new JLabel("用户名:"));
tfUser = new JTextField();
add(tfUser);
add(new JLabel("密码:"));
tfPwd = new JPasswordField();
add(tfPwd);
add(new JLabel("手机号:"));
tfPhone = new JTextField();
add(tfPhone);
add(new JLabel("初始余额:"));
tfBalance = new JTextField("100");
add(tfBalance);
JButton btnReg = new JButton("注册");
JButton btnBack = new JButton("返回登录");
add(btnReg);
add(btnBack);
// 注册按钮事件
btnReg.addActionListener(e->{
String name = tfUser.getText().trim();
String pwd = new String(tfPwd.getPassword()).trim();
String phone = tfPhone.getText().trim();
double bal;
try{
bal = Double.parseDouble(tfBalance.getText().trim());
}catch (Exception ex){
JOptionPane.showMessageDialog(this,"余额输入非法!");
return;
}
if(name.isEmpty()||pwd.isEmpty()||phone.isEmpty()){
JOptionPane.showMessageDialog(this,"信息不能为空!");
return;
}
// 创建用户
int uid = store.nextUserId++;
User user = new User(uid,name,pwd,bal,phone);
store.userMap.put(uid,user);
JOptionPane.showMessageDialog(this,"注册成功!你的用户ID:"+uid);
this.dispose();
new LoginFrame().setVisible(true);
});
// 返回登录
btnBack.addActionListener(e->{
this.dispose();
new LoginFrame().setVisible(true);
});
}
}
六view/LoginFrame.java 登录窗口(登录自动检测中奖通知)
package view;
import dao.DataStore;
import entity.User;
import util.LotteryUtil;
import javax.swing.*;
import java.awt.*;
import java.util.Set;
public class LoginFrame extends JFrame {
private JTextField tfUser;
private JPasswordField tfPwd;
private DataStore store = DataStore.getInstance();
public LoginFrame(){
setTitle("彩票系统登录");
setSize(300,200);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(new GridLayout(4,2,8,8));
add(new JLabel("用户名:"));
tfUser = new JTextField();
add(tfUser);
add(new JLabel("密码:"));
tfPwd = new JPasswordField();
add(tfPwd);
JButton btnLogin = new JButton("登录");
JButton btnReg = new JButton("注册账号");
add(btnLogin);
add(btnReg);
// 登录事件
btnLogin.addActionListener(e->{
String name = tfUser.getText().trim();
String pwd = new String(tfPwd.getPassword()).trim();
User loginUser = null;
for(User u : store.userMap.values()){
if(u.getUsername().equals(name) && u.getPassword().equals(pwd)){
loginUser = u;
break;
}
}
if(loginUser == null){
JOptionPane.showMessageDialog(this,"用户名或密码错误!");
return;
}
// 登录成功,检测中奖
if(store.drawResult != null){
StringBuilder msg = new StringBuilder("【中奖通知】\n");
boolean winFlag = false;
for(Set<Integer> t : loginUser.getTickets()){
int level = LotteryUtil.checkWinLevel(t,store.drawResult);
if(level == 2){
msg.append("特等奖:7个号码全中\n");
winFlag = true;
}else if(level ==1){
msg.append("一等奖:命中6个号码\n");
winFlag = true;
}
}
if(winFlag){
JOptionPane.showMessageDialog(this,msg.toString());
}else {
JOptionPane.showMessageDialog(this,"本期暂无中奖");
}
}
this.dispose();
// 打开主界面
new LotteryFrame(loginUser).setVisible(true);
});
// 跳转注册
btnReg.addActionListener(e->{
this.dispose();
new RegisterFrame().setVisible(true);
});
}
}
七 view/BuyTicketPanel.java 购彩面板(手动 / 机选、多注投注)
package view;
import dao.DataStore;
import entity.User;
import util.LotteryUtil;
import javax.swing.*;
import java.awt.*;
import java.util.HashSet;
import java.util.Set;
public class BuyTicketPanel extends JPanel {
private User loginUser;
private DataStore store = DataStore.getInstance();
private JTextField tfCount;
private JTextArea taNum;
private Set<Integer> manualNum = new HashSet<>();
public BuyTicketPanel(User user){
this.loginUser = user;
setLayout(new BorderLayout(10,10));
setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
// 顶部信息
JPanel top = new JPanel();
top.add(new JLabel("当前账户余额:"+loginUser.getBalance()+"元"));
add(top,BorderLayout.NORTH);
// 中部选号区
JPanel mid = new JPanel(new GridLayout(3,2,5,5));
mid.add(new JLabel("投注注数:"));
tfCount = new JTextField("1");
mid.add(tfCount);
JButton btnRandom = new JButton("机选号码");
mid.add(btnRandom);
JButton btnClear = new JButton("清空手动号码");
mid.add(btnClear);
mid.add(new JLabel("当前号码预览:"));
taNum = new JTextArea(3,20);
taNum.setEditable(false);
mid.add(taNum);
add(mid,BorderLayout.CENTER);
// 底部按钮
JPanel bottom = new JPanel();
JButton btnBuy = new JButton("确认购买");
bottom.add(btnBuy);
add(bottom,BorderLayout.SOUTH);
// 机选按钮
btnRandom.addActionListener(e->{
manualNum = LotteryUtil.createRandomTicket();
taNum.setText(LotteryUtil.sortNumToString(manualNum));
});
// 清空号码
btnClear.addActionListener(e->{
manualNum.clear();
taNum.setText("");
});
// 购彩按钮
btnBuy.addActionListener(e->{
int betNum;
try{
betNum = Integer.parseInt(tfCount.getText().trim());
if(betNum <=0) throw new Exception();
}catch (Exception ex){
JOptionPane.showMessageDialog(this,"注数必须为正整数!");
return;
}
int totalCost = betNum * store.TICKET_PRICE;
if(loginUser.getBalance() < totalCost){
JOptionPane.showMessageDialog(this,"余额不足!需要"+totalCost+"元");
return;
}
// 扣款
loginUser.setBalance(loginUser.getBalance()-totalCost);
// 批量添加彩票
for(int i=0;i<betNum;i++){
if(manualNum.size()==7){
loginUser.getTickets().add(new HashSet<>(manualNum));
}else {
loginUser.getTickets().add(LotteryUtil.createRandomTicket());
}
}
JOptionPane.showMessageDialog(this,"购买成功!扣除"+totalCost+"元,剩余余额:"+loginUser.getBalance());
});
}
}
八view/LotteryFrame.java 主窗口 + 抽奖动画(核心滚动效果)
package view;
import dao.DataStore;
import entity.User;
import util.BatchTest;
import util.LotteryUtil;
import javax.swing.*;
import java.awt.*;
import java.util.Set;
public class LotteryFrame extends JFrame {
private User loginUser;
private DataStore store = DataStore.getInstance();
private JLabel lblRollNum;
private Thread rollThread;
private boolean isRolling = false;
public LotteryFrame(User user){
this.loginUser = user;
setTitle("36选7福利彩票系统 | 用户ID:"+user.getUserId());
setSize(600,400);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(new BorderLayout());
// 左侧购彩面板
BuyTicketPanel buyPanel = new BuyTicketPanel(user);
add(buyPanel,BorderLayout.WEST);
// 右侧抽奖面板
JPanel lotteryPanel = new JPanel(new BorderLayout(10,10));
lotteryPanel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
lblRollNum = new JLabel("等待开奖",SwingConstants.CENTER);
lblRollNum.setFont(new Font("黑体",Font.BOLD,30));
lotteryPanel.add(lblRollNum,BorderLayout.CENTER);
JPanel btnPanel = new JPanel();
JButton btnStart = new JButton("开始滚动");
JButton btnStop = new JButton("停止开奖");
JButton btnBatchTest = new JButton("批量测试(10万用户)");
JButton btnShowWinner = new JButton("查看全部中奖用户");
btnPanel.add(btnStart);
btnPanel.add(btnStop);
btnPanel.add(btnBatchTest);
btnPanel.add(btnShowWinner);
lotteryPanel.add(btnPanel,BorderLayout.SOUTH);
add(lotteryPanel,BorderLayout.CENTER);
// 开始滚动
btnStart.addActionListener(e->{
if(isRolling) return;
isRolling = true;
rollThread = new Thread(()->{
while(isRolling){
Set<Integer> temp = LotteryUtil.createRandomTicket();
String numStr = LotteryUtil.sortNumToString(temp);
lblRollNum.setText(numStr);
try {
Thread.sleep(80);
} catch (InterruptedException ex) {
break;
}
}
});
rollThread.start();
});
// 停止开奖
btnStop.addActionListener(e->{
if(!isRolling) return;
isRolling = false;
try {
rollThread.join();
} catch (InterruptedException ex) {}
// 生成正式开奖号码
Set<Integer> draw = LotteryUtil.createRandomTicket();
store.drawResult = draw;
String resStr = LotteryUtil.sortNumToString(draw);
lblRollNum.setText("本期开奖:"+resStr);
JOptionPane.showMessageDialog(this,"开奖完成!号码:"+resStr);
});
// 批量10万用户测试
btnBatchTest.addActionListener(e->{
new Thread(()->{
BatchTest bt = new BatchTest();
bt.batchRegisterAndBuy(100000);
JOptionPane.showMessageDialog(this,"10万用户批量生成完成!");
}).start();
});
// 展示所有中奖用户
btnShowWinner.addActionListener(e->{
BatchTest bt = new BatchTest();
bt.scanAllWinner();
JOptionPane.showMessageDialog(this,"控制台已输出全部中奖用户ID及档位");
});
}
}
九 Main.java 程序入口
import view.LoginFrame;
public class Main {
public static void main(String[] args) {
// 启动登录窗口
new LoginFrame().setVisible(true);
}
}
总结
本次 Java 课程设计是第一次完整独立开发带图形界面的桌面应用,过程中遇到了不少典型问题。
第一大难题是 Swing 界面卡顿,最开始直接在按钮点击事件里写循环刷新号码,窗口完全卡死,查阅多线程相关知识后,新建子线程单独处理动画循环,才解决界面阻塞问题,也理解了 UI 线程不能执行耗时操作的核心知识点。
第二是号码重复问题,一开始使用 ArrayList 随机添加数字会出现重复号码,改用 HashSet 自动去重,简化了去重逻辑,加深了对 Set 集合特性的理解。
第三是批量生成十万用户时运行缓慢,通过减少 IO 输出、简化对象创建逻辑优化速度,同时学会了使用 System.currentTimeMillis () 统计代码运行耗时。
第四是 Jar 打包失败,最开始未配置主类,打包后无法运行,反复调试 Artifact 配置,最终成功生成可独立运行的 Jar 包,掌握了 Java 项目部署打包流程。
整个开发过程从需求分析、分包设计、编码、调试、打包完整走通,熟练掌握面向对象封装、集合、Swing、多线程等课堂知识点,把书本理论落地成可运行程序,收获很大。
。

4643

被折叠的 条评论
为什么被折叠?



