java - 如何使用 .json 文件刷新基本“数据库”
问题描述
我正在研究一个用 Java 编写的大学项目。该项目包括一个用于体育用品连锁店的小软件。我的老师告诉我使用 JSON simple.jar 将员工信息、运动对象和许多其他东西(商店订单……)保存到 JSON 文件中。我的软件一开始从 .json 文件加载列表,这里是一个例子:
private static ArrayList<Person> personale = new ArrayList<Person>();
public ArrayList<Person> readPersonale() throws IOException, org.json.simple.parser.ParseException {
JSONParser parser = new JSONParser();
FileReader fileReader = new FileReader("f:\\personale.json");
JSONObject jsonObject = (JSONObject) parser.parse(fileReader);
ArrayList<Person> personale = new ArrayList<>();
JSONArray array = (JSONArray) jsonObject.get("personale");
for(int i=0; i<array.size(); i++) {
Person p = new Person();
JSONObject json = (JSONObject)array.get(i);
p.setName(json.get("NAME"));
p.setSurname(json.get("SURNAME"));
p.setUserCode(json.get("USER CODE"));
p.setPassword(json.get("PASSWORD"));
p.setRule(json.get("RULE"));
personale.add(p);
}
fileReader.close();
return personale;
}
在软件关闭之前,我的程序必须删除以前的 .json 文件的内容并将所有列表重写到同一个 .json 文件中:
public void writePersonale(ArrayList<Person> list) throws org.json.simple.parser.ParseException, ParseException {
JSONObject obj = new JSONObject();
JSONArray Jlist = new JSONArray();
for(Person e : list) {
JSONObject json = new JSONObject();
json.put("NAME", e.getName());
json.put("SURNAME", e.getSurname());
json.put("USER CODE", e.getUserCode());
json.put("PASSWORD", e.getPassword());
json.put("RULE", e.getRule());
Jlist.add(json);
}
obj.put("personale", Jlist);
try (FileWriter file = new FileWriter("f:\\personale.json")) {
file.write(obj.toJSONString());
file.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
这是使用 .json 文件进行编程的正确方法吗?有更好的方法来使用 JSON 文件吗?谢谢
解决方案
好的,首先我会避免使用您用于 JSON 处理的库。手动创建 JSONArrays 等更让人头疼,而不是富有成效。从这个意义上说,我会去Jackson
执行任何序列化/反序列化(写入和从数据库写入)。
由于Jackson
可以主动映射数据类型并转换它们,您将使用以下 POJO 来完成您的工作:
用户Dto
public class UserDto {
private String name;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
private String surName;
public String getSurName() { return surName; }
public void setSurName(String surName) { this.surName = surName; }
private Integer userCode;
public Integer getUserCode() { return userCode; }
public void setUserCode(Integer userCode) { this.userCode = userCode; }
private String rule;
public String getRule() { return rule; }
public void setRule(String rule) { this.rule = rule; }
public UserDto() {}
public UserDto(String name, String surName, Integer userCode, String rule) {
this.name = name;
this.surName = surName;
this.userCode = userCode;
this.rule = rule;
}
@Override
public String toString() {
return "UserDto{" +
"name='" + name + '\'' +
", surName='" + surName + '\'' +
", userCode=" + userCode +
", rule='" + rule + '\'' +
'}';
}
}
BulkUserDto
public class BulkUserDto {
private List<UserDto> userDtos;
public List<UserDto> getUserDtos() { return userDtos; }
public void setUserDtos(List<UserDto> userDtos) { this.userDtos = userDtos; }
}
有了这两个,您的数据库实用程序类可以简化为:
public final class DatabaseUtil {
private static final String FILE_PATH = "/tmp/db.json";
private static ObjectMapper objectMapper = new ObjectMapper();
private DatabaseUtil() {}
public static List<UserDto> initUserList() throws IOException {
BulkUserDto dto = objectMapper.readValue(Paths.get(FILE_PATH).toFile(), BulkUserDto.class);
return dto.getUserDtos();
}
public static void saveUserList(BulkUserDto dto) throws IOException {
String parsedObject = objectMapper.writeValueAsString(dto);
if (Files.exists(Paths.get(FILE_PATH))) {
System.out.println("Found old db file under:: " + FILE_PATH + " deleting");
Files.delete(Paths.get(FILE_PATH));
}
FileWriter writer = new FileWriter(Paths.get(FILE_PATH).toFile());
writer.write(parsedObject);
writer.flush();
}
}
请注意,序列化/反序列化过程是多么精简。有关杰克逊的更多信息,您可以参考以下基本教程https://www.mkyong.com/java/how-to-convert-java-object-to-from-json-jackson/
另请注意,如果文件系统中已经存在旧的 db.json 文件,则保存方法会主动检查并删除它。
您可能会做的另一个不错的优化如下。由于您将所有读取的用户条目存储在静态列表中,因此您实际上是在创建缓存。我假设你readPersonale
只通过程序调用一次,因为你似乎没有相关的检查,这会破坏它。基于以上,我建议如下:
我将保留静态列表声明,但不会为其分配一个空列表,而是继续将其保留为空。然后,我将创建以下方法以确保缓存仅初始化一次:
private static final Object LOCK = new Object();
private static List<UserDto> userCache;
public static List<UserDto> getUserCache() {
synchronized (LOCK) {
if (userCache == null) {
try {
userCache = initUserList();
} catch (IOException e) {
return Collections.emptyList();
}
}
return userCache;
}
}
请注意这里的同步块,它将确保初始化只会发生一次并且仅由第一个调用线程发生。
有了这个,我会简单地使用这个缓存来添加/删除用户,然后最后我会继续保存它。请注意,如果您确实选择遵循这一点,则应考虑同步(假设您的程序中有多个线程)。
推荐阅读
- r - 删除小于一定数量的数据,利用剩余信息新建一行,做条形图,加起来为100%
- firebase - 如何仅从 Firebase 查询中获取部分数据集
- r - 使用 translateR 将国家名称从西班牙语翻译成英语
- github - 从您的分叉 GitHub 存储库安装 BigBluebutton,您的设置不是原始存储库
- javascript - 如何将文本字段值保留到文本字段中
- ms-access - 如何在子表单中引用具有全局变量的表单并对其进行处理?
- python - django-webpack-loader 不使用 react-app-rewired 渲染反应应用程序
- flutter - 脚手架的背景图像
- java - java转换:MultivalueMap
到地图 - r - 使用 MatchIt 进行 1 对 1 粗化精确匹配