Jfinal源码分析

Stella981
• 阅读 448

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

关于上传文件,他和普通的表单提交不一样,有啥不一样,为何不一样,怎么就不一样了?我想这个应该不用我多少吧,做WEB应用的同学们都应该知道,在有附件提交的那种表单里面,一定要加一个属性“enctype="multipart/form-data"”加了这个以后,我们就可以通过POST请求的方式将所有相关信息提交到我们的后台去了!!但是,在使用JFinal的时候,我们一定要注意一点,就是在我们后台接收这个POST数据的时候,我们一定要注意一点的就是,假如我们的POST请求中有上传附件的表单元素,也就是的时候,我们一定要将

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

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

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

好了第一个问题解决,在我们假如jar包以后,我们就可以来进行文件上传了。

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

由于我们再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的方法,我们看看他们有什么不同,

第一个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对象。 欢迎拍砖指正啊!!

点赞
收藏
评论区
推荐文章
芝士年糕 芝士年糕
2年前
Nginx 调整文件上传大小限制
使用3A服务器做了网页,感觉挺不错的,使用LNMP环境用Nginx部署了前端,发现上传附件大一点就会报错,查看配置文件,发现spring的附件配置已经配置了。那么就看下Nginx的body设置。nginx文件上传默认是1MB。在server
皕杰报表(关于如何上传和下载文件到数据库)
在皕杰报表中文件是否可以上传到数据库中,当然是可以的。然后在附件上传和下载中,设置相对路径或绝对路径,文件名称,文件类型和上传的空值条件(上传的大小,默认限制是5120kb和满足什么条件时上传)。在下载中选择相对路径或绝对路径,填写下载链接名称和下载文件名称。填报操作时有三个函数:filedata、filename、filepath。filedata:获取文
happlyfox happlyfox
3年前
.net web core 如何编码实现文件上传功能
关于我前言在进行Web前后端分析开始时,我们经常会碰到文件上传的需求。上传用户头像,上传认证材料、审核材料等,这些都可以归类为文件上传功能。今天主要把自己在开发过程中的心得进行一个整理,供大家学习。开启静态文件中间件默认情况下,静态文件(如HTML、CSS、图像和JavaScript)是ASP.NETCore应用直接提供给客户端的资产。开启静态
Easter79 Easter79
3年前
SpringBoot2.0 基础案例(14):基于Yml配置方式,实现文件上传逻辑
本文源码GitHub地址:知了一笑https://github.com/cicadasmile/springbootbase一、文件上传文件上传是项目开发中一个很常用的功能,常见的如头像上传,各类文档数据上传等。SpringBoot使用MultiPartFile接收来自表单的file文件,然后执
Stella981 Stella981
3年前
Play 2.0 用户指南 - 文件上传 -- 针对Scala开发者
   处理文件上传   在form中指定multipart/formdata属性上传文件   上传文件的标准方式是指定form的一个特殊属性multipart/formdata,可以让你混合表单数据和表单文件附件。   开始编写HTML表单:@form(actionrou
Stella981 Stella981
3年前
SpringBoot2.0 基础案例(14):基于Yml配置方式,实现文件上传逻辑
本文源码GitHub地址:知了一笑https://github.com/cicadasmile/springbootbase一、文件上传文件上传是项目开发中一个很常用的功能,常见的如头像上传,各类文档数据上传等。SpringBoot使用MultiPartFile接收来自表单的file文件,然后执
Wesley13 Wesley13
3年前
PHP 文件上传的原理及案例分析
原理将客户端文件上传至服务器端,在服务器端临时存储,再将服务器端临时存储的文件移至指定位置实现文件上传需要的知识点:前端页面1.form表单必须是用post发送方式,因为get会将参数带到url中,而上传的文件转换后字符会很长,而且也是为了安全性2.form表单需要使用enctype
Stella981 Stella981
3年前
Spring Boot 2.x基础教程:实现文件上传
文件上传的功能实现是我们做Web应用时候最为常见的应用场景,比如:实现头像的上传,Excel文件数据的导入等功能,都需要我们先实现文件的上传,然后再做图片的裁剪,excel数据的解析入库等后续操作。今天通过这篇文章,我们就来一起学习一下如何在SpringBoot中实现文件的上传。动手试试第一步:创建一个基础的SpringBo
Wesley13 Wesley13
3年前
Java多线程导致的的一个事物性问题
业务场景我们现在有一个类似于文件上传的功能,各个子站点接受业务,业务上传文件,各个子站点的文件需要提交到总站点保存,文件是按批次提交到总站点的,也就是说,一个批次下面约有几百个文件。      考虑到白天提交这么多文件会影响到子站点其他系统带宽,我们将分站点的文件提交到总站点这个操作过程独立出来,放到晚上来做,具体时间是晚上7:00到早上7:00。
前端文件上传的几种交互造轮子 | 京东云技术团队
前端文件上传本来是一个常规交互操作,没什么特殊性可言,但是最近在做文件上传,需要实现截图粘贴上传,去找了下有没有什么好用的组件,网上提供的方法有,但是没找完整的组件来支持cv上传,经过了解发现可以用剪贴板功能让自己的cv实现文件上传,于是自己就整合了目前几种文件上传的交互方式,码了一个支持cv的vue3文件上传组件(造个轮子)。