Part 1. 로그인에서 로그인 부분을 설명하였고, Part 2. 슬라이딩 퍼즐에 관련하여 설명하겠습니다.
Swing을 이용하여 슬라이딩 퍼즐 GUI를 만들었습니다.
Puzzle DTO
package Puzzle_pkg;
public class PuzzleData {
private String ID,Time,Rank;
public PuzzleData() {}
public PuzzleData(String ID, String Time){
this.ID = ID;
this.Time = Time;
}
public PuzzleData(String ID, String Time, String Rank){
this.ID = ID;
this.Time = Time;
this.Rank = Rank;
}
public PuzzleData(String ID){
this.ID = ID;
}
public String GetID(){
return ID;
}
public void SetID(String ID){
this.ID = ID;
}
public String GetTime(){
return Time;
}
public void SetTime(String Rank){
this.Time = Rank;
}
public String GetRank(){
return Rank;
}
public void SetRank(String Rank){
this.Rank = Rank;
}
}
Puzzle DAO
package Puzzle_pkg;
import java.util.*;
import java.sql.*;
public class PuzzleDB{
Connection conn = null;
ResultSet rs = null;
Statement st = null;
PreparedStatement ps = null;
public PuzzleDB() { // 생성자로 데이터베이스 연결
try {
final String url = "jdbc:mariadb://localhost:3306/puzzledb";
final String id = "root";
final String pw = "1234";
Class.forName("org.mariadb.jdbc.Driver");
conn = DriverManager.getConnection(url, id, pw);
}catch(ClassNotFoundException cnfe) {
System.out.println("DB 드라이버 로딩 실패:"+ cnfe.toString());
}catch(SQLException sqle){
System.out.println("DB 접속실패"+ sqle.toString());
}catch(Exception e){
System.out.println("Unkown error");
e.printStackTrace();
}
}
public void DBClose() { // 커넥션 연결 종료
try {
if(rs != null) rs.close();
if(st != null) st.close();
if(ps != null) ps.close();
} catch (Exception e) {
System.out.println(e + " => DBClose fail");
}
}
//퍼즐 정보 저장
public void InsertPuzzleDB(PuzzleData puzzledata) { // puzzle table -> puzzle data insert
try {
String sql = "insert into puzzle values(?, ?, ?)";
ps = conn.prepareStatement(sql);
ps.setString(1, puzzledata.GetID());
ps.setString(2, puzzledata.GetTime());
ps.setString(3, null);
ps.executeUpdate();
} catch(SQLException e) {
e.printStackTrace();
} finally {
DBClose();
}
}
// 퍼즐 정보 목록
public Vector<PuzzleData> PuzzleDBlist() // puzzle table -> puzzle data list
{
Vector<PuzzleData> Ar = new Vector<PuzzleData>();
try{
st = conn.createStatement();
String sql = "Select DENSE_RANK() OVER (ORDER BY Time ASC ) as RANK, ID, Time from puzzle";
rs = st.executeQuery(sql);
while (rs.next()) {
Ar.add(new PuzzleData(rs.getString(1), rs.getString(2), rs.getString(3)));
}
}catch (SQLException e) {
e.printStackTrace();
} finally {
DBClose();
}
return Ar;
}
Vector 사용하여 데이터형을 PuzzleData(DTO)로 정하였고, DB에 있는 퍼즐 정보를 불러와 저장하는 메소드입니다.
// 퍼즐 정보 업데이트
public void UpdatePuzzleDB(PuzzleData puzzledata) // puzzle table -> puzzle data update
{
try {
String Updata = "update puzzle set Rank = ?, where Time = ?;";
ps = conn.prepareStatement(Updata);
ps.setString(1, puzzledata.GetRank());
ps.setString(2, puzzledata.GetTime());
ps.executeUpdate();
}catch(SQLException e){
e.printStackTrace();
} finally {
DBClose();
}
}
퍼즐 정보를 수정하는 메소드입니다.
// 퍼즐 정보 삭제
public void Delete(String ID) // puzzle table -> puzzle data delete
{
String Delete = "delete from puzzle where ID = ?;";
try {
ps = conn.prepareStatement(Delete);
ps.setString(1, ID);
ps.executeUpdate();
}catch (SQLException e) {
e.printStackTrace();
} finally {
DBClose();
}
}
}
퍼즐 정보를 삭제하는 메소드입니다.
Puzzle Swing
package Puzzle_pkg;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import Login_pkg.LoginData;
import Login_pkg.LoginDB;
public class Puzzle_Swing extends JFrame {
PuzzleDB Pdb = new PuzzleDB();
LoginData Ldata = new LoginData();
LoginDB Ldb = new LoginDB();
private JButton changebtn; // 빈칸과 바꿀 칸 변경
private JButton[][] numbtn = new JButton[4][4]; // 15 까지의 버튼
private int[][] numcount = new int[4][4]; // 15까지의 숫자
private int row = 0, col = 0;
private static String timerBuffer; //경과 시간 문자열이 저장될 버퍼 정의
private static int oldTime; //타이머 시작 시각을 기억하고 있는 변수
public Puzzle_Swing() {
stopwatch(1); // 시간 측정 시작
// 배치
setTitle("슬라이딩 퍼즐");
setSize(350, 350);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container c = getContentPane();
c.setLayout(new GridLayout(4, 4));
int k = 1;
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
numbtn[i][j] = new JButton(String.valueOf(k));
numbtn[i][j].setFont(new Font("굴림체", Font.BOLD, 30));
c.add(numbtn[i][j]);
numbtn[i][j].addKeyListener(new MyKeyListener());
k++;
}
}
getNum();
display();
setVisible(true);
}
// 0~16 난수발생
public void getNum() {
int[] num = new int[16];
int n = 0;
boolean Check = false;
for (int i = 0; i < 16; i++) {
Check = true;
while (Check) {
n = (int) (Math.random() * 16);
Check = false;
for (int j = 0; j < i; j++) {
if (n == num[j]) // 같은 수 저장 방지
{
Check = true;
break;
}
}
}
num[i] = n;
numcount[i / 4][i % 4] = n;
if (n == 15) { // 랜덤 칸 생성
row = i / 4;
col = i % 4;
}
}
}
// 디스플레이
public void display() {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (i == row && j == col) {
numbtn[i][j].setText(String.valueOf(""));
numbtn[i][j].setEnabled(false);
} else {
System.out.println("numcount["+i+"]"+"["+j+"] "+numcount[i][j]+" ");
numbtn[i][j].setText(String.valueOf(numcount[i][j] + 1));
numbtn[i][j].setEnabled(true);
}
}
}
}
// 종료 여부 확인 numbtn 과 k 가 같으면 종료
public boolean isEnd() {
int k = 1;
try {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (Integer.parseInt(numbtn[i][j].getText()) != k)
return false;
System.out.println("k :"+k);
k++;
}
}
}catch(NumberFormatException e) {
}
return true;
}
private class MyKeyListener extends KeyAdapter {
public void keyPressed(KeyEvent e) {
boolean isEnd = false;
int keyCode = e.getKeyCode();
switch (keyCode) {
case KeyEvent.VK_UP: // 방향키 ↑ 클릭 시 동작
if (row == 0) { // 바깥 나감 방지
break;
} else {
changebtn = numbtn[row - 1][col]; // 변경할 위 버튼
numbtn[row][col].setText(String.valueOf(changebtn.getText())); // 변경할 버튼 숫자 변경
numbtn[row][col].setEnabled(true);
row = row - 1; // 위에를 다시 가리킴
changebtn = numbtn[row][col]; // 빈칸 버튼 지정
numbtn[row][col].setText("");
numbtn[row][col].setEnabled(false);
isEnd(); // 게임 종료 확인
if (isEnd) { // isEnd를 true로 변경하면 키보드 입력 시 테스트가 바로 가능 함.
String getID = JOptionPane.showInputDialog("아이디를 입력 해주세요.");
int s = Ldb.LoginOX(new LoginData(getID));
if(s== -1) {
JOptionPane.showMessageDialog(null, "아이디가 동일하지 않습니다.");
while(true) {
getID = JOptionPane.showInputDialog("아이디를 입력 해주세요.");
s = Ldb.LoginOX(new LoginData(getID));
if(s == 1) {
break;
}
else JOptionPane.showMessageDialog(null, "아이디가 동일하지 않습니다.");
}
JOptionPane.showMessageDialog(null, "등록 완료 ID: "+getID+", 걸린 시간: "+timerBuffer);
Pdb.InsertPuzzleDB(new PuzzleData(getID, timerBuffer));
System.exit(0);
}
else {
JOptionPane.showMessageDialog(null, "등록 완료 ID: "+getID+", 걸린 시간: "+timerBuffer);
Pdb.InsertPuzzleDB(new PuzzleData(getID, timerBuffer));
System.exit(0);
}
}
break;
}
case KeyEvent.VK_DOWN: // 방향키 ↓ 클릭 시 동작
if (row == 3) { // 바깥 나감 방지
break;
} else {
changebtn = numbtn[row + 1][col]; // 변경할 아래 버튼
numbtn[row][col].setText(String.valueOf(changebtn.getText())); // 변경할 버튼 숫자 변경
System.out.println("row : " + row + " col : " + col);
numbtn[row][col].setEnabled(true);
row = row + 1; // 아래를 다시 가리킴
changebtn = numbtn[row][col]; // 빈칸 버튼 지정
numbtn[row][col].setText("");
numbtn[row][col].setEnabled(false);
isEnd(); // 게임 종료 확인
if (isEnd) {
String getID = JOptionPane.showInputDialog("아이디를 입력 해주세요.");
int s = Ldb.LoginOX(new LoginData(getID));
if(s== -1) {
JOptionPane.showMessageDialog(null, "아이디가 동일하지 않습니다.");
while(true) {
getID = JOptionPane.showInputDialog("아이디를 입력 해주세요.");
s = Ldb.LoginOX(new LoginData(getID));
if(s == 1) {
break;
}
else JOptionPane.showMessageDialog(null, "아이디가 동일하지 않습니다.");
}
JOptionPane.showMessageDialog(null, "등록 완료 ID: "+getID+", 걸린 시간: "+timerBuffer);
Pdb.InsertPuzzleDB(new PuzzleData(getID, timerBuffer));
System.exit(0);
}
else {
JOptionPane.showMessageDialog(null, "Your message: "+getID);
Pdb.InsertPuzzleDB(new PuzzleData(getID, timerBuffer));
System.exit(0);
}
}
break;
}
case KeyEvent.VK_RIGHT: // 방향키 → 클릭 시 동작
if (col == 3) { // 바깥 나감 방지
break;
} else {
changebtn = numbtn[row][col + 1]; // 변경할 오른쪽 버튼
numbtn[row][col].setText(String.valueOf(changebtn.getText())); // 변경할 버튼 숫자 변경
System.out.println("row : " + row + " col : " + col);
numbtn[row][col].setEnabled(true);
col = col + 1; // 오른쪽을 다시 가리킴
changebtn = numbtn[row][col]; // 빈칸 버튼 지정
numbtn[row][col].setText("");
numbtn[row][col].setEnabled(false);
isEnd(); // 게임 종료 확인
if (isEnd) {
String getID = JOptionPane.showInputDialog("아이디를 입력 해주세요.");
int s = Ldb.LoginOX(new LoginData(getID));
if(s== -1) {
JOptionPane.showMessageDialog(null, "아이디가 동일하지 않습니다.");
while(true) {
getID = JOptionPane.showInputDialog("아이디를 입력 해주세요.");
s = Ldb.LoginOX(new LoginData(getID));
if(s == 1) {
break;
}
else JOptionPane.showMessageDialog(null, "아이디가 동일하지 않습니다.");
}
JOptionPane.showMessageDialog(null, "등록 완료 ID: "+getID+", 걸린 시간: "+timerBuffer);
Pdb.InsertPuzzleDB(new PuzzleData(getID, timerBuffer));
System.exit(0);
}
else {
JOptionPane.showMessageDialog(null, "Your message: "+getID);
Pdb.InsertPuzzleDB(new PuzzleData(getID, timerBuffer));
System.exit(0);
}
}
}
break;
case KeyEvent.VK_LEFT: // 방향키 ← 클릭 시 동작
if (col == 0) { // 바깥 나감 방지
break;
} else {
changebtn = numbtn[row][col - 1]; // 변경할 왼쪽 버튼
numbtn[row][col].setText(String.valueOf(changebtn.getText())); // 변경할 버튼 숫자 변경
System.out.println("row : " + row + " col : " + col);
numbtn[row][col].setEnabled(true);
col = col - 1; // 왼쪽을 다시 가리킴
changebtn = numbtn[row][col]; // 빈칸 버튼 지정
numbtn[row][col].setText("");
numbtn[row][col].setEnabled(false);
isEnd(); // 게임 종료 확인
if (isEnd) {
String getID = JOptionPane.showInputDialog("아이디를 입력 해주세요.");
int s = Ldb.LoginOX(new LoginData(getID));
if(s== -1) {
JOptionPane.showMessageDialog(null, "아이디가 동일하지 않습니다.");
while(true) {
getID = JOptionPane.showInputDialog("아이디를 입력 해주세요.");
s = Ldb.LoginOX(new LoginData(getID));
if(s == 1) {
break;
}
else JOptionPane.showMessageDialog(null, "아이디가 동일하지 않습니다.");
}
JOptionPane.showMessageDialog(null, "등록 완료 ID: "+getID+", 걸린 시간: "+timerBuffer);
Pdb.InsertPuzzleDB(new PuzzleData(getID, timerBuffer));
System.exit(0);
}
else {
JOptionPane.showMessageDialog(null, "Your message: "+getID);
Pdb.InsertPuzzleDB(new PuzzleData(getID, timerBuffer));
System.exit(0);
}
}
break;
}
}
stopwatch(0); // 시간 측정 종료
}
}
public static void stopwatch(int onOff) {
if (onOff == 1) //타이머 on
oldTime = (int) System.currentTimeMillis() / 1000;
if (onOff == 0) // 타이머 off, 시분초 timerBuffer 에 저장
secToHHMMSS( ((int) System.currentTimeMillis() / 1000) - oldTime );
}
// 정수로 된 시간을 초단위(sec)로 입력 받고, 문자열로 시분초를 저장
public static void secToHHMMSS(int secs) {
int hour, min, sec;
sec = secs % 60;
min = secs / 60 % 60;
hour = secs / 3600;
timerBuffer = String.format("%02d%02d%02d", hour, min, sec);
}
}
package Login_pkg;
public class LoginData {
private String ID;
private String Password;
public LoginData() { }
public LoginData(String ID, String Password){
this.ID = ID;
this.Password = Password;
System.out.println("ID"+ID);
}
public LoginData(String ID){
this.ID = ID;
}
public String GetID(){
return ID;
}
public void SetID(String Password){
this.Password = Password;
}
public String GetPassword(){
return Password;
}
public void SetPasswordD(String Password){
this.Password = Password;
}
}
LoginDAO
package Login_pkg;
import java.sql.*;
public class LoginDB {
private Connection conn = null;
private ResultSet rs = null;
private Statement st = null;
private PreparedStatement ps = null;
int count = 0;
public LoginDB() { // 생성자로 데이터 베이스 연결
final String url = "jdbc:mariadb://localhost:3306/puzzledb";
final String id = "root";
final String pw = "1234";
try{
Class.forName("org.mariadb.jdbc.Driver");
conn = DriverManager.getConnection(url, id, pw);
}catch(ClassNotFoundException cnfe) {
System.out.println("DB 드라이버 로딩 실패:"+ cnfe.toString());
}catch(SQLException sqle){
System.out.println("DB 접속실패"+ sqle.toString());
}catch(Exception e){
System.out.println("Unkown error");
e.printStackTrace();
}
}
public void DBClose(){ // 커넥션 연결 종료
try{
if(rs != null) rs.close();
if(st != null) st.close();
if(ps != null) ps.close();
}catch(Exception e) { System.out.println(e + "=> DBClose 실패");}
}
DB 연결 부분을 생성자로 구현하여, 클래스 객체 생성시 DB와 연결합니다.
// 회원 정보 저장
public void InsertLogin(LoginData logindata){
String sql = "insert into login values(?, ?, ?)";
try{
ps = conn.prepareStatement(sql);
st = conn.createStatement();
rs = st.executeQuery("Select * From login order by position*1");
while(rs.next())
{
int Number1 = rs.getInt("position");
if(Number1 == count) count++;
}
ps.setInt(1, count);
ps.setString(2, logindata.GetID());
ps.setString(3, logindata.GetPassword());
ps.executeUpdate();
count++;
}catch(SQLException e)
{
e.printStackTrace();
}finally
{
DBClose();
}
}
회원정보번호가 중복되지 않게 전역변수를 count로 만들고, DB의 position(회원정보번호)를 가져와 Number1 변수에 저장하여 count와 비교해 값을 증가시킨다. 마지막 while 루프를 돌게되면 count 값은 position보다 1이 증가한 값이 되게 됩니다.
// 회원 정보 삭제
public void Delete(String ID){ // login table -> Login ID data delete
String sql = "Delete from login where ID =?";
try{
ps = conn.prepareStatement(sql);
ps.setString(1, ID);
ps.executeUpdate();
}catch(SQLException e)
{
e.printStackTrace();
} finally
{
DBClose();
}
}
// ID, Password 확인
public int LoginTry(LoginData logindata){ // login table -> Login ID, Password Confirm
String sql = "select * from login where ID = ? and Password = ?";
try{
ps = conn.prepareStatement(sql);
ps.setString(1, logindata.GetID());
ps.setString(2, logindata.GetPassword());
rs = ps.executeQuery();
if(rs.next())
{
return 1;
}
}catch(Exception e)
{
e.printStackTrace();
}
return -1;
}
GUI 에서 입력한 ID, Password가 DB에 있는지 확인하는 메소드이다. 성공 시 1을 리턴하고, 실패시 -1을 리턴합니다.
// ID 확인
public int LoginOX(LoginData logindata){ // login_management table -> Login ID Confirm
String sql = "select * from login where ID = ?";
try{
ps = conn.prepareStatement(sql);
ps.setString(1, logindata.GetID());
rs = ps.executeQuery();
if(rs.next())
{
return 1;
}
}catch(Exception e)
{
e.printStackTrace();
}
return -1;
}
}
회원의 ID가 DB에 있는지 확인하는 메소드이다. 성공 시 1을 리턴하고, 실패시 -1을 리턴합니다.
LoginWindowBulder
package Login_pkg;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import java.awt.Color;
import Puzzle_pkg.Puzzle_Swing;
import Ranking_pkg.Ranking;
public class Login_WindowBuilder {
private JFrame frame;
private JTextField IDtext;
private JPasswordField passwordtext;
LoginDB db = new LoginDB();
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Login_WindowBuilder window = new Login_WindowBuilder();
window.frame.setVisible(true);
window.frame.setResizable(false);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public Login_WindowBuilder()
{
initialize();
}
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 401, 346);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
JPanel panel = new JPanel();
panel.setBackground(Color.WHITE);
panel.setBounds(0, 0, 385, 307);
frame.getContentPane().add(panel);
panel.setLayout(null);
JLabel IDLabel = new JLabel("ID : ");
IDLabel.setBounds(71, 122, 66, 33);
IDLabel.setHorizontalAlignment(SwingConstants.CENTER);
IDLabel.setFont(new Font("맑은 고딕", Font.BOLD, 18));
panel.add(IDLabel);
JLabel PassWordLabel = new JLabel("PW : ");
PassWordLabel.setBounds(71, 173, 66, 29);
PassWordLabel.setHorizontalAlignment(SwingConstants.CENTER);
PassWordLabel.setFont(new Font("맑은 고딕", Font.BOLD, 18));
panel.add(PassWordLabel);
IDtext = new JTextField();
IDtext.setBounds(149, 125, 145, 33);
IDtext.setToolTipText("ID 입력");
panel.add(IDtext);
IDtext.setColumns(10);
passwordtext = new JPasswordField();
passwordtext.setBounds(149, 172, 145, 33);
passwordtext.setToolTipText("PassWord 입력");
panel.add(passwordtext);
JLabel lblNewLabel = new JLabel("로그인 창");
lblNewLabel.setBounds(12, 10, 361, 81);
lblNewLabel.setHorizontalAlignment(SwingConstants.CENTER);
lblNewLabel.setFont(new Font("돋움체", Font.BOLD, 30));
panel.add(lblNewLabel);
JButton Loginbutton = new JButton("로그인");
Loginbutton.setBackground(Color.WHITE);
Loginbutton.setBounds(71, 243, 111, 47);
Loginbutton.addActionListener(new ActionListener() { // 로그인 버튼 클릭 시 동작
public void actionPerformed(ActionEvent arg0) {
String ID = IDtext.getText();
char[] PS1 = passwordtext.getPassword();
String PS = String.valueOf(PS1);
int s = db.LoginTry(new LoginData(ID,PS));
System.out.println(s);
if(s == 1) {
JOptionPane.showMessageDialog(null, "로그인 성공");
frame.dispose(); // 로그인 GUI 창 종료
Puzzle_Swing window = new Puzzle_Swing();
window.setVisible(true); // 슬라이딩 퍼즐 GUI 화면 나타남
window.setResizable(false); // GUI 창 크기 조절 불가능
Ranking window2 = new Ranking();
window2.frame.setVisible(true); // 랭킹 GUI 화면 나타남
window2.frame.setResizable(false); // GUI 창 크기 조절 불가능
} else JOptionPane.showMessageDialog(null, "로그인 실패");
}
});
Loginbutton.setFont(new Font("맑은 고딕", Font.PLAIN, 15));
panel.add(Loginbutton);
JButton button = new JButton("회원 가입");
button.setBackground(Color.WHITE);
button.setBounds(211, 243, 111, 47);
button.addActionListener(new ActionListener() { // 회원 가입 버튼 클릭 시 동작
public void actionPerformed(ActionEvent e) {
String ID = IDtext.getText();
char[] PS1 = passwordtext.getPassword();
String PS = String.valueOf(PS1);
System.out.println();
System.out.println(passwordtext.getPassword());
if(ID.length() != 0 && PS.length() != 0){
db.InsertLogin(new LoginData(ID, PS));
IDtext.setText(""); passwordtext.setText("");
JOptionPane.showMessageDialog(null, "등록 완료");
}else JOptionPane.showMessageDialog(null, "ID , PW 입력 바람.");
}
});
button.setFont(new Font("맑은 고딕", Font.PLAIN, 15));
panel.add(button);
}
}