(三)、《学生管理项目》设计
1、完成效果图
2、完整的代码
- SchoolClassDAO.java
package org.ngweb.student.dao;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import org.ngweb.student.model.SchoolClass;
public class SchoolClassDAO {
//1. 私有变量,保存的文件名
private String fileName;
//2. 初始化文件名
public SchoolClassDAO(String fileName) {
this.fileName = fileName;
}
//save方法:保存
public void save(SchoolClass schoolClass) {
try {
ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream(fileName));
oos.writeObject(schoolClass);
oos.close();
}catch(Exception e) {
e.printStackTrace();
}
}
//read方法:读取
public SchoolClass read() {
//保存读取的class
SchoolClass schoolClass = null;
try {
ObjectInputStream ois = new ObjectInputStream(
new FileInputStream(fileName));
schoolClass = (SchoolClass)ois.readObject();
ois.close();
}catch(Exception e) {
e.printStackTrace();
}
return schoolClass;
}
}
-IPerson.java
package org.ngweb.student.model.interfaze;
import java.io.Serializable;
import org.ngweb.student.model.ValidatorException;
public interface IPerson extends Serializable{
//从Person中复制的get\set方法体,由于这里不能有方法体,所以删除方法体,得到抽象类。
public String getId();
public void setId(String id);
public String getName();
public void setName(String name)throws ValidatorException;
public int getAge();
public void setAge(int age)throws ValidatorException;
public String getEmail();
public void setEmail(String email)throws ValidatorException;
}
- Person.java
package org.ngweb.student.model;
//6. 导入UUID包
import java.util.UUID;
import java.util.regex.*;
import org.ngweb.student.model.interfaze.IPerson;
//1. Person是实现IPerson的所以implements
public class Person implements IPerson {
//2. 设置每个人的属性,为私有private
private String id;
private String name;
private int age;
private String email;
//4. 构造方法:
//5. ID:唯一标识符,使用UUID:全球唯一标识码
public Person() {
id = UUID.randomUUID().toString();
this.age=0;
}
public Person(String name, int age,String email) throws ValidatorException {
this();
//7. this()来调用自己的构造方法
//11. 直接赋值改为set赋值
setName(name);
setAge(age);
setEmail(email);
}
//3. 自动加上get、set
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) throws ValidatorException {
//13: public void setName(String name) throws ValidatorException
//13.1:声明抛出异常,出现错误原因:set这个方法应该是从IPerson继承来的,IPerson
//里的set方法没有抛出更多的方法,在实现一个抽象类的时候,实现方法不能比抽象方法抛出更多的异常
//
//8.姓名的校验,java的字符36位
if(name.length()<2 || name.length()>4) {
this.name = "";//不能为空值
//12.添加异常处理
throw new ValidatorException("姓名的长度不符合要求。");
}
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) throws ValidatorException {
//9.年龄的校验
if(age<15 || age>28) {
this.age = -1;
throw new ValidatorException("年龄值不符合要求。");
}
this.age = age;
}
public String getEmail() {
return email;
}
public void setEmail(String email) throws ValidatorException {
//10.对电子邮箱的校验
Pattern pattern = Pattern
.compile("\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*");
Matcher matcher = pattern.matcher(email);
if(!matcher.matches()) {
this.email = "";
throw new ValidatorException("电子邮件格式不对。");
}
this.email = email;
}
}
- SchoolClass.java
package org.ngweb.student.model;
import java.io.Serializable;
import java.util.*;
public class SchoolClass implements Serializable{
//1. map对象:保存班级的所有学生
//6. map是无序的,所以采用LinkedHashMap
private Map<String, Student> map =new LinkedHashMap<String, Student>();
public Map<String, Student> getMap() {
return map;
}
public void setMap(Map<String, Student> map) {
this.map = map;
}
//2. 增删改学生的功能的方法:
//2.1 增
public void insertStudent(Student student) {
map.put(student.getId(), student);
}
//4. 增加一个方法,用于取得第index位学生
//4.1:使用的是一个整形参数,用于从map里下标为index的学生
public Student getStudent(int index) {
Set<String> set = map.keySet();
if(index<-1||index>=set.size()) {
return null;
}
Iterator<String> it = set.iterator();
for(int i=0;i<index;i++) {
it.next();
}
return map.get(it.next());
}
//5. 取得班级中的学生
public int getStudentCount() {
return map.size();
}
//2.2 删
public void deleteStudent(Student student) {
map.remove(student.getId());
}
//2.3 更新
public void updateStudent(Student student) {
map.put(student.getId(), student);
}
//2.4获取
public Student getStudent(String studentID) {
return map.get(studentID);
}
//3. 计算全班某门课的平均成绩
public double averageScore(int courseIndex) {
double sum = 0;
Set set = map.keySet();
Iterator it = set.iterator();
while(it.hasNext()) {
String key=(String)it.next();
Student s = map.get(key);
sum += s.getScore()[courseIndex];
}
return sum/map.size();
}
}
- Student.java
package org.ngweb.student.model;
//1. 扩展继承Person类
public class Student extends Person {
//2. 自己的属性
//3. 最大的课程门数,课程名称
public static final int maxCourse = 3;
public static String[] courseName = {"语文","数学","英语"};
private int[] score;//4. 乘积数组
//5. 只需要对score设置get、set方法
//7. 创建自己的构造方法:
public Student() {
super();
int[] score = {0,0,0};
this.score = score;
}
public Student(String name, int age, String email,int[] score) throws ValidatorException {
super(name , age, email);
setScore(score);
}
public int[] getScore() {
return score;
}
public void setScore(int[] score)throws ValidatorException{
//7. 对乘积进行校验
for(int i = 0;i<maxCourse;i++) {
if(score[i]<0 || score[i]>100) {
score[i]=-1;
this.score = null;
throw new ValidatorException(courseName[i]+"的成绩超出百分制的范围。");
}
}
this.score = score;
}
//6. 一个只读性变量,用于返回一个学生成绩的平均值
public double getAvScore() {
double sum = 0;
for (int i= 0;i<maxCourse;i++) {
sum +=score[i];
}
return sum/maxCourse;
}
}
- ValidatorException.java
package org.ngweb.student.model;
//自定义异常
public class ValidatorException extends Exception{
public ValidatorException(String msg) {
super(msg);
}
}
- DaoTest.java
package org.ngweb.student.test;
import org.ngweb.student.dao.SchoolClassDAO;
import org.ngweb.student.model.*;
import junit.framework.*;
public class DaoTest extends TestCase {
public void testDao(){
SchoolClassDAO dao = new SchoolClassDAO("d:/class831");
SchoolClass shoolClass = new SchoolClass();
Student student;
try {
student = new Student("王明", 23, "wangm@qq.com", new int[] {
82, 93, 88 });
student.setId("1001");
shoolClass.insertStudent(student);
student = new Student("李倩", 22, "liq@qq.com", new int[] {
94, 89, 91 });
student.setId("1002");
shoolClass.insertStudent(student);
dao.save(shoolClass);
} catch (ValidatorException e) {
e.printStackTrace();
}
// read from file
SchoolClass shoolClass1 = new SchoolClass();
Student s;
shoolClass1=dao.read();
s = shoolClass1.getStudent("1001");
Assert.assertEquals("王明", s.getName());
}
}
- StudentTest.java
package org.ngweb.student.test;
import org.ngweb.student.model.Student;
import org.ngweb.student.model.ValidatorException;
public class StudentTest {
public static void main(String[] args) {
Student[] student = new Student[2];
try {
student[0] = new Student("王明", 23, "wangm@qq.com", new int[] {
82, 93, 88 });
} catch (ValidatorException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
student[1] = new Student("李倩", 22, "liq@qq.com", new int[] {
94, 89, 91 });
} catch (ValidatorException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for (int i = 0; i < student.length; i++) {
System.out.println("\n第" + (i + 1) + "位学生的信息如下 :");
System.out.println("\t姓名=" + student[i].getName() + ", 年龄="
+ student[i].getAge() + ", 电子邮件=" + student[i].getEmail());
System.out.print("\t\t成绩为:");
for (int j = 0; j < Student.maxCourse; j++) {
System.out.print(Student.courseName[j] + "="
+ student[i].getScore()[j] + " ");
}
System.out.print("\n\t\t平均成绩为:");
System.out.println(student[i].getAvScore());
}
}
}
- StudentUnitTest.java
package org.ngweb.student.test;
import org.ngweb.student.model.Student;
import org.ngweb.student.model.ValidatorException;
import junit.framework.Assert;
import junit.framework.TestCase;
public class StudentUnitTest extends TestCase {
public void testValidateName1(){
Student s = new Student();
try {
s.setName("李");
} catch (ValidatorException e) {
System.out.println(e.getMessage());
}
Assert.assertEquals("", s.getName());
}
public void testValidateName2(){
Student s = new Student();
try {
s.setName("错误的名字");
} catch (ValidatorException e) {
System.out.println(e.getMessage());
}
Assert.assertEquals("", s.getName());
}
public void testValidateName3(){
Student s = new Student();
try {
s.setName("李明");
} catch (ValidatorException e) {
System.out.println(e.getMessage());
}
Assert.assertEquals("李明", s.getName());
}
public void testValidateAge1(){
Student s = new Student();
try {
s.setAge(32);
} catch (ValidatorException e) {
System.out.println(e.getMessage());
}
Assert.assertEquals(-1, s.getAge());
}
public void testValidateAge2(){
Student s = new Student();
try {
s.setAge(12);
} catch (ValidatorException e) {
System.out.println(e.getMessage());
}
Assert.assertEquals(-1, s.getAge());
}
public void testValidateAge3(){
Student s = new Student();
try {
s.setAge(22);
} catch (ValidatorException e) {
System.out.println(e.getMessage());
}
Assert.assertEquals(23, s.getAge());
}
public void testValidateEmail1(){
Student s = new Student();
try {
s.setEmail("abc#aa.cc");
} catch (ValidatorException e) {
System.out.println(e.getMessage());
}
Assert.assertEquals("", s.getEmail());
}
public void testValidateEmail2(){
Student s = new Student();
try {
s.setEmail("abc@aa.cc");
} catch (ValidatorException e) {
System.out.println(e.getMessage());
}
Assert.assertEquals("abc@aa.cc", s.getEmail());
}
public void testValidateScore(){
Student s = new Student();
try {
s.setScore( new int[] {101, 93, 88 });
} catch (ValidatorException e) {
System.out.println(e.getMessage());
}
Assert.assertEquals(null, s.getScore());
}
}
- StudentMgrSys.java
package org.ngweb.student.view;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.io.*;
import org.ngweb.student.dao.SchoolClassDAO;
import org.ngweb.student.model.*;
public class StudentMgrSys extends JFrame implements ActionListener {
// 通过班级来管理班上的学生
private SchoolClass schoolClass = new SchoolClass();
// 当前显示的学生的索引号
private int currentStudent=0;
// 班级串行化后保存的文件名
String fileName = "d:/student";
// 用于显示和输入的输入框, 每个属性一个输入框
// 由于它们需要在监听器内被访问,所以作为成员变量处理
JTextField sId = new JTextField(16); // ID
JTextField name = new JTextField(16); // 姓名
JTextField age = new JTextField(16); // 年龄
JTextField email = new JTextField(16); // 邮件
JTextField chinese = new JTextField(16);// 语文成绩
JTextField math = new JTextField(16); // 数学成绩
JTextField english = new JTextField(16);// 英语成绩
// 状态显示标签
JLabel lMsg = new JLabel("记录数:");
public static void main(String[] args) {
// 主方法, 调用构造方法
new StudentMgrSys();
}
public StudentMgrSys(){
// 构造方法
// 设置窗口标题和关闭时的动作
super("学生管理系统");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 创建一个JPanel,它将被加入到JFrmae中
JPanel p = new JPanel();
// 用简单的流布局
p.setLayout(new FlowLayout());
// 字段标记
JLabel lId = new JLabel("ID:");
JLabel lName = new JLabel("姓名");
JLabel lAge = new JLabel("年龄");
JLabel lEmail = new JLabel("邮件");
JLabel lChinese = new JLabel("语文");
JLabel lMath = new JLabel("数学");
JLabel lEnglish = new JLabel("英语");
// 所有的按钮,每个按钮都有一个对应的ActionCommand
// ActionCommand用于在监听器中识别不同的按钮
JButton saveStudent = new JButton("保存到文件");
saveStudent.setActionCommand("save");
JButton readStudent = new JButton("从文件读取");
readStudent.setActionCommand("read");
JButton prevStudent = new JButton("上一条记录");
prevStudent.setActionCommand("prev");
JButton nextStudent = new JButton("下一条记录");
nextStudent.setActionCommand("next");
JButton newStudent = new JButton("添加一个学生");
newStudent.setActionCommand("new");
JButton delStudent = new JButton("删除当前学生");
delStudent.setActionCommand("del");
// 为上述按钮添加监听器
// 监听器是this, 因为类本身实现了 ActionListener
// 并且也覆盖了必须的actionPerformed()方法
saveStudent.addActionListener(this);
readStudent.addActionListener(this);
prevStudent.addActionListener(this);
nextStudent.addActionListener(this);
newStudent.addActionListener(this);
delStudent.addActionListener(this);
// 输入框不可编辑, 在读入文件, 或添加学生后改为可编辑
setEditable(true);
sId.setEnabled(false); //学号是自动管理的,不能被修改
// 依次添加标签和文本输入框
p.add(lId);
p.add(sId);
p.add(lName);
p.add(name);
p.add(lAge);
p.add(age);
p.add(lEmail);
p.add(email);
p.add(lChinese);
p.add(chinese);
p.add(lMath);
p.add(math);
p.add(lEnglish);
p.add(english);
// 添加按钮
p.add(saveStudent);
p.add(readStudent);
p.add(prevStudent);
p.add(nextStudent);
p.add(newStudent);
p.add(delStudent);
// 添加状态显示标签
p.add(lMsg);
// 上述的标签、文本输入框、按钮都是在JPanel上的
// 将JPanel加入到类本身,因为类是extends JFrame的
// 所以这个类就是JFrame
this.add(p);
// 设置大小和显示
this.setSize(250, 380);
this.setVisible(true);
// 外观界面编写完成
// 注:所有按钮的动作在actionPerformed中实现
}
// 将当前学生信息取出显示到屏幕上
private void getStudent(){
// 取出学生
Student s = schoolClass.getStudent(currentStudent);
// 将信息显示到输入文框上
sId.setText(s.getId());
name.setText(s.getName());
age.setText(Integer.toString(s.getAge()));
email.setText(s.getEmail());
chinese.setText(Integer.toString(s.getScore()[0]));
math.setText(Integer.toString(s.getScore()[1]));
english.setText(Integer.toString(s.getScore()[2]));
}
// 将用户修改的信息存入schoolClass中
private boolean putStudent(){
if(schoolClass.getStudentCount()==0){
// 如果schoolClass中没有学生,应该加一条记录
schoolClass.insertStudent(new Student());
currentStudent=0;
}
// 取出当前的学生
Student s = schoolClass.getStudent(currentStudent);
try {
// 将文本输入框的内容更新到学生信息中,
// 注意:这里异常的处理
s.setName(name.getText());
s.setAge(Integer.parseInt(age.getText()));
s.setEmail(email.getText());
int[] score = new int[3];
score[0] = Integer.parseInt(chinese.getText());
score[1] = Integer.parseInt(math.getText());
score[2] = Integer.parseInt(english.getText());
s.setScore(score);
} catch (ValidatorException e) {
// ValidatorException是在前面的项目中的自定义异常
showMsg(e.getMessage());
return false;
}
// 更新,即更新当前的学生信息
schoolClass.updateStudent(s);
return true;
}
void setEditable(boolean editable){
// 设置文本框为可编辑或不可编辑
name.setEditable(editable);
age.setEditable(editable);
email.setEditable(editable);
chinese.setEditable(editable);
math.setEditable(editable);
english.setEditable(editable);
}
void showMsg(String msg){
// 显示一个对话框和提示信息
JOptionPane.showMessageDialog(this, msg);
}
@Override
public void actionPerformed(ActionEvent e) {
// 在监听器中实现按钮的功能
boolean hasMsg=false;
if ("new".equals(e.getActionCommand())) {
if(schoolClass.getStudentCount()>0){
if(!putStudent()){
// 没有通过校验,因此,不能继续
return;
}
}
}else if (!"read".equals(e.getActionCommand())) {
if(!putStudent()){
// 没有通过校验,因此,不能继续
return;
}
}
if ("save".equals(e.getActionCommand())) {
// 保存文件
SchoolClassDAO dao = new SchoolClassDAO(fileName);
dao.save(schoolClass);
}
if ("read".equals(e.getActionCommand())) {
// 读取文件
SchoolClassDAO dao = new SchoolClassDAO(fileName);
schoolClass = dao.read();
getStudent();
setEditable(true);
}
if ("new".equals(e.getActionCommand())) {
// 新建学生
Student s = new Student();
schoolClass.insertStudent(s);
currentStudent = schoolClass.getStudentCount()-1;
getStudent();
setEditable(true);
}
if ("prev".equals(e.getActionCommand())) {
// 上一条记录
if(currentStudent>0){
currentStudent--;
getStudent();
}else{
lMsg.setText("已经是第一条记录。");
hasMsg=true;
}
}
if ("next".equals(e.getActionCommand())) {
// 下一条记录
if(currentStudent<schoolClass.getStudentCount()-1){
currentStudent++;
getStudent();
}else{
lMsg.setText("已经是最后一条记录。");
hasMsg=true;
}
}
if ("del".equals(e.getActionCommand())) {
// 删除当前记录
Student s = new Student();
s.setId(sId.getText());
schoolClass.deleteStudent(s);
if(currentStudent>=schoolClass.getStudentCount()){
currentStudent--;
}
getStudent();
}
if(!hasMsg){
lMsg.setText("记录数:"+(currentStudent+1)+"/"+(schoolClass.getStudentCount()));
}
}
}
3、关键问题
正则表达式在此项目中作用,用于检测邮件是否符合规范