首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用.csv文件实现持久性的学生管理应用程序

使用.csv文件实现持久性的学生管理应用程序
EN

Code Review用户
提问于 2013-05-03 22:42:54
回答 2查看 880关注 0票数 1

该应用程序是一个学生管理系统,使用.csv文件作为我们学校项目的一部分。

这是我第一次创建一个基本的DAO。我想得到一些反馈,说明到目前为止可以改进什么,以及如何为UserDAO.class编写好的单元测试。

UserDAO.java

代码语言:javascript
复制
package com.studentenverwaltung.persistence;

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import org.supercsv.cellprocessor.constraint.NotNull;
import org.supercsv.cellprocessor.constraint.Unique;
import org.supercsv.cellprocessor.ift.CellProcessor;
import org.supercsv.io.CsvBeanReader;
import org.supercsv.io.CsvBeanWriter;
import org.supercsv.io.ICsvBeanReader;
import org.supercsv.io.ICsvBeanWriter;
import org.supercsv.prefs.CsvPreference;

import com.studentenverwaltung.model.User;

/**
 * 
 * @author philippkosel
 * 
 */
public class UserDAO {
    private static final String CSV_FILE = "/com/studentenverwaltung/resources/test.csv";

    private ArrayList<User> users;
    private URL url;

    /**
     * 
     */
    public UserDAO() {
        this.users = new ArrayList<User>();
        this.url = getClass().getResource(this.CSV_FILE);
    }

    /**
     * 
     * @return
     */
    private static CellProcessor[] getProcessors() {
        final CellProcessor[] processors = new CellProcessor[] { new Unique(), // id
                new NotNull() // password
        };

        return processors;
    }

    /**
     * 
     * @throws IOException
     */
    private void readCSV() throws IOException {
        ICsvBeanReader beanReader = null;

        try {
            beanReader = new CsvBeanReader(new FileReader(this.url.getPath()),
                    CsvPreference.STANDARD_PREFERENCE);

            final String[] header = beanReader.getHeader(true);
            final CellProcessor[] processors = getProcessors();

            User newUser;

            while ((newUser = beanReader.read(User.class, header, processors)) != null) {
                this.users.add(newUser);
            }
        } finally {
            if (beanReader != null) {
                beanReader.close();
            }
        }
    }

    /**
     * 
     * @throws IOException
     */
    private void writeCSV() throws IOException {
        ICsvBeanWriter beanWriter = null;

        try {
            File temp = File.createTempFile("tempfile", ".tmp");

            beanWriter = new CsvBeanWriter(new FileWriter(temp),
                    CsvPreference.STANDARD_PREFERENCE);

            final String[] header = new String[] { "id", "password" };
            final CellProcessor[] processors = getProcessors();

            beanWriter.writeHeader(header);

            for (User user : this.users) {
                beanWriter.write(user, header, processors);
            }

            File file = new File(this.url.getPath());
            file.delete();

            temp.renameTo(file);
        } finally {
            if (beanWriter != null) {
                beanWriter.close();
            }
        }

    }

    /**
     * 
     * @param user
     * @throws IOException
     */
    public void add(User user) throws IOException {
        readCSV();
        this.users.add(user);
        writeCSV();
    }

    /**
     * 
     * @param user
     * @throws IOException
     */
    public void update(User user) throws IOException {
        readCSV();

        for (User userToBeUpdated : this.users) {
            if (userToBeUpdated.getId().equals(user.getId())) {
                this.users.remove(userToBeUpdated);
                this.users.add(user);
            }
        }

        writeCSV();
    }

    /**
     * 
     * @param userId
     * @throws IOException
     */
    public void delete(String userId) throws IOException {
        readCSV();

        for (User userToBeDeleted : this.users) {
            if (userToBeDeleted.getId().equals(userId)) {
                this.users.remove(userToBeDeleted);
            }
        }

        writeCSV();
    }

    /**
     * 
     * @return
     * @throws IOException
     */
    public List<User> findAll() throws IOException {
        readCSV();

        return this.users;
    }

    /**
     * 
     * @param userId
     * @return
     * @throws IOException
     */
    public User findByPrimaryKey(String userId) throws IOException {
        readCSV();

        for (User userToBeReturned : this.users) {
            if (userToBeReturned.getId().equals(userId)) {
                return userToBeReturned;
            }
        }

        return null;
    }
}

UserDAOTest.java

代码语言:javascript
复制
package com.studentenverwaltung.persistence;

import org.junit.Test;

import com.studentenverwaltung.model.User;

public class UserDAOTest {

    @Test
    public void testAdd() {
        UserDAO ud = new UserDAO();

        User user = new User();
        user.setId("test");
        user.setPassword("test");

        ud.add(user);
    }
}
EN

回答 2

Code Review用户

回答已采纳

发布于 2013-05-04 14:45:51

看起来在writeCSV()中有一个潜在的错误。打开一个临时文件并写入它,然后在关闭它之前移动该文件。

代码语言:javascript
复制
try {
    File temp = File.createTempFile("tempfile", ".tmp");
    beanWriter = new CsvBeanWriter(new FileWriter(temp), CsvPreference.STANDARD_PREFERENCE);
    // ...
    temp.renameTo(file); // <-- moving a file that hasn't been closed yet!
} finally {
    if (beanWriter != null) {
        beanWriter.close();
    }
}

您目前正在以类路径资源的形式访问该文件:

代码语言:javascript
复制
getClass().getResource(this.CSV_FILE);

虽然这在开发中可能有效,但当将应用程序捆绑到jar和/或更大的应用程序中时,不太可能起作用。该文件很可能驻留在jar中,这可能会阻止将其作为File进行读取/写入。我建议使用不同的策略来存储和定位文件。

CSV_FILE被声明为static成员。这意味着它属于类本身,而不是类的任何特定实例。您正在以非静态的方式访问它。以静态的方式访问它更常见,例如:

代码语言:javascript
复制
this.url = getClass().getResource(CSV_FILE);
this.url = getClass().getResource(UserDAO.CSV_FILE);

由于它是私有的(因此,只在这个类中引用),我倾向于选择第一个。

users成员的使用对我来说似乎很奇怪。它不用于维护任何单一方法之外的状态。我看不出有什么令人信服的理由让它成为这个班的一员。考虑将readCSV()writeCSV()更改为分别返回和接受Collection of User,并将users本地化到需要它的方法。

代码语言:javascript
复制
private Collection<User> readCSV() throws IOException { ... }
private void writeCSV(Collection<User> users) throws IOException { ... }

其他方法可以这样做:

代码语言:javascript
复制
public void add(User user) throws IOException {
    Collection<User> users = readCSV();
    users.add(user);
    writeCSV(users);
}

这使得通过限制users的范围来读取这些方法变得更加容易。不再有任何状态可以跟踪该方法范围之外的情况。

注意,我也在使用Collection而不是ListArrayList。对我来说,List的使用意味着用户处于某种定义的顺序中。在这段代码中,我没有看到任何强制执行任何特定顺序的内容,所以我选择了使用Collection。您应该使用适当的集合类型来显示含义/意图。如果订单重要且有意义,请坚持使用List。如果订单不重要,请使用CollectionSet也是一种选择。Set表示顺序不重要,但唯一性重要。

票数 3
EN

Code Review用户

发布于 2013-05-04 16:40:11

对不起,拼写和语法问题,我在平板电脑上。

至于单元测试,您应该始终先进行测试。把它想象成一次学校考试。你的老师给你一张白纸,告诉你你还有30分钟要完成吗?单元测试是测试中的问题。你的生产代码就是答案。你的老师正在检查你的答案。

因此,通过您的测试,我想如何拯救我的用户,如何将我的用户加载到内存中,我应该如何将更多的用户添加到我的collection...etc中,一旦您编写了这些问题,然后编写您的代码就可以了。现在,如果您忘记了一个方法是如何工作的,那么现在可以回到您的单元测试,看看如何实现它。我希望这幅插图能给你一个正确的方向。

票数 0
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/25788

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档