第十一次实验课代码

添加C08~C011
This commit is contained in:
2025-11-20 17:01:56 +08:00
parent 1c869f816f
commit 9930f2421a
67 changed files with 1137 additions and 7 deletions

View File

@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="com.codeverse.userSettings.MarscodeWorkspaceAppSettingsState">
<option name="chatAppRouterInfo" value="builder/690c5888a0e96eb419edfb1d" />
<option name="progress" value="1.0" />
</component>
</project>

4
.idea/modules.xml generated
View File

@@ -8,6 +8,10 @@
<module fileurl="file://$PROJECT_DIR$/C05 Extends/C05 Extends.iml" filepath="$PROJECT_DIR$/C05 Extends/C05 Extends.iml" />
<module fileurl="file://$PROJECT_DIR$/C06 Polymorphism/C06 Polymorphism.iml" filepath="$PROJECT_DIR$/C06 Polymorphism/C06 Polymorphism.iml" />
<module fileurl="file://$PROJECT_DIR$/C07 StaticAndEnum/C07 StaticAndEnum.iml" filepath="$PROJECT_DIR$/C07 StaticAndEnum/C07 StaticAndEnum.iml" />
<module fileurl="file://$PROJECT_DIR$/C08-SnackGame/C08-SnackGame.iml" filepath="$PROJECT_DIR$/C08-SnackGame/C08-SnackGame.iml" />
<module fileurl="file://$PROJECT_DIR$/C09-Collection/C09-Collection.iml" filepath="$PROJECT_DIR$/C09-Collection/C09-Collection.iml" />
<module fileurl="file://$PROJECT_DIR$/C10-Swing/C10-Swing.iml" filepath="$PROJECT_DIR$/C10-Swing/C10-Swing.iml" />
<module fileurl="file://$PROJECT_DIR$/C11-Swing/C11-Swing.iml" filepath="$PROJECT_DIR$/C11-Swing/C11-Swing.iml" />
<module fileurl="file://$PROJECT_DIR$/ClassOfJava.iml" filepath="$PROJECT_DIR$/ClassOfJava.iml" />
</modules>
</component>

View File

@@ -1,7 +1,7 @@
package shape;
import java.awt.*;
public class Shape {
public abstract class Shape {
protected Color color;
protected int x,y;
@@ -11,9 +11,7 @@ public class Shape {
public Color getColor() {
return color;
}
public double getArea(){
return x*y;
}
public abstract double getArea();
public void setX(int x){
this.x=x;
@@ -29,9 +27,7 @@ public class Shape {
return y;
}
public double getPerimeter(){
return x*y;
}
public abstract double getPerimeter();
public void move(int dx,int dy){
x += dx;

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@@ -0,0 +1,17 @@
package game;
import java.awt.*;
public enum Direction {
UP(new Point(0,-1)),
DOWN(new Point(0,1)),
LEFT(new Point(-1,0)),
RIGHT(new Point(1,0));
private Point offset;
Direction(Point offset) {
this.offset = offset;
}
public static Point getOffset(Direction dir) {
return dir.offset;
}
}

View File

@@ -0,0 +1,7 @@
package game;
import java.awt.*;
public interface Drawable {
void draw(Graphics g);
}

View File

@@ -0,0 +1,38 @@
package game;
import java.awt.*;
import java.util.Random;
public class Food extends GameElement{
private static Random randeom = new Random();
public Food(int width,int height) {
super(0,0);
randomPosition(width,height);
}
/**
* 随机设置位置坐标
* @param width 可用宽度范围
* @param height 可用高度范围
*/
public void randomPosition(int width, int height) {
//计算一排或一列最多的格子数
int maxX = width/SIZE;
int maxY = height/SIZE;
//将位置坐标映射到像素点
int x = randeom.nextInt(maxX)*SIZE;
int y = randeom.nextInt(maxY)*SIZE;
//设置坐标
position.setLocation(x,y);
}
@Override
public void draw(Graphics g) {
//红色填充,黑色边框
g.setColor(Color.RED);
g.fillOval(position.x,position.y,SIZE,SIZE);
g.setColor(Color.BLACK);
g.drawOval(position.x,position.y,SIZE,SIZE);
}
}

View File

@@ -0,0 +1,15 @@
package game;
import java.awt.*;
public abstract class GameElement {
protected Point position;
public static final int SIZE = 20;
protected GameElement(int x,int y) {
position = new Point(x,y);
}
public Point getPosition() {
return position;
}
public abstract void draw(Graphics g);
}

View File

@@ -0,0 +1,5 @@
package game;
public interface Movable {
void move();
}

View File

@@ -0,0 +1,31 @@
package game;
import java.awt.*;
public class SnakeNode extends GameElement implements Movable{
private Direction direction;
public SnakeNode(int x, int y, Direction direction) {
super(x, y);
this.direction = direction;
}
public void setDirection(Direction direction) {
this.direction = direction;
}
@Override
public void draw(Graphics g) {
//绿色填充,黑色边框
g.setColor(Color.GREEN);
g.fillRect(position.x, position.y, SIZE, SIZE);
// 绘制边框,让蛇身更清晰
g.setColor(Color.BLACK);
g.drawRect(position.x, position.y, SIZE, SIZE);
}
@Override
public void move() {
Point offset = Direction.getOffset(direction);
position.x += offset.x*SIZE;
position.y += offset.y*SIZE;
}
}

View File

@@ -0,0 +1,85 @@
package view;
import game.Direction;
import game.Food;
import game.SnakeNode;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
public class GamePanel extends JPanel {
private static final int WIDTH = 600;
private static final int HEIGHT = 600;
private boolean isRunning;
// FIXME 蛇身体节点 未来需要改进
private SnakeNode[] snakeBody = new SnakeNode[3];
private final Food food;
public GamePanel() {
setPreferredSize(new Dimension(WIDTH, HEIGHT));
setBackground(Color.WHITE); // 背景色设为白色
// FIXME 初始化蛇 未来需要改进
snakeBody[0] = new SnakeNode(100, 100, Direction.RIGHT);
snakeBody[1] = new SnakeNode(80, 100, Direction.RIGHT);
snakeBody[2] = new SnakeNode(60, 100, Direction.RIGHT);
food = new Food(WIDTH, HEIGHT);
// 键盘监听
addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
// TODO 按下按键后需要做处理
}
});
setFocusable(true); // 确保面板能接收键盘事件
// 游戏循环
new Thread(() -> {
while (isRunning) {
try {
Thread.sleep(250);
moveSnake(); // 移动蛇
checkCollision(); // 检查碰撞
repaint(); // 调用paintComponent重绘
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
private void moveSnake() {
// TODO
}
private void checkCollision() {
// TODO
}
private void gameOver() {
isRunning = false;
JOptionPane.showMessageDialog(this, "游戏结束!得分:");
System.exit(0);
}
// 核心改进重写paintComponent而非paint利用Swing双缓冲
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); // 先绘制背景(双缓冲关键步骤)
// 绘制蛇
for (SnakeNode node : snakeBody) {
node.draw(g);
}
// 绘制食物
food.draw(g);
}
}

View File

@@ -0,0 +1,18 @@
package view;
import javax.swing.*;
public class SnakeGame extends JFrame {
public SnakeGame() {
setTitle("贪吃蛇");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(new GamePanel()); // 添加游戏面板
pack(); // 自动调整窗口大小以适应面板
setLocationRelativeTo(null); // 窗口居中
setVisible(true);
}
public static void main(String[] args) {
new SnakeGame();
}
}

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@@ -0,0 +1,24 @@
import java.util.*;
public class Josephus {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
ArrayList<Integer> arr = new ArrayList<>();
for(int i=0;i<n;++i)
arr.add(i+1);
int cnt = 0;
int i=2;
while(arr.size()>2) {
Iterator<Integer> it = arr.iterator();
while(it.hasNext()) {
it.next();
cnt++;
if(cnt==3) {
it.remove();
cnt = 0;
}
}
System.out.println(arr);
}
}
}

View File

@@ -0,0 +1,17 @@
package game;
import java.awt.*;
public enum Direction {
UP(new Point(0,-1)),
DOWN(new Point(0,1)),
LEFT(new Point(-1,0)),
RIGHT(new Point(1,0));
private Point offset;
Direction(Point offset) {
this.offset = offset;
}
public static Point getOffset(Direction dir) {
return dir.offset;
}
}

View File

@@ -0,0 +1,7 @@
package game;
import java.awt.*;
public interface Drawable {
void draw(Graphics g);
}

View File

@@ -0,0 +1,38 @@
package game;
import java.awt.*;
import java.util.Random;
public class Food extends GameElement{
private static Random randeom = new Random();
public Food(int width,int height) {
super(0,0);
randomPosition(width,height);
}
/**
* 随机设置位置坐标
* @param width 可用宽度范围
* @param height 可用高度范围
*/
public void randomPosition(int width, int height) {
//计算一排或一列最多的格子数
int maxX = width/SIZE;
int maxY = height/SIZE;
//将位置坐标映射到像素点
int x = randeom.nextInt(maxX)*SIZE;
int y = randeom.nextInt(maxY)*SIZE;
//设置坐标
position.setLocation(x,y);
}
@Override
public void draw(Graphics g) {
//红色填充,黑色边框
g.setColor(Color.RED);
g.fillOval(position.x,position.y,SIZE,SIZE);
g.setColor(Color.BLACK);
g.drawOval(position.x,position.y,SIZE,SIZE);
}
}

View File

@@ -0,0 +1,15 @@
package game;
import java.awt.*;
public abstract class GameElement {
protected Point position;
public static final int SIZE = 20;
protected GameElement(int x,int y) {
position = new Point(x,y);
}
public Point getPosition() {
return position;
}
public abstract void draw(Graphics g);
}

View File

@@ -0,0 +1,5 @@
package game;
public interface Movable {
void move();
}

View File

@@ -0,0 +1,34 @@
package game;
import java.awt.*;
public class SnakeNode extends GameElement implements Movable{
private Direction direction;
public SnakeNode(int x, int y, Direction direction) {
super(x, y);
this.direction = direction;
}
public void setDirection(Direction direction) {
this.direction = direction;
}
public Direction getDirection() {
return direction;
}
@Override
public void draw(Graphics g) {
//绿色填充,黑色边框
g.setColor(Color.GREEN);
g.fillRect(position.x, position.y, SIZE, SIZE);
// 绘制边框,让蛇身更清晰
g.setColor(Color.BLACK);
g.drawRect(position.x, position.y, SIZE, SIZE);
}
@Override
public void move() {
Point offset = Direction.getOffset(direction);
position.x += offset.x*SIZE;
position.y += offset.y*SIZE;
}
}

View File

@@ -0,0 +1,138 @@
package view;
import game.Direction;
import game.Food;
import game.GameElement;
import game.SnakeNode;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.*;
public class GamePanel extends JPanel {
private static final int WIDTH = 600;
private static final int HEIGHT = 600;
private boolean isRunning;
private LinkedList<SnakeNode> snakeBody = new LinkedList<>();
private final Food food;
private int score = 0;
public GamePanel() {
setPreferredSize(new Dimension(WIDTH, HEIGHT));
setBackground(Color.WHITE); // 背景色设为白色
isRunning = true;
snakeBody.add(new SnakeNode(100, 100, Direction.RIGHT));
snakeBody.add(new SnakeNode(80, 100, Direction.RIGHT));
snakeBody.add(new SnakeNode(60, 100, Direction.RIGHT));
food = new Food(WIDTH, HEIGHT);
// 键盘监听
addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
Direction currentDir = snakeBody.getFirst().getDirection();
switch(e.getKeyCode()){
case KeyEvent.VK_UP: {
if (currentDir != Direction.DOWN)
snakeBody.getFirst().setDirection(Direction.UP);
break;
}
case KeyEvent.VK_DOWN: {
if (currentDir != Direction.UP)
snakeBody.getFirst().setDirection(Direction.DOWN);
break;
}
case KeyEvent.VK_LEFT: {
if (currentDir != Direction.RIGHT)
snakeBody.getFirst().setDirection(Direction.LEFT);
break;
}
case KeyEvent.VK_RIGHT: {
if (currentDir != Direction.LEFT)
snakeBody.getFirst().setDirection(Direction.RIGHT);
break;
}
default:
System.out.println("位置案件");
}
}
});
setFocusable(true); // 确保面板能接收键盘事件
// 游戏循环
new Thread(() -> {
while (isRunning) {
try {
Thread.sleep(50);
moveSnake(); // 移动蛇
checkCollision(); // 检查碰撞
repaint(); // 调用paintComponent重绘
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
private void moveSnake() {
//获取蛇头
SnakeNode head = snakeBody.getFirst();
Point offset = Direction.getOffset(head.getDirection());
//(x',y')=(x,y)+offset*SIZE
int xNew= head.getPosition().x+offset.x*GameElement.SIZE;
int yNew= head.getPosition().y+offset.y*GameElement.SIZE;
//在新位置添加蛇头
snakeBody.addFirst(new SnakeNode(xNew, yNew, head.getDirection()));
//判断是否吃到食物
if(head.getPosition().equals(food.getPosition())){
//吃到食物
food.randomPosition(WIDTH, HEIGHT);
score++;
}
//删除蛇尾
else {
snakeBody.removeLast();
}
}
private void checkCollision() {
SnakeNode head = snakeBody.getFirst();
Point headPos = head.getPosition();
//撞墙
if(headPos.x<0||headPos.x>WIDTH||headPos.y<0||headPos.y>HEIGHT)
gameOver();
//撞自己
for(int i=1;i<snakeBody.size();i++){
if(snakeBody.get(i).getPosition().equals(headPos)){
gameOver();
break;
}
}
}
private void gameOver() {
isRunning = false;
JOptionPane.showMessageDialog(this, "游戏结束!得分:"+score);
System.exit(0);
}
// 核心改进重写paintComponent而非paint利用Swing双缓冲
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); // 先绘制背景(双缓冲关键步骤)
// 绘制蛇
for (SnakeNode node : snakeBody) {
node.draw(g);
}
// 绘制食物
food.draw(g);
}
}

View File

@@ -0,0 +1,18 @@
package view;
import javax.swing.*;
public class SnakeGame extends JFrame {
public SnakeGame() {
setTitle("贪吃蛇");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(new GamePanel()); // 添加游戏面板
pack(); // 自动调整窗口大小以适应面板
setLocationRelativeTo(null); // 窗口居中
setVisible(true);
}
public static void main(String[] args) {
new SnakeGame();
}
}

11
C10-Swing/C10-Swing.iml Normal file
View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

7
C10-Swing/src/Main.java Normal file
View File

@@ -0,0 +1,7 @@
import view.LoginFrame;
public class Main {
public static void main(String[] args) {
new LoginFrame();
}
}

View File

@@ -0,0 +1,54 @@
package utils;
import java.util.Random;
/**
* 验证码工具类
*/
public class CaptchaUtils { // final修饰类不能被继承
// 【任务1】静态常量字符集全局固定
static final String CHAR_SET="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
// 【任务2】静态常量验证码长度全局固定
static final int CAPTCHA_LENGTH=4;
// 【任务3】私有构造方法禁止创建实例工具类无需实例化
private CaptchaUtils(){
}
/**
* 【任务4】
* 静态方法generateCaptcha 生成随机验证码
* @return String 返回生成的随机验证码字符串
*/
public static String generateCaptcha(){
Random random = new Random();
//生成随机验证码
StringBuilder sb = new StringBuilder();
for(int i=0;i<CAPTCHA_LENGTH;i++){
//生成随机数索引
int index = random.nextInt(CHAR_SET.length());
//根据索引获取随机字符
sb.append(CHAR_SET.charAt(index));
}
return sb.toString();
}
/**
* 【任务5】
* 静态方法verifyCaptcha 验证验证码
* @param inputCaptcha 用户输入的验证码
* @param systemCaptcha 系统生成的验证码
* @return boolean 验证结果true表示验证通过false表示验证失败
*/
public static boolean verifyCaptcha(String inputCaptcha,String systemCaptcha){
return inputCaptcha.equalsIgnoreCase(systemCaptcha);
}
public static void main(String[] args) {
for(int i=0;i<10;i++)
System.out.println(generateCaptcha());
System.out.println(CaptchaUtils.verifyCaptcha(generateCaptcha(), generateCaptcha()));
}
}

View File

@@ -0,0 +1,129 @@
package view;
import javax.swing.*;
import java.awt.*;
import utils.CaptchaUtils;
public class LoginFrame extends JFrame {
private JPanel mainPanel;//中间层面板
private JTextField usernameTextField;//用户名输入框
private JPasswordField passwordField;//密码输入框
private JTextField captchaTextField;//验证码输入框
private JLabel captchaLabel;//验证码标签
private JButton loginButton;//登录按钮
private JButton registerButton;//注册按钮
public LoginFrame() {
initView();
}
//顶层容器
private void initView(){
//1.设置标题
setTitle("登录");
//2.设置点击关闭时的动作
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//3.中间层容器
add(initPanel());
//4.不允许窗口改变大小
setResizable(false);
//5.自动调整窗口大小 居中显示
pack();//自动调整窗口大小
setLocationRelativeTo(null);//剧中
//6.显示窗口
setVisible(true);
}
private JPanel initPanel(){
mainPanel = new JPanel();
GridLayout gridLayout = new GridLayout(6,1,10,10);
mainPanel.setLayout(gridLayout);
//第1层 空白面板 占用
mainPanel.add(new JPanel());
//第2层 账号面板
mainPanel.add(initAcountPanel());
//第3层 密码面板
mainPanel.add(initPasswordPanel());
//第4层 验证码面板
mainPanel.add(initCaptchaPanel());
//第5层 按钮面板
mainPanel.add(initButtonPanel());
//第6层 空白面板 占用
return mainPanel;
}
/**
* 初始化账户信息面板
* @return 包含用户名输入框的面板组件
*/
private JPanel initAcountPanel(){
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(1,4,10,0));
JLabel label = new JLabel("用户名:");
//让label居右
label.setHorizontalAlignment(SwingConstants.RIGHT);
usernameTextField = new JTextField(15);
panel.add(label);
panel.add(usernameTextField);
panel.add(new JPanel());
return panel;
}
/**
* 初始化密码输入面板
* @return 包含密码标签和输入框的JPanel面板
*/
private JPanel initPasswordPanel(){
JPanel panel = new JPanel();
// 设置网格布局1行4列水平间距10像素
panel.setLayout(new GridLayout(1,4,10,0));
JLabel label = new JLabel("密 码:");
// 设置标签文本右对齐
label.setHorizontalAlignment(SwingConstants.RIGHT);
passwordField = new JPasswordField(15);
panel.add(label);
panel.add(passwordField);
// 添加空白面板占位
panel.add(new JPanel());
return panel;
}
/**
* 初始化验证码面板
*
* @return 包含验证码相关组件的JPanel面板
*/
private JPanel initCaptchaPanel(){
// 创建面板并设置网格布局
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(1,4,10,0));
// 创建验证码标签
JLabel label = new JLabel("验证码:");
label.setHorizontalAlignment(SwingConstants.RIGHT);
// 创建验证码输入框和验证码显示标签
captchaTextField = new JTextField(4);
captchaLabel = new JLabel(CaptchaUtils.generateCaptcha());
// 将组件添加到面板中
panel.add(label);
panel.add(captchaTextField);
panel.add(captchaLabel);
return panel;
}
private JPanel initButtonPanel(){
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(1,4,10,0));
loginButton = new JButton("登录");
registerButton = new JButton("注册");
panel.add(new JPanel());
panel.add(loginButton);
panel.add(registerButton);
panel.add(new JPanel());
return panel;
}
}

11
C11-Swing/C11-Swing.iml Normal file
View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

7
C11-Swing/src/Main.java Normal file
View File

@@ -0,0 +1,7 @@
import view.LoginFrame;
public class Main {
public static void main(String[] args) {
new LoginFrame();
}
}

View File

@@ -0,0 +1,74 @@
package common;
/**
* 登录状态枚举类
* 用final保证状态信息不可变用static提供工具方法
*/
public enum LoginStatus {
// 【任务3】枚举实例状态码和描述
// 成功登录
SUCCESS(200,"登录成功"),
// 密码错误
PASSWORD_ERROR(901,"密码错误"),
// 验证码错误
CAPTCHA_ERROR(902,"验证码错误"),
// 用户不存在
USER_NOT_FOUND(903,"用户不存在");
// 【任务1】定义 final修饰的属性确保状态信息不可修改
private final int code;
private final String msg;
/**
* 【任务2】
* 构造函数用于创建LoginStatus实例
* @param code 状态码
* @param msg 状态消息
*/
LoginStatus(int code, String msg) {
this.code = code;
this.msg = msg;
}
// 静态方法根据状态码获取枚举实例static工具方法
/**
* 【任务4】
* 静态方法: getByCode 根据状态码获取对应的登录状态枚举值
* @param code 状态码
* @return LoginStatus 对应的LoginStatus枚举值如果找不到匹配的状态码则返回null
*/
public static LoginStatus getByCode(int code){
for(LoginStatus status:values()){
if(status.code==code){
return status;
}
}
return null;
}
// getter方法final属性无需setter
/**
* 【任务5】
* 方法: getCode 获取code值
*
* @return int code值
*/
public int getCode() {
return code;
}
/**
* 任务【6】
* 方法: getMsg 获取消息内容
*
* @return String 返回当前对象的消息字符串
*/
public String getMsg() {
return msg;
}
}

View File

@@ -0,0 +1,22 @@
package po;
public class AccountPo {
private String username;
private String password;
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;
}
}

View File

@@ -0,0 +1,27 @@
package service;
import common.LoginStatus;
import po.AccountPo;
public class AuthService {
private static AccountPo dbAccount = new AccountPo();
static {
dbAccount.setUsername("admin");
dbAccount.setPassword("123456");
}
public LoginStatus login(AccountPo account) {
//1.获取用户输入的账号在数据库中查询该账号信息
//2.账号不存在
//3.账号存在 比较密码是否一致
if (dbAccount.getUsername().equals(account.getUsername()) &&
dbAccount.getPassword().equals(account.getPassword()))
return LoginStatus.SUCCESS;
else if (!dbAccount.getUsername().equals(account.getUsername())) {
return LoginStatus.USER_NOT_FOUND;
}
return LoginStatus.PASSWORD_ERROR;
}
}

View File

@@ -0,0 +1,54 @@
package utils;
import java.util.Random;
/**
* 验证码工具类
*/
public class CaptchaUtils { // final修饰类不能被继承
// 【任务1】静态常量字符集全局固定
static final String CHAR_SET="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
// 【任务2】静态常量验证码长度全局固定
static final int CAPTCHA_LENGTH=4;
// 【任务3】私有构造方法禁止创建实例工具类无需实例化
private CaptchaUtils(){
}
/**
* 【任务4】
* 静态方法generateCaptcha 生成随机验证码
* @return String 返回生成的随机验证码字符串
*/
public static String generateCaptcha(){
Random random = new Random();
//生成随机验证码
StringBuilder sb = new StringBuilder();
for(int i=0;i<CAPTCHA_LENGTH;i++){
//生成随机数索引
int index = random.nextInt(CHAR_SET.length());
//根据索引获取随机字符
sb.append(CHAR_SET.charAt(index));
}
return sb.toString();
}
/**
* 【任务5】
* 静态方法verifyCaptcha 验证验证码
* @param inputCaptcha 用户输入的验证码
* @param systemCaptcha 系统生成的验证码
* @return boolean 验证结果true表示验证通过false表示验证失败
*/
public static boolean verifyCaptcha(String inputCaptcha,String systemCaptcha){
return inputCaptcha.equalsIgnoreCase(systemCaptcha);
}
public static void main(String[] args) {
for(int i=0;i<10;i++)
System.out.println(generateCaptcha());
System.out.println(CaptchaUtils.verifyCaptcha(generateCaptcha(), generateCaptcha()));
}
}

View File

@@ -0,0 +1,192 @@
package view;
import common.LoginStatus;
import utils.CaptchaUtils;
import service.AuthService;
import po.AccountPo;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class LoginFrame extends JFrame {
private JPanel mainPanel;//中间层面板
private JTextField usernameTextField;//用户名输入框
private JPasswordField passwordField;//密码输入框
private JTextField captchaTextField;//验证码输入框
private JLabel captchaLabel;//验证码标签
private JButton loginButton;//登录按钮
private JButton registerButton;//注册按钮
private AuthService authService = new AuthService();
public LoginFrame() {
//初始化界面
initView();
//注册监听器
initListener();
usernameTextField.setText("admin");
passwordField.setText("123456");
captchaTextField.setText(captchaLabel.getText());
}
//顶层容器
private void initView(){
//1.设置标题
setTitle("登录");
//2.设置点击关闭时的动作
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//3.中间层容器
add(initPanel());
//4.不允许窗口改变大小
setResizable(false);
//5.自动调整窗口大小 居中显示
pack();//自动调整窗口大小
setLocationRelativeTo(null);//剧中
//6.显示窗口
setVisible(true);
}
private void initListener(){
captchaLabel.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
captchaLabel.setText(CaptchaUtils.generateCaptcha());
}
});
loginButton.addActionListener(e -> {
//点击注册按钮后的事件
String username = usernameTextField.getText();
String password = passwordField.getText();
String captcha = captchaTextField.getText();
//System.out.println("用户名" + username + " 密码" + password + " 验证码" + captcha);
if(username.equals("")||password.equals("")||captcha.equals("")) {
JOptionPane.showMessageDialog(this, "请填写完整信息!", "提示", JOptionPane.INFORMATION_MESSAGE);
return;
}
if(!CaptchaUtils.verifyCaptcha(captcha,captchaLabel.getText())){
JOptionPane.showMessageDialog(this, LoginStatus.CAPTCHA_ERROR.getMsg(), "提示", JOptionPane.INFORMATION_MESSAGE);
return;
}
AccountPo account = new AccountPo();
account.setUsername(username);
account.setPassword(password);
LoginStatus loginStatus = authService.login(account);
if(loginStatus == LoginStatus.SUCCESS) {
//进入主界面
MainFrame mainFrame = new MainFrame();
this.dispose();
}
else if(loginStatus == LoginStatus.USER_NOT_FOUND) {
JOptionPane.showMessageDialog(this, LoginStatus.USER_NOT_FOUND.getMsg(), "提示", JOptionPane.INFORMATION_MESSAGE);
return;
}
else if(loginStatus == LoginStatus.PASSWORD_ERROR) {
JOptionPane.showMessageDialog(this, LoginStatus.PASSWORD_ERROR.getMsg(), "提示", JOptionPane.INFORMATION_MESSAGE);
return;
}
else{
JOptionPane.showMessageDialog(this, loginStatus.getMsg(), "提示", JOptionPane.INFORMATION_MESSAGE);
}
});
registerButton.addActionListener(e -> {
//点击注册按钮后的事件
return;
});
}
private JPanel initPanel(){
mainPanel = new JPanel();
GridLayout gridLayout = new GridLayout(6,1,10,10);
mainPanel.setLayout(gridLayout);
//第1层 空白面板 占用
mainPanel.add(new JPanel());
//第2层 账号面板
mainPanel.add(initAcountPanel());
//第3层 密码面板
mainPanel.add(initPasswordPanel());
//第4层 验证码面板
mainPanel.add(initCaptchaPanel());
//第5层 按钮面板
mainPanel.add(initButtonPanel());
//第6层 空白面板 占用
return mainPanel;
}
/**
* 初始化账户信息面板
* @return 包含用户名输入框的面板组件
*/
private JPanel initAcountPanel(){
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(1,4,10,0));
JLabel label = new JLabel("用户名:");
//让label居右
label.setHorizontalAlignment(SwingConstants.RIGHT);
usernameTextField = new JTextField(15);
panel.add(label);
panel.add(usernameTextField);
panel.add(new JPanel());
return panel;
}
/**
* 初始化密码输入面板
* @return 包含密码标签和输入框的JPanel面板
*/
private JPanel initPasswordPanel(){
JPanel panel = new JPanel();
// 设置网格布局1行4列水平间距10像素
panel.setLayout(new GridLayout(1,4,10,0));
JLabel label = new JLabel("密 码:");
// 设置标签文本右对齐
label.setHorizontalAlignment(SwingConstants.RIGHT);
passwordField = new JPasswordField(15);
panel.add(label);
panel.add(passwordField);
// 添加空白面板占位
panel.add(new JPanel());
return panel;
}
/**
* 初始化验证码面板
*
* @return 包含验证码相关组件的JPanel面板
*/
private JPanel initCaptchaPanel(){
// 创建面板并设置网格布局
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(1,4,10,0));
// 创建验证码标签
JLabel label = new JLabel("验证码:");
label.setHorizontalAlignment(SwingConstants.RIGHT);
// 创建验证码输入框和验证码显示标签
captchaTextField = new JTextField(4);
captchaLabel = new JLabel(CaptchaUtils.generateCaptcha());
// 将组件添加到面板中
panel.add(label);
panel.add(captchaTextField);
panel.add(captchaLabel);
return panel;
}
private JPanel initButtonPanel(){
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(1,4,10,0));
loginButton = new JButton("登录");
registerButton = new JButton("注册");
panel.add(new JPanel());
panel.add(loginButton);
panel.add(registerButton);
panel.add(new JPanel());
return panel;
}
}

View File

@@ -0,0 +1,7 @@
package view;
import javax.swing.*;
public class MainFrame {
JFrame frame = new JFrame();
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.