技能目标
会使用commons-fileupload 上传文件
会使用CKEditor编辑文本
任务1:实现新闻配图
在添加新闻的同时,实现图片的上传
任务2:实现对新闻的富文本编辑
通过调用第三方控件,实现所见即所得的可视化新闻编辑
任务1 实现新闻配图
关键步骤如下
获取commons-fileupload 组件
配置commons-fileupload组件
编码实现文件上传
3.1.1 认识第三方控件
在进行项目开发时,很多功能需要编写大量的代码,业务逻辑复杂,实现相对困难。
在以前,这些功能只能由程序员编码完成,但是有了第三方控件,实现功能就相对简单
了。什么是第三方控件?如何在项目中使用第三方控件?请带着这些问题来学习下面的
内容。
1.第三方控件简介
第三方控件又被称为第三方组件,本书将统一采用第三方组件方式进行后续的描述。
第三方组件不是软件本身就具有和提供的功能,而是由一个新的组织或者各人开发出来
的功能软件。
使用第三方组件,程序员可以避免大量编码,减少开发工作量及由于逻辑或算法造
成的程序异常,从而降低开发成本,提高开发效率。第三方组件也存在缺点,由于第三
方组件是第三方组织或个人提供的,在开发时提供的版本可能会出现Bug。一旦出现
Bug,在解决时就相当麻烦。
2.commons-fileupload 组件与API
虽然使用第三方组件可能会出现Bug,但其优势还是非常明显的,而且有很多非常
使用的组件已被广泛应用到各种项目中。其中,commons-fileupload组件是由Apache开
发的一个应用于文件上传的组件,其特点就是使用方便,简单。该组件涉及的API介绍
如下。
(1)FileItem接口
FileItem 是一个接口,在该接口中定义了用于处理表单内容以及文件内容的方法。
在应用过程中,每一个表单中的单个字段元素,都会被封装成一个FileItem类型的对象,
通过调用FileItem 对象的相关方法可以得到相关表单字段元素的数据。在应用程序中,
可以直接用FileItem 接口进行访问。
FileItem 接口的常用方法如表3-1 所示。
方法 | 返回类型 | 说明 |
---|---|---|
getFileName() | String | 返回表单字段元素的name属性值 |
isFormField() | boolean | 判断FileItem封装的数据是属于普通表单字段还是文件表单字段,普通表单字段返回true,文件表单字段返回false |
getName() | String | 返回上传文件字段中的文件名,文件名通常是不含路径信息的,取决于浏览器实现 |
write(File file) | void | 将FileItem对象中的内容保存到指定文件中 |
getString(String encoding) | String | 按照指定的编码格式将内容转换成字符串返回 |
提示
FileItem 接口的其他方法请参考 API文档进行学习。
(2) FileItemFactory 接口与 DiskFileItemFactory 类
FileItemFactory 是一个接口,是用于构建FileItem 实列的工厂。
DiskFileItemFactory 类是 FileItemFactory 接口的实现类,在使用过程中,可以使用
DiskFileItemFactory 类构造一个FileItemFactory 接口类型的实列,语法格式如下。
FileItemFactory factory = new DiskFileItemFactory();
(3) ServletFileUpload 类
ServletFileUpload 类是 Apache 文件上传组件中用于处理文件上传的一个核心类。
它的作用是以 List 形式返回每一个别封装成 FileItem 类型的表单元素集合。
ServletFileUpload 类的构造语法如下。
public ServletFileUpload(FileItemFactory fileitemfactory)
ServletFileUpload 类的常用方法如表 3-2 所示。
方法 | 返回类型 | 说明 |
---|---|---|
isMutipartContent(HttpServletRequest request) | boolean | 静态方法,用于判断请求数据中的内容是否是multipart/form-data 类型,是返回 true,否返回 false |
parseRequest(HttpServletRequest request) | List | 将请求数据中的每一个字段单独封装成 FileItem 对象,并以集合方式返回 |
提示
ServletFileUpload 类的其他方法请参考 API 文档进行学习。
3.1.2使用 commons-fileupload 组件上传文件
1.准备工作
使用 commons-fileupload 组件实现文件上传前的准备工作包括以下几个环节。
(1)获取组件:使用 commons-fileUpload 组件需要获取两个必要的 jar 包,分别
是 commons-fileupload-1.2.2.jar 和 commons-io-2.4.jar 。下载地址 分别是
http://commons.apache.org/fileupload/download_fileupload.cgi 和
http://commons.apache.org/io/download_io.cgi 。下载完毕后,可以通过相关的 API
文档查看类,接口及方法说明。页面效果如图3.1 所示。
??不知道怎么找这个文档
图3.1 commons-fileupload 组件相关API 文档
(2) 将解压后得到的两个 jar 文件复制到项目中的 WEB-INF/lib 目录下,并导入到
项目中。
(3) 修改新闻添加页面。
修改表单:在<form>标签中修改并添加如下代码。
method = "post" enctype = "multipart/form-data"
其中, enctype = "multipart/form-data" 明确表单提交时采用二进制进行数据传输,简
单地说就是表单提交时以多部分内容进行提交,可能是普通表单,也可能是包含文件的
表单。
设置上传文件的标签。
<input type = "file" name = "picPath" value="">
(4) 在表单提交的处理页面将实现文件上传所需的包导入。
<%@page import = "java.io.*,java.util.*%">
<%@page import = "org.apache.commons.fileupload.disk.DiskFileItemFactory"%>
<%@page import = "org.apache.commons.fileupload.servlet.Servlet.SeervletFileUpload"%>
<%@page import = "org.apache.commons.fileupload.*"%>
2.编码实现图片上传
通过对 commons-fileupload 组件 API 的了解,我们已经知道了文件上传需要使用到
的类及常用方法,同时也完成了文件上传前的准备工作,下面将开始文件上传的编码工作。
(1)判断表单提交内容的形式
由于表单提交时可能是普通表单提交,也可能在提交的表单中含有需要上传的文件,
因此在获取表单时要对表单内容的形式进行判断。
注意
如果表单中未设置 enctype = "multipart/form-data", 则无法实现文件上传,这
一点在编码时要注意。
(2) 创建文件上传所需的 API 实列
在讲解上传组件 API 时, 分别介绍了3种常用的类及方法。 ServletFileUpload 类用
来解析 request 请求,而 FileItemFactory 工厂类会对表单中的字段进行处理。因此,需
要首先创建它们的实列。
(3) 解析 request 请求,获取 FileItem 对象集合。
在 ServletFileUpload 实列创建好后,就可以使用其来解析 request 请求数据,获取
已经被封装成 FileItem 对象的表单元素集合。
上述3个步骤归纳起来如示例1所示。
示例1
编写代码实现对表单提交内容的判断,创建文件上传所需的 API 实列,并完成
request 请求解析。
关键代码:
……
//读取 request 请求,判断是否是多部分内容表单提交
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if(isMultipart == true){
// 创建 FileItemFactory 实列
FileItemFactory factory = new DiskFileItemFactory();
//创建 ServletFileUpload 实列
ServletFileUpload upload = new 色如vletFileUpload(factory);
try{
//解析 request 请求中的数据
List<FileItem> items = upload.parseRequest(request);
}
}
……
(4)循环遍历集合中的数据。
由于解析 request 返回的是数据字段的列表集合,因此还需要使用迭代方式进行集
合的遍历。对于集合中的数据,一种类型是普通的表单元素,如文本框,下拉列表等。
另一种可能是文件元素,所以还需要进行比较和判断。
示例2
使用迭代器,对集合中的数据进行解析。
分析如下
对于集合的解析,看似简单,但其中涉及一定的业务逻辑。具体体现在如下几个方面。
- 通过循环对集合进行遍历。
- 读取数据并转换成 FileItem 类型。
- 判断数据元素是属于普通表单元素,还是文件元素。
如果是普通表单元素,则通过数据元素名称对应需要保存的字段,然后进行
数据的保存。
如果是文件元素,则需要获取上传文件的名称,并指定保存路径,调用
write()方法,实现文件上传。
关键代码:
……
//创建迭代器,进行集合遍历
Iterator<FileItem> itr = items.iterator();
while(iter.hasNext()){
//读取数据元素
FileItem item = (FileItem) iter.next();
//判断元素类型, true- 普通表单元素, false- 文件元素
if(item.isFormField()){
//获取普通表单元素名称
fileName = item.getFieldName();
//判断元素名称与表单元素的对应关系
if(fieldName.equals("title")){
news.setTitle(item.getString("UTF-8"));
}else if(fileName.equals("id")){
String id = item.getString();
if(id!=null&&!id.equals("")){
news.setId(Integer.parseInt(id));
}
}
……
}else{
//读取文件元素的名称
String fileName = item.getName();
if(fileName !=null&&!fileName.equals("")){
//获取上传文件的名称,并通过名称创建一个新File 实例
File fullFile = new File(item.getname());
//从路径中提取文件名称,并构建一个新的File 实例
File saveFile = new File(uploadFilepath,fullFile.getName());
//写入文件,实现上传
item.write(saveFile);
uploadFileName = fullFile.getName();
news.setPicPath(uploadFileName);
}
}
}
……
图3.2所示是添加新闻图片后的展示效果。