Jfinal源码分析-------上传源码分析

在WEB开发中,上传文件的操做时必不可少的一项功能。那么,在Jfinal中,关于文件上传的操做,他到底都作了些什么呢?又有什么须要注意的了?今天咱们就来看看关于文件上传的那些个故事。java

关于上传文件,他和普通的表单提交不同,有啥不同,为什么不同,怎么就不同了?我想这个应该不用我多少吧,作WEB应用的同窗们都应该知道,在有附件提交的那种表单里面,必定要加一个属性“enctype="multipart/form-data"”加了这个之后,咱们就能够经过POST请求的方式将全部相关信息提交到咱们的后台去了!!可是,在使用JFinal的时候,咱们必定要注意一点,就是在咱们后台接收这个POST数据的时候,咱们必定要注意一点的就是,假如咱们的POST请求中有上传附件的表单元素,也就是<input type=”file” name=”filename”>的时候,咱们必定要将框架

<!-- lang: java -->
UploadFile uf = getFile("filename","code/");

这个东西放在方法的第一行,由于这样的话,才可以接收表单元素中的非上传附件的元素的值,至于他为何要这么去作,咱们再后面会详细的介绍,先告诉你们怎么去使用,而后在去理解原理,我认为这个是在软件开发领域中广泛的学习方法吧,由于我写的这些基本上应该是属于内功,和江湖上所说的那些个“《九阴真经》”之类的书籍属于一个性质,嘿嘿,开始有点飘了!!学习

废话不说,进入正题: 一、若是要使用Jfinal的文件上传的话,他必定是有依赖包的,记住,必定是有依赖包,不然,你的上传操做是会出现未知的错误的,那么这个依赖包是啥?从哪儿下。 答案:依赖包是“cos.jar”至少个人是这个,若是版本有更新的话,你均可以从Jfinal的那个官网上面去下载下来,这样的,你就能够下载到最新的那个jar包了,不过应该不会常常变吧,不然就用户会受不了的编码

好了第一个问题解决,在咱们假如jar包之后,咱们就能够来进行文件上传了。code

按照我刚刚说的那个,在你要处理的方法的第一行 写上上述的那一句接收的方法,那么你的文件上传基本算做完了,是的,就是这样,此时的文件已经到了你的默认上传文件的目录项目下面了,只是此时,他的名称和你本地的名称同样,不过这只是第一步,也就是所,他的文件是不会放到一个临时的文件夹或者之类的地方,而是直接给弄过去到一个他默认的位置的。文件夹的名称叫作“upload”,如今咱们就看看这个过程orm

因为咱们再Controller中使用getFile()这个方法来接收相关的文件,因此咱们就从这个地方下手,看看Jfinal框架的自己对这个过程都作了什么样的操做。对象

打开Controller这个类,找到getFile这个方法,咱们看看都有些啥:事件

<!-- lang: java -->
public UploadFile getFile(String parameterName, String saveDirectory) {
	getFiles(saveDirectory);
	return getFile(parameterName);
}
public UploadFile getFile(String parameterName, String saveDirectory, Integer maxPostSize, String encoding) {
	getFiles(saveDirectory, maxPostSize, encoding);
	return getFile(parameterName);
}

public UploadFile getFile(String parameterName) {
	List<UploadFile> uploadFiles = getFiles();
	for (UploadFile uploadFile : uploadFiles) {
		if (uploadFile.getParameterName().equals(parameterName)) {
			return uploadFile;
		}
	}
	return null;
}

以上是列举了一些getFile的方法,咱们看看他们有什么不一样,ip

第一个GetFile 他接收的参数是parameter和SaveDirectory Parameter是表单里面的file对应的name属性值,你们应该都明白吧,就是去接收谁的参数 第二个参数就是savedirectory,这个主要是表示当前接收的文件存放在什么位置;举个例子;假如咱们的文件上传的根路径是upload(Jfinal默认的),那么咱们假如使用这个方法的话,填写了saveDirectory,假如是“a”,那么文件就会被放在“upload/a/”这个路径下面,请注意的是,假如咱们的savedirectory的文件夹不存在的话。Jfinal会自动建立出这个文件夹。开发

而后再往下看,第二行调用了getfiles()参数神马的我就不说了,一看就可以明白是什么意思。无非就是写编码,最大容许上传之类的参数一看就应该明白

而后调用getFile(Param)去处理文件,其实若是你细心的话你能够看到,他的处理过程是把一个上传文件看作是多个上传文件的一个特例,经过循环迭代出来处理各个上传文件的。至此 咱们第一个问题算是解决了,就是在getFile的过程当中,他的底层是怎么去处理的,若是你看到这里,若是仍是只知其一;不知其二的话,我强烈的建议你去看看这个JFinal框架的源代码。写得仍是比较的容易懂的。

好了,咱们来解决下一个问题,那就是,为何在有上传文件的过程中,他必定要将getFile这个方法写在最前面,不然无论怎么样都会不能能接受的非上传文件的参数,我相信,初次用JFinal框架作WEB项目的时候确定,必定以及绝对的遇到过这个问题。不过这个问题的说明在文档中有提到过的,不过我第一次使用这个框架的时候,确实没有好好看过这方面的东西,因此遇到这个问题的时候,我足足搞了一天,在网上各类搜索,没有任何结果,心中有一万匹草泥马在心中奔腾,检查各类配置都没有问题,尼玛拿到是个灵异事件。后来看文档,才焕然大悟。原来必定要这么干才可以拿到想要的东西,框架么,确定有本身的一套规矩。因此走走弯路,有时候收获的东西会更加多。 因此,之后再遇到这种尼玛各项配置都OK的,又有文件上传的状况,你先看看getFIle这个东西是否是在你要处理方法的第一行,若是没有的话,问题可能就出在这里,你要问为何,也许一下子会有答案,不过你能够先记住一点就是,框架要求这样作的,也许这可以给你一点点内心安慰,但假如你是把这个做为完美解决方案的话,那么接下来至关有养分的东西,你可能就要错过了。

首先说说,为何JFinal在没有配置上传文件根目录的状况下,他会在项目中建立一个叫upload的文件夹

<!-- lang: java -->
private void initOreillyCos() {
	Constants ct = constants;
	if (OreillyCos.isMultipartSupported()) {
		String uploadedFileSaveDirectory = ct.getUploadedFileSaveDirectory();
		if (uploadedFileSaveDirectory == null || "".equals(uploadedFileSaveDirectory.trim())) {
			uploadedFileSaveDirectory = PathKit.getWebRootPath() + File.separator + "upload" + File.separator;
			ct.setUploadedFileSaveDirectory(uploadedFileSaveDirectory);
			
			/*File file = new File(uploadedFileSaveDirectory);
			if (!file.exists())
				file.mkdirs();*/
		}
		OreillyCos.init(uploadedFileSaveDirectory, ct.getMaxPostSize(), ct.getEncoding());
	}
}

在Jfinal类中,你找到一个叫initOreillyCos()的方法,别说你不会找方法的快捷键啊“ctrl+o”,不解释,只要你使用的是默认的配置。这个确定管用的。 其中有一句话就是说明咱们刚刚的这个问题的:

<!-- lang: java -->
uploadedFileSaveDirectory = PathKit.getWebRootPath() + File.separator + "upload" + File.separator;

喏,啥也不说了,在Jfinal初始化的时候,请注意他的判断条件,他就会创建一个默认的文件夹,格式就是“项目根路径”+upload+”/”。记住这个过程是在你没有配置上传文件根路径的时候,系统默认的,不过这个路径会有个问题,有啥问题,咱们一下子讨论,不过若是你要使用上传的话 我我的是不建议使用系统默认的这个,由于很悲剧。没错,确实是很悲剧的。 好了,咱们讨论了默认上传路径之后,咱们须要继续前进,而后解决其余相关的问题。

第二个问题,在上传文件的时候,为何要把GetFile放在处理方法的第一行。 在咱们刚刚提到的处理上传文件的过程当中,假如了enctype="multipart/form-data, 之后 此时的request对象就不是咱们使用普通表单提交的request对象了,咱们假设加了刚刚的那个属性的方式的request对象叫作MutipartRequest对象,那么咱们以getMOdel()这样的方法的举例

<!-- lang: java -->
public <T> T getModel(Class<T> modelClass) {
	return (T)ModelInjector.inject(modelClass, request, false);
}

在调用这个方法的时候,咱们看到 他执行了inject这个方法,正好这个方法里面有request对象,按照咱们普通表单提交之后产生的这个request对象,咱们是可以经过反射创建这个model实例,而后遍历其中的属性为咱们的model实例进行相应的赋值操做,不过咱们假设咱们提交了这个带有附件上传的表单,那么咱们产生的request对象就不是咱们日常见到那个request对象,而是经过以下代码产生的request对象:

<!-- lang: java -->
public List<UploadFile> getFiles(String saveDirectory, Integer maxPostSize, String encoding) {
	if (multipartRequest == null) {
		multipartRequest = new MultipartRequest(request, saveDirectory, maxPostSize, encoding);
		request = multipartRequest;
	}
	return multipartRequest.getFiles();
}

经过如上的代码,咱们能够看到,request对象已经变成mutipartRequest对象了,这个对象里面,我猜,他包含了原来普通request对象内容和咱们上传附件里面的一些个内容,这样的话,再将这个mutipartRequest对象传入getModel里面,这样经过遍历这里面的相应内容,从而就可以获得咱们想要的文件相应的数据和咱们非上传文件中的内容了,这也就可以解释,为何咱们再不使用getfile这个方法在最开始的时候,获得model中的全部属性值都为null,由于咱们model实例是被反射建立的,而这赋值的过程但中,他并无拿到相应的值,全部所有为NULL; 简单总结一下: 就是在咱们进行非附件表单提交的时候,获得的request对象时咱们JavaServlet的中的request对象,而在咱们进行带附件上传的时候获得的对象实际上是包含了这个标准的Request对象内容的MutipartRequest对象,至少

<!-- lang: java -->
multipartRequest = new MultipartRequest(request, saveDirectory, maxPostSize, encoding);

request = multipartRequest;

这个证实了我刚刚说的观点,此时的request对象非彼时的request对象。 欢迎拍砖指正啊!!

相关文章
相关标签/搜索