系列文章目錄
Java文件 I/O流的操作實戰和高級UI組件和事件監聽的綜合
文章目錄
- 系列文章目錄
- 前言
- 一、大致流程思路分析:
- 二、定義用戶類:
- 三、服務層的實現:
- 1.保護用戶數據功能的實現
- 2.登錄操作的實現
- 四、實現用戶的注冊界面:
- 大體流程:
- 五、實現用戶的登錄界面(在這里面相當于總界面)
- 大體流程:
- 六、在實現時的易錯點:
- 以我自己舉例:
- 總結
前言
? ? 在學習完文件和IO流的操作后,包括事件監聽機制和UI組件以后,我們可能會想這些知識可以用來干什么,今天我們就用一個實戰案例來幫大家將學過的知識運用起來。(但是這個實戰案例本來是可以用數據庫與Java進行連接,但是這篇我們也可以用將用戶數據存儲到文件當中來實現,因為像MySQL等數據庫,本質都是存儲在文件當中的)。
一、大致流程思路分析:
? ? ? ? 我將用最通俗易懂的話向大家解釋一下這個的具體流程:
? ? ?首先我們想要實現用戶的注冊和登錄功能,就要先定義出來用戶類,把用戶的數據當作成員屬性定義出來,然后我們需要建一個窗口來實現登錄,注冊,重置的操作,注冊和登錄需要我們輸入文本,這些都是基礎的,最關鍵的操作是什么呢?
? ? ?就是要定義一個能實現注冊和登錄的類作為服務層,注冊的時候就是把在窗口得到的數據寫到文件當中存儲起來,那文件當中肯定會有一個又一個的用戶的數據,因此我們實現登錄的功能就需要把這些個用戶全都讀取出來,和登錄窗口得到的文本核對,看是否能登錄成功,大體流程就是這些,反正就是服務層和窗口層的連接,包括數據庫的連接也是如此,這個我們后來再講。
二、定義用戶類:
? ? 首先我們需要把用戶當成一個用戶類,它的屬性就是我們理解的用戶的數據。
? ? ? ? ? ?這里面的用戶數據包括了:用戶名,密碼,性別,愛好,地址,學歷。
? ? ? ? ?以下是代碼:
public class User {//用戶實體private int id; //用戶private String userName; //用戶名private String passWord; //密碼private int sex; //性別private String hobby; //愛好private String address; //地址private String degree; //學歷public User(String userName, String passWord, int sex, String hobby, String address, String degree) {this.userName = userName;this.passWord = passWord;this.sex = sex;this.hobby = hobby;this.address = address;this.degree = degree;}public User(int id, String userName, String passWord, int sex, String hobby, String address, String degree) {this.id = id;this.userName = userName;this.passWord = passWord;this.sex = sex;this.hobby = hobby;this.address = address;this.degree = degree;}public void setId(int id) {this.id = id;}public void setUserName(String userName) {this.userName = userName;}public void setPassWord(String passWord) {this.passWord = passWord;}public void setSex(int sex) {this.sex = sex;}public void setAddress(String address) {this.address = address;}public void setHobby(String hobby) {this.hobby = hobby;}public void setDegree(String degree) {this.degree = degree;}public int getId() {return id;}public String getUserName() {return userName;}public String getPassWord() {return passWord;}public String getHobby() {return hobby;}public int getSex() {return sex;}public String getAddress() {return address;}public String getDegree() {return degree;}}
三、服務層的實現:
public static String filePath = "E:\\User.txt";private static final String DELIMITER = "|";
? ?先創建出來文件路徑,以方便下面的操作。
1.保存用戶數據功能的實現:
? ? ? ?這個方法是用來將用戶的數據讀取到文件當中的、
以下是代碼實現:
public boolean saveUser(User user) throws IOException {File file = new File(filePath);if (!file.exists()) {if (!file.createNewFile()) {System.out.println("存儲用戶文件創建失敗");return false;}}//下面開始對文件進行輸入保存BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePath, true));//這是我們在注冊窗口時通過輸入的文本框的內容放在一個User對象// 得到我們在注冊時的用戶信息String userData = String.join(DELIMITER, String.valueOf(user.getId()), user.getUserName(),user.getPassWord(), String.valueOf(user.getSex()), user.getHobby(),user.getAddress(), user.getDegree());bufferedWriter.write(userData);bufferedWriter.newLine();bufferedWriter.close();return true;}
? ? ? ? ?2.登錄操作的實現(即從文件中讀取數據)
?這里面最關鍵的一點是:
我們要想對登錄的用戶進行驗證,首先肯定要得到存儲在文件中的所有用戶資源 因此我們肯定需要寫一個ReadAllUsers的方法,然后再對每一個對象進行一一遍歷
? 以下是代碼實現:
//這個方法用來完成登錄的操作// 首先我們肯定要得到用戶名和密碼,這個應該是在界面層通過輸入的文本來得到// 相應的用戶名和密碼進行驗證public boolean vaildateLogin(String inputUserName,String inputPassWord) throws IOException {//我們要想對登錄的用戶進行驗證,首先肯定要得到存儲在文件中的所有用戶資源//因此我們肯定需要寫一個ReadAllUsers的方法,然后再對每一個對象進行一一遍歷List<User> users = readAllUsers();//下面開始對文件當中的每一個用戶數據進行驗證判斷是否能登陸成功for(User user:users){if(user.getUserName().equals(inputUserName)&&user.getPassWord().equals(inputPassWord)){return true;}}return false;}public List<User> readAllUsers() throws IOException {//先創建一個列表來存放每一個用戶數據對象List<User> list = new ArrayList<>();File file = new File(filePath);if (file.exists()) {//開始進行讀操作BufferedReader bufferedReader = new BufferedReader(new FileReader(file));String line;while ((line = bufferedReader.readLine()) != null) {String[] parts = line.split("\\" + DELIMITER);//下面開始創建User對象并傳入到列表當中if (parts.length == 7) {list.add(new User(Integer.parseInt(parts[0]), // IDparts[1], // 用戶名parts[2], // 密碼Integer.parseInt(parts[3]), // 性別parts[4], // 愛好parts[5], // 地址parts[6] // 學歷));}}}return list;}
? 四、實現用戶的注冊界面:
? ?大體流程:? ? ? ?
? ? ? ? 對于注冊界面我們肯定要設置標簽和文本框,還需要設置布局方式,并且對確認和重置按鈕作監聽。
下面是代碼的實現:
? ?
public class RegistFrame extends JFrame {//這是實現用戶注冊界面//主面板private JPanel p;//標簽private JLabel lblName, lblPwd, lblRePwd, lblSex, lblHobby,lblAdress, lblDegree;//用戶名文本框private JTextField txtName;//密碼共和確認密碼文本框private JPasswordField txtPwd, txtRepwd;//性別,單選按鈕private JRadioButton rbMale, rbFemale;//愛好,多選框private JCheckBox ckbRead, ckbNet, ckbSwim, ckbTour;//地址,文本框private JTextArea txtAdress;//學歷,組合框private JComboBox<String> cmbDegree;//確認和取消,按鈕private JButton btnOk, btnCancle;//注冊的用戶private static User user;//用戶業務類private UserService userService;//構造方法public RegistFrame() {super("用戶注冊");//實例化用戶業務類對象userService = new UserService();//設置窗體的icon
//.......//設置面板布局,網格布局p = new JPanel(new GridLayout(8, 1, 0, 10));//實例化組件lblName = new JLabel("用 戶 名:");lblPwd = new JLabel("密 碼:");lblRePwd = new JLabel("確認密碼:");lblSex = new JLabel("性 別:");lblHobby = new JLabel("愛 好:");lblAdress = new JLabel("地 址:");lblDegree = new JLabel("學 歷");txtName = new JTextField(25);txtPwd = new JPasswordField(25);txtRepwd = new JPasswordField(25);rbMale = new JRadioButton("男");rbFemale = new JRadioButton("女");//性別的單選邏輯ButtonGroup bg = new ButtonGroup();bg.add(rbMale);bg.add(rbFemale);ckbRead = new JCheckBox("閱讀");ckbNet = new JCheckBox("上網");ckbSwim = new JCheckBox("游泳");ckbTour = new JCheckBox("旅游");txtAdress = new JTextArea(3, 20);//組合框顯示學歷數組// 正確初始化組合框cmbDegree = new JComboBox<>(new String[]{"小學", "初中", "高中", "本科", "碩士", "博士"});//設置組合框可編輯cmbDegree.setSelectedIndex(0);// 默認選中第一項cmbDegree.setPreferredSize(new Dimension(200, 30));cmbDegree.setEditable(true);btnOk = new JButton("確定");btnCancle = new JButton("重置");btnOk.setPreferredSize(new Dimension(120, 35)); // 寬度120,高度35btnCancle.setPreferredSize(new Dimension(120, 35));Font bigFont = new Font("宋體", Font.PLAIN, 16);// 統一設置組件字體txtName.setFont(bigFont);txtPwd.setFont(bigFont);txtRepwd.setFont(bigFont);rbMale.setFont(bigFont);rbFemale.setFont(bigFont);ckbRead.setFont(bigFont);ckbNet.setFont(bigFont);ckbSwim.setFont(bigFont);ckbTour.setFont(bigFont);txtAdress.setFont(bigFont);cmbDegree.setFont(bigFont);btnOk.setFont(bigFont);btnCancle.setFont(bigFont);//這一步需要注冊監聽器,監聽確定按鈕btnOk.addActionListener(new RegisterListener());//還需要注冊監聽器,監聽重置按鈕btnCancle.addActionListener(new ResetListener());/*將組件分組放入面板,然后將小面板放入主面板*/JPanel p1 = new JPanel(new FlowLayout(FlowLayout.LEFT));p1.setBorder(BorderFactory.createEmptyBorder(5,10,5,10));p1.add(lblName);p1.add(txtName);p.add(p1);JPanel p2 = new JPanel(new FlowLayout(FlowLayout.LEFT));p2.setBorder(BorderFactory.createEmptyBorder(5,10,5,10));p2.add(lblPwd);p2.add(txtPwd);p.add(p2);JPanel p3 = new JPanel(new FlowLayout(FlowLayout.LEFT));p3.setBorder(BorderFactory.createEmptyBorder(5,10,5,10));p3.add(lblRePwd);p3.add(txtRepwd);p.add(p3);JPanel p4 = new JPanel(new FlowLayout(FlowLayout.LEFT));p4.setBorder(BorderFactory.createEmptyBorder(5,10,5,10));p4.add(lblSex);p4.add(rbMale);p4.add(rbFemale);p.add(p4);JPanel p5 = new JPanel(new FlowLayout(FlowLayout.LEFT));p5.setBorder(BorderFactory.createEmptyBorder(5,10,5,10));p5.add(lblHobby);p5.add(ckbRead);p5.add(ckbNet);p5.add(ckbSwim);p5.add(ckbTour);p.add(p5);JPanel p6 = new JPanel(new FlowLayout(FlowLayout.LEFT));p6.setBorder(BorderFactory.createEmptyBorder(5,10,5,10));p6.add(lblAdress);p6.add(txtAdress);p.add(p6);JPanel p7 = new JPanel(new FlowLayout(FlowLayout.LEFT));p7.setBorder(BorderFactory.createEmptyBorder(5,10,5,10));p7.add(lblDegree);p7.add(cmbDegree);p.add(p7);JPanel p8 = new JPanel(new FlowLayout(FlowLayout.CENTER));p8.setBorder(BorderFactory.createEmptyBorder(5,10,5,10));p8.add(btnOk);p8.add(btnCancle);p.add(p8);//主面板放入窗體中this.add(p);//設置窗體的大小和位置居中this.setSize(450, 500);this.setLocationRelativeTo(null);//設置窗體不可改變大小this.setResizable(false);//設置窗體初始可見this.setVisible(true);}//監聽類,負責處理確認按鈕的業務邏輯private class RegisterListener implements ActionListener {@Overridepublic void actionPerformed(ActionEvent e) {//獲取用戶輸入的數據String userName = txtName.getText().trim();String passWord = new String(txtPwd.getPassword());String rePassWord = new String(txtRepwd.getPassword());//將性別"男""女"對應轉化為"1""0"int sex = Integer.parseInt(rbFemale.isSelected() ? "0" : "1");String hobby = (ckbRead.isSelected() ? "閱讀" : "")+ (ckbNet.isSelected() ? "上網" : "")+ (ckbSwim.isSelected() ? "游泳" : "")+ (ckbTour.isSelected() ? "旅游" : "");String address = txtAdress.getText();Object selectedDegree = cmbDegree.getSelectedItem();String degree = (selectedDegree != null) ? selectedDegree.toString().trim() : "";//判斷兩次輸入密碼是否一致if (passWord.equals(rePassWord)) {//將數據封裝到對象當中user = new User(userName, passWord, sex, hobby, address, degree);//保存數據try {if (userService.saveUser(user)) {System.out.println("注冊成功!");}} catch (IOException ex) {throw new RuntimeException(ex);}} else {System.out.println("兩次密碼輸入的不一致!");}}}public class ResetListener implements ActionListener {@Overridepublic void actionPerformed(ActionEvent e) {//清空姓名,密碼,確認密碼等內容txtName.setText("");txtPwd.setText("");txtRepwd.setText("");//重置單選按鈕為未選擇rbMale.setSelected(false);rbFemale.setSelected(false);//重置所有復選按鈕為未選擇ckbRead.setSelected(false);ckbNet.setSelected(false);ckbSwim.setSelected(false);ckbTour.setSelected(false);//清空地址欄txtAdress.setText("");//重置組合框為未選擇狀態cmbDegree.setSelectedIndex(0);}}}
?五、實現用戶的登錄界面(在這里面相當于總界面)
? ? ? ? ? 大體流程:
這里的用戶登錄肯定也需要多個組件,用戶名和密碼的標簽和文本框,然后登錄,注冊,重置按鈕,并對其實現監聽機制,這里面需要和服務層的登錄方法匹配
? ? 以下是代碼實現:
??
/*** @author 袁敬堯* @version 1.0*/
public class LoginFrame extends JFrame {//這是用戶登錄 注冊界面,我們需要多個組件//主面板private JPanel p;//標簽private JLabel lblName, lblPwd;//用戶名,文本框private JTextField txtName;//密碼,密碼框private JPasswordField txtPwd;//確認,取消和注冊,按鈕private JButton btnOk, btnCancle, btnRegist;//登錄用戶private static User user;//用戶業務類private UserService userService;//構造方法public LoginFrame() {super("登錄");//實例化用戶業務類對象userService = new UserService();//實例化組件p = new JPanel();Font inputFont = new Font("微軟雅黑", Font.PLAIN, 16);//使用null布局p.setLayout(null);lblName = new JLabel("用戶名:");lblPwd = new JLabel("密碼:");txtName = new JTextField(20);txtPwd = new JPasswordField(20);txtPwd.setEchoChar('*');btnOk = new JButton("登錄");btnOk.addActionListener(new LoginListener());btnCancle = new JButton("重置");btnCancle.addActionListener(new ResetListener());btnRegist = new JButton("注冊");btnRegist.addActionListener(new RegistListener());lblName.setBounds(30, 30, 80, 30); // 增大標簽寬度lblPwd.setBounds(30, 80, 80, 30); // 下移密碼標簽位置txtName.setBounds(120, 30, 200, 30); // 寬度200 → 300txtPwd.setBounds(120, 80, 200, 30); // 同用戶名框對齊btnOk.setBounds(50, 130, 80, 35); // 增大按鈕尺寸btnCancle.setBounds(150, 130, 80, 35);btnRegist.setBounds(250, 130, 80, 35);p.add(lblName);p.add(txtName);p.add(lblPwd);p.add(txtPwd);p.add(btnOk);p.add(btnCancle);p.add(btnRegist);txtName.setFont(inputFont);txtPwd.setFont(inputFont);//主面板放入窗體中this.add(p);//設置窗體的大小和位置this.setSize(420, 300);//設置窗口在屏幕中央this.setLocationRelativeTo(null);//設置窗體的默認關閉按鈕this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//設置窗體初始可見this.setVisible(true);}public class LoginListener implements ActionListener {@Overridepublic void actionPerformed(ActionEvent e) {//這里我在服務層里面已經寫好了驗證的數據String userName = txtName.getText().trim();String passWord = new String(txtPwd.getPassword());try {if (userService.vaildateLogin(userName,passWord)) {LoginFrame.this.setVisible(false);JOptionPane.showMessageDialog(null,"登錄成功!歡迎您:" + userName,"系統提示",JOptionPane.INFORMATION_MESSAGE);}else{//輸出提示信息System.out.println("密碼錯誤,請重新輸入");//清空密碼框txtPwd.setText("");txtName.setText("");}} catch (IOException ex) {throw new RuntimeException(ex);}}}//監聽類,負責處理重置按鈕public class ResetListener implements ActionListener{@Overridepublic void actionPerformed(ActionEvent e) {txtName.setText("");txtPwd.setText("");}}//監聽類,負責處理注冊按鈕public class RegistListener implements ActionListener{@Overridepublic void actionPerformed(ActionEvent e) {new RegistFrame();}}public static void main(String[] args){new LoginFrame();}}
? ? 六、在實現時的易錯點:
? ? ?以我自己舉例:
? ? ? ? ? ? ? 我在實現這個功能的時候,就報了空指針異常的錯誤,包括像我當時寫坦克大戰的時候也犯了空指針異常的錯誤,因為可能我們使用的類還沒有分配內存就被使用了,那肯定會拋異常的,
private JComboBox<String> cmbDegree;
...
cmbDegree.setEditable(true); // 未初始化直接調用方法
我這里面未初始化就直接調用方法了
// 正確初始化組合框
private JComboBox<String> cmbDegree = new JComboBox<>(new String[]{"小學", "初中", "高中", "本科", "碩士", "博士"});
密碼字段也錯了
// LoginFrame.java
String userPwd = txtPwd.getPassword().toString(); // 錯誤!得到的是數組地址// RegistFrame.java
String passWord = new String(txtPwd.getPassword()); // 正確但未去空格
具體改正:
// LoginFrame.java
String userPwd = new String(txtPwd.getPassword()).trim(); // 轉換為字符串并去空格// RegistFrame.java
String passWord = new String(txtPwd.getPassword()).trim();
還有最關鍵的一點就是使用文件流一定要記得關流。
總結
以上就是我要講的內容了,這是一個實現用戶登錄和注冊的基本功功能,其實這個還有很多可以擴充功能的,具體怎么實現我會和大家一起思考的,下面兩周我會持續更新藍橋杯算法題的,希望大家多多關注,我們一起加油,謝謝大家。