PostRepositoryByList
和PostRepositoryByMap
都已经实现了博客管理的部分功能,现在还差几个重要部分:
那应该如何来存储呢? 这里我们给出一种方案:
{id}---{title}
进行命名,比如id
为1、标题为"天码营"的文章,用以保存内容的文件就命名为1---天码营
content
属性我们以PostRepositoryByList
为例来讲如何实现完整的功能。
基于以上的方案,首先我们可以使用static
和final
修饰符来定义两个常量:
public class PostRepositoryByList implements PostRepository {
private static final String FOLDER = "TMY-BLOG"; // 保存文件的文件夹名称
private static final String SEPARATOR = "---"; // id和title的分隔符
...
}
Java开发中最经常做的一件事情就是管理项目的依赖,所谓的依赖其实就是第三方的库,以JAR包的形式存在。JAR包就是把编译好的类用Zip格式压缩存储在一个文件中。引入JAR包,我们就能够使用JAR包公共的类及其方法和属性。
Java开发中大多数常用的功能其实都有非常优秀的第三方库实现了,给我们提供了很多“轮子”,我们造汽车的时候直接拿来就可以了。
我们现在需要进行文件操作,这里我们准备使用Apache Commons IO提供的一个文件操作库来实现博客信息的加载和存储。
当然我们也可以使用JDK自带的IO功能来实现,不过你需要学习Java IO相关的类和接口,还记得我说的三个神器吗?大家可以自行学习。这些类和接口通常也称之为API,应用编程接口,它们给我们提供的一些封装了底层功能的基础设施,极大地简化了我们的开发。事实上了解API可能是成为一个编程高手花时间最多的一个地方。当然你也不可能把所有API完全记下来。在软件开发中也有二八原则,少数的API能够胜任开发中的大部分场景。所以你只需要掌握这些关键部分,当在新场景下遇到不能解决的新问题时,再去查看帮助文档。所以帮助文档的阅读也是技术学习的一个关键因素。了解了基础原理之后一般就能上手开发了,帮助文档可以帮助你在实践中学习。
回到我们的项目,要使用第三方的库,需要将其加入到类路径当中。
import
就能使用其中的类了。将来我们引入其他JAR包也可以按照相同的方式来进行操作。
PostRepositoryByList
的方法操作的都是static
类型的List
,即所有实例共享数据,因此一个PostRepositoryByList
实例(即对象)就能满足使用了。为了让系统更加高效,应该让用户无法创建多个PostRepositoryByList
实例。
让一个类只能创建一个实例的做法,是一种典型的设计模式,成为Singleton模式。设计模式你可能还是第一次听说,你现在只要知道设计模式是一种常用的定义类的方式就好了,这些方式能更好地适应某些特定的应用场景。
为了实现Singleton模式,我们对PostRepositoryByList
做两点修改:
private
的,这样外部就不能创建PostRepositoryByList
实例了;PostRepositoryByList
可以提供一个获取实例的静态方法,每次返回的都是它自己创建的唯一一个实例。public class PostRepositoryByList implements PostRepository {
...
private static final PostRepository postRepository = new PostRepositoryByList();
public static PostRepository instance() {
return postRepository;
}
private PostRepositoryByList() {
}
...
}
做了这两点修改后,系统中就只可能出现唯一一个PostRepositoryByList
实例了。你已经学会了第一个设计模式了!
接下来我们来设计创建博客的流程:
Post
对象,添加到PostRepository
中。为了实现这个流程,代码中有几个关键点:
while
循环来不断获取输入,当发现结束信息时跳出循环。Scanner
的nextLine()
方法。StringBuffer
。title
和content
的信息后,调用Post
构造函数即可创建对象。以下为处理create命令的代码:
private static void processCreateCommand() {
System.out.println("please input blog title");
String title = scanner.nextLine();
System.out.println("please input blog content ended with '***'");
StringBuffer content = new StringBuffer();
while (true) {
String word = scanner.nextLine();
if (word.equals(END_OF_POST)) {
break;
}
content.append(word);
content.append("\n");
}
Post post = new Post(title, content.toString());
post.print();
postRepository.add(post);
}
从博客加载信息的流程为:
id
和title
,读取文件内容作为content
;Post
对象,并且添加到PostRepository
中。代码实现中,有以下几个关键点:
FiltUtils
类的listFiles
方法。你可能会问如何知道需要调用这个方法,首先是可以去读它的文档,或者你在Google中输入"Commons IO"、"read all files in a directory"等关键字,你肯定能找到解决方案。id
和title
两部分,可以调用String
类的split
方法。你可以思考一个问题,如果标题中也包含"---"这几个字符会出现什么情况,你应该如何解决?long
类型的id
,可以通过Long.parseLong()
方法。FitleUtils
的readFileToString()
方法可能抛出的IOException
,Eclipse会给你自动提示。第二种是Long.parseLong()
方法如果遇到一个不是表达整数的字符串,可能抛出NumberFormatException
。我们要确保异常情况下程序不会意外退出。如何catch
多个异常现在你应该知道怎么做了吧?@Override
public void loadData() throws BlogAppException {
File dir = new File(FOLDER);
List<File> files = (List<File>) FileUtils.listFiles(dir, null, true);
for (File f : files) {
try {
String fileName[] = f.getName().split("---");
String content = FileUtils.readFileToString(f, "utf-8");
Post post = new Post(fileName[1], content);
post.setId(Long.parseLong(fileName[0]));
postRepository.add(post);
} catch (IOException e) {
e.printStackTrace();
BlogAppException be = new BlogAppException("load");
be.initCause(e);
throw be;
} catch (NumberFormatException e) {
e.printStackTrace();
BlogAppException be = new BlogAppException("load");
be.initCause(e);
throw be;
}
}
}
这里我们将catch
到的异常,重新以BlogAppException
的方式抛出来,交给main
方法来处理。这样情况下,为了保存导致某个异常的原因(即另一个异常),可以调用initCause()
方法。这样就不会丢失异常信息,能够方便我们进行调试和异常处理。
将博客信息保存的文件的流程与加载流程刚好相反,这里我们需要基于博客信息生成文件的标题和内容,代码如下:
@Override
public void saveData() throws BlogAppException {
for (Post post : PostRepositoryByList.instance().getAll()) {
String fileName = Long.toString(post.getId()) + SEPARATOR
+ post.getTitle();
try {
FileUtils.write(new File(FOLDER + File.separator + fileName), post.getContent());
} catch (IOException e) {
e.printStackTrace();
BlogAppException be = new BlogAppException("save");
be.initCause(e);
throw be;
}
}
}
至此,我们的博客管理应用已经完成了。虽然是一个很简陋的应用,但是我们需要用到Java开发中的大部分核心知识,如果你已经可以轻松地写出这个应用,那么你现在可以进阶了!
你尝试继续学习Java贪吃蛇游戏的设计与实现,进一步巩固J2SE的编程技能。
登录发表评论 登录 注册
花了999购买的
Java Web全栈开发实战课程
为什么只能学习一门
Java入门基础教程
????
综合实例有参考代码嘛?
看到最后很没意思。那个构架引入后,又不表明怎么用,直接一堆片段,好吧,大概也知道,最后发现这些片段对应那个类,那个接口都没有描述,只是简单陈述后,就直接晒出片段,好像我们读了前面那些基础,就成了高手似的,设计模式,说是会了也不应该连片段方法作用何处都不提示下把?教程开始沉迷到了自己的境界还是需要收费模式了?别浪费大家时间,友好的开始请友好的结束,大家都好。要收费请直说,别玩手段。
你的教程再有套路,新的学员,学了后不愿意分享,则一点互联网价值都不会有。顶多就是一个坑。
在类的成员变量里,定义了这样一个静态常量
for (Post post : PostRepositoryByList.instance().getAll()) { String fileName = Long.toString(post.getId()) + SEPARATOR + post.getTitle(); try { FileUtils.write(new File(FOLDER + File.separator + fileName), post.getContent()); }
这里的SEPARATOR不需要定义和赋值的吗?直接识别成“---”?
那应该如来来存储呢?
这句厉害了我的哥。如来,
我把链接加上了,你可以点击进去看一下
请问三个神器是啥?
这里直接使用了一个第三方库,屏蔽了文件操作的底层细节。
@Toder 我仔细看了2遍,但是从文件加载博客信息、将博客信息保存文件部分涉及到文件操作的不太清楚,就是卡在那里
。希望作者可以讲清楚点谢谢
@prayer123321 哪个知识点需要进一步讲清楚可以提出来,我们可以增加:)
好乱啊 这个博客应用知识点还有很多细节没讲到,感觉仅仅通过上面的知识做出来还有点困难啊
请问是哪三个神器?
请问大家本课程的实战任务中的答案可以在哪里看到?谢谢!
StringBuffer用于大量字符串的拼接操作效率要更好。
下面几行代码就是判断结束:
END_OF_POST
的值这里设置为***
(你可以设置为其他),即最后一行输入***
就表示内容输入结束。这是综合实例的例子,将content放进去会出现java heap space ,如果拿出来或出现死循环。并且没有办法判断结束的关键字,为什么还要加StringBuffer
为什么跳转到这个链接后没有显示参考代码,请问完整的代码在哪里可以下载
越看越不懂了
写不出来
教程对该应用的程序结构描述太分散了