一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第4天,点击查看活动详情。
这个简单通讯录系统是我第一个自主完成的实践小项目,即使开发完成后,所需的功能完善了,还额外添加了一个背景音乐的功能,但缺点非常多,现在来看看都有哪些问题和优点。
1、开发顺序颠倒
我的开发顺序 1、功能需求分析,编写了需求规格说明书; 2、项目框架搭建; 3、设计页面; 4、根据页面的需求设计数据库; 5、事务处理; 正确开发顺序 1、功能需求分析,编写了需求规格说明书; 2、根据功能需求设计数据库; 3、项目框架搭建; 4、事务处理; 5、设计页面;
2、数据库设计
1、不应该根据页面去设计数据库,页面不知道需要完成什么功能,而是要根据需求规格说明书来设计数据库。因为是根据页面设计的数据库,导致没有理清数据之间的关系,在开发完成后,出现不能添加新的分组,用户登录后好友列表是共用的,出现了用户没有添加的好友,这里就是在设计数据库是忽略了用户和用户好友的关系。
2、在设计数据库是尽量减少使用外键,在使用外键时要弄清楚外键是在哪个数据库表中添加。在1中出现的不能添加新的分组,问题就在外键设计不当。数据库简单还可以稍微使用一下外键,如果数据库复杂,使用外键会使数据库愈发复杂。
3、在多对多的关系中,最好是多建立一个关系,要不然会导致数据冗余等问题。
3、事务处理-·对数据进行操作
事务处理是保证数据库中数据完整性与一致性的重要机制。
事务处理,对数据库进行操作也是要根据功能需求进行设计的。
1、建立连接
private String driver = "com.mysql.jdbc.Driver";
private String url = "jdbc:mysql://localhost:3306/数据库名称?serverTimezone=UTC&characterEncoding=utf-8&&useSSL=false";
private String user = "root";
private String sqlpassword = "密码";
Connection conn = null;
Class.forName(driver);
try {
conn = DriverManager.getConnection(url, user, sqlpassword);
} catch (SQLException ex) {
ex.printStackTrace();
} finally {
if (conn != null) {
conn.close();
}
}
2、对数据库进行操作
PreparedStatement ps = null;
ResultSet rs = null;
public List<FriendAd> AllFAdmin() throws ClassNotFoundException, SQLException {
String sql = " select * from friend"; //查询语句
//String sql = " delete from friend where fname =?"; 删除语句
//String sql = "insert into friend values(?,?,?,?,?,?,?)"; 插入语句
//String sql = "update friend set =fname=?,telphone=?,mophone=?,adress=?,gname=?,gender=? where fanme=?"; 更新数据
Class.forName(driver); //加载驱动
FriendAd friendAd = null;
List<FriendAd> friendAds = new ArrayList<>();
try {
//连接代码
conn = DriverManager.getConnection(url, user, sqlpassword);
ps = conn.prepareStatement(sql);
rs = ps.executeQuery(); //查询结果
while (rs.next()) {
String name = rs.getString("fname");
String telphone = rs.getString("telphone");
String mophone = rs.getString("mophone");
String adress = rs.getString("adress");
String gname = rs.getString("gname");
String gender = rs.getString("gender");
friendAd = new FriendAd(name, telphone, mophone, adress, gname, gender);
friendAds.add(friendAd);
}
return friendAds;
} catch (SQLException ex) {
ex.printStackTrace();
return null;
} finally {
if (rs != null) {
rs.close();
}
if (ps != null) {
ps.close();
}
if (conn != null) { //关闭连接
conn.close();
}
}
}
4、代码风格简洁规范
由于这个是我第一个项目,没有很多经验,现在复看项目代码的时候发现代码紊乱,难以看出哪块代码实现的是哪个功能。实体类和数据访问层均在同一个类中,代码冗余,没有过多的对代码进行注释,难以阅读代码。
在编写程序时,代码没有规范,思路不清晰,没有条理。在命名方法和类时没有规范命名,导致代码只有自己可读,降低了代码可读性。
5、页面设计
在设计页面时没有使用布局,使得页面不稳定,使用组件的大小,默认间隙设计页面,在页面放大和缩小时组件会浮动,在意识到这点后,我在布局页面时使用了FlowLayout。
JPanel jPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 30, 50));
在设计页面时使用了许多相同的组件,为了代码简洁,使用循环给组件赋予不同的参数
MenuItem menuItem2[];
String[] strings4 = { "增加好友", "查询好友", "删除好友" };
private void initPop() {
menuItem2 = new MenuItem[3];
for (int i = 0; i < menuItem.length; i++) {
menuItem2[i] = new MenuItem(strings4[i]);
popupMenu.add(menuItem2[i]);
menuItem2[i].addActionListener(this);
}
add(popupMenu);
}
6、页面渲染
好友列表使用的是树组件构成的。查询到好友列表的数据渲染在树组件上。
树根是好友列表,这个是不能改变的,每一个根节点是分组,分组下的叶子节点是该分组的好友。
创建树组件
DefaultMutableTreeNode node = new DefaultMutableTreeNode("好友列表"); //树状控件
DefaultMutableTreeNode root;
DefaultMutableTreeNode you;
JTree tree = new JTree(node);
在数据库中查询到的好友列表的数据渲染到树组件上
private void layoutCenter(Container contentPane) {
contentPane.add(tree);
tree.setFont(new Font(null, Font.BOLD, 15));
tree.setOpaque(false);
try {
java.util.List<FriendAd> friendAds = navicatGF.AllFAdmin(); // 查询所有人的信息
java.util.List<FriendAd> fAds = navicatGF.AllGAdmin(); // 查询所有组
for (FriendAd fAd : fAds) {
root = new DefaultMutableTreeNode(fAd.getGname()); // 组结点
node.add(root);
for (FriendAd friendAd : friendAds) { // 好友名
if (friendAd.getGname().equals(fAd.getGname())) {
you = new DefaultMutableTreeNode(friendAd.getName());
root.add(you);
}
}
}
} catch (ClassNotFoundException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
7、背景音乐
背景音乐是不能在程序中关闭的,背景音乐在程序开始时开始,程序结束时结束。
public class Music extends Thread {
Player player;
String music;
public Music(String file) {
this.music = file;
}
public void run() {
try {
play();
} catch (FileNotFoundException | JavaLayerException e) {
e.printStackTrace();
}
}
public void play() throws FileNotFoundException, JavaLayerException {
BufferedInputStream buffer = new BufferedInputStream(new FileInputStream(music));
player = new Player(buffer);
player.play();
}
public void Stop() throws FileNotFoundException, JavaLayerException {
BufferedInputStream buffer = new BufferedInputStream(new FileInputStream(music));
player = new Player(buffer);
player.play();
}
}
8、总结
emmmm....从新再捋一遍感觉收获许多,语言实在太匮乏啦,没有把我想表达的表达出来。不得不说,纵使看许多的书和视频还不及自己动手实现更好。
总的来说能独立完成第一个程序已经是一个进步,虽然这个程序错漏百出,没有严谨的思路,但是把该要实现的功能都实现了。后面就不在整理这个项目啦,虽然在文章中没有完整的表达出来,但是我在复盘项目的时候收获了许多,就已经足够了。
感谢阅读,如若有误,还请指正。