声明,作者本人是初学者,欢迎不吝指出错误之处。对本文观点请保持审视的态度。



1. 加载hunchentoot包

(ql:quickload "hunchentoot")

如果你还没有安装quicklisp,可以先安装quicklisp,再在repl中,执行此条表达式即可安装并加载hunchentoot包。

2.创建easy-acceptor类的实例对象

(defparameter *acceptor* (make-instance 'hunchentoot:easy-acceptor :port 4244))

创建一个easy-acceptor实例对象,并将其赋值为全局变量*acceptor*


注:这个*acceptor*和hunchentoot中所说的那个*acceptor*是不同的变量。
但是,我也不清楚hunchentoot文档中说的那个*acceptor*变量如何使用。
根据hunchentoot文档,其有一个动态变量:
[Special variable]
*acceptor*

The current ACCEPTOR object in the context of a request.
但我在repl中执行(symbo-value hunchentoot:*acceptor*)也好,直接键入hunchentoot:*acceptor*也好,只得到该变量未绑定的结果,执行(find-symbol "*acceptor*" "HUNCHENTOOT")之后得到的只有NIL。这是为何,hunchentoot提供的这个动态变量又该怎么使用呢。

3.更改网站根目录

(setf (hunchentoot:acceptor-document-root *acceptor*)
      #P"d:/apple/i686/.emacs.d/.quicklisp/dists/quicklisp/software/hunchentoot-v1.3.0/www/toptest/test1/")

hunchentoot默认的网站根目录是#P".../hunchentoot-v1.3.0/www/"(在我的例子中就是#P"d:/apple/i686/.emacs.d/.quicklisp/dists/quicklisp/software/hunchentoot-v1.3.0/www/")。我这里用的是在里面新建的文件夹,你不做这步也没问题,但下面的例子中注意替换成你自己的路径。

4. 准备一个html文件。

准备好的html文件:

<html>
  <head>
    <title>Hello!</title>
  </head>
  <body>
    <h1>Hello local server!</h1>
    <p>
    We just served our own files.
    </p>
	<form action="/test8" method="post" enctype="multipart/form-data">
	<input name="file" type="file" class="file"/> <br/>
	<input type="submit" class="button"/>
	</form>
  </body>
</html>

将这个文件保存在网站根目录下,即保存为d:/apple/i686/.emacs.d/.quicklisp/dists/quicklisp/software/hunchentoot-v1.3.0/www/toptest/test1/upload-file.html,如果你没有做第三步来改变网站根目录的话,就保存为d:/apple/i686/.emacs.d/.quicklisp/dists/quicklisp/software/hunchentoot-v1.3.0/www/upload-file.html

5. 定义处理函数

(hunchentoot:define-easy-handler (test8 :uri "/test8") ()
	   (setf (hunchentoot:content-type*) "text/plain")
	   (with-open-file (s (car (hunchentoot:post-parameter "file")))
	     (with-open-file (topath  #P"d:/apple/i686/.emacs.d/.quicklisp/dists/quicklisp/software/hunchentoot-v1.3.0/www/toptest/test1/hunchentoot-4.uppedfile"
			      :if-does-not-exist :create
			      :direction :output)
	       (let ((a (make-array 256 :initial-element #\Space :element-type (stream-element-type s))))
		 (loop for pos = (read-sequence a s)  ;;在这个loop中完成复制文件的工作
		       until (zerop pos)
		       do (write-sequence a topath :end pos))))))

注意,指定那个路径名(就是(with-open-file (topath ...后面那个路径)时,你可以自己指定一个别的,文件名和属性可以随便设置,比如设成 #P"d:/apple/banana/melon/copied.appletypefile
如果出现问题的话,可以注意下是不是所指定的地方需要特殊的存储权限什么的。
有个关键的地方:
如果在html文件中的form表单中的<form action="/test8" method="post" enctype="multipart/form-data"中的enctype="multipart/form-data"没有的话,那么处理函数中执行(hunchentoot:post-parameters*)的结果是(("file" . "setup.log"))(这里是我上传了一个我桌面上的一个名为setup.log的文件)。
执行(hunchentoot:post-parameter "file")的结果就是"setup.log"

而如果有那个enctype="multipart/form-data",那么(hunchentoot:post-parameters* "file")的结果为

(("file"
  #P"d:/apple/i686/.emacs.d/.quicklisp/dists/quicklisp/software/hunchentoot-v1.3.0/www/toptest/test1/hunchentoot-10"
  "setup.log" "application/octet-stream"))

(hunchentoot:post-parameter "file")的结果为:

(#P"d:/apple/i686/.emacs.d/.quicklisp/dists/quicklisp/software/hunchentoot-v1.3.0/www/toptest/test1/hunchentoot-10"
 "setup.log" "application/octet-stream")

注意,(hunchentoot:post-parameter "file")的结果和hunchentoot官方文档中的post-parameter函数的结果格式相符:(path file-name content-type)

path是一个pathname,它指明了上传的文件被暂时存储到了哪里,此例中上传的文件被存储到了d:/apple/i686/.emacs.d/.quicklisp/dists/quicklisp/software/hunchentoot-v1.3.0/www/toptest/test1/这个文件夹下,文件名为hunchentoot-10。文件在请求处理完毕之后会被删除,所以如果你想保存所上传的文件,就应该在处理请求的函数中把它移动或复制到其他地方。
在上面的那个处理函数中,我在d:/apple/i686/.emacs.d/.quicklisp/dists/quicklisp/software/hunchentoot-v1.3.0/www/toptest/test1/下,新建了文件hunchentoot-4.uppedfile,并将上传文件的内容复制到了新文件中。

file-name的值是一个字符串,代表浏览器上传的文件的文件名,此例中为"setup.log",这就是我所上传的文件的名字。
content-type的值是一个字符串,代表浏览器传送的内容的格式,此例中为"application/octet-stream"
注:我并不清楚application/octet-stream是什么东西,字面翻译来看是字节流。也不清楚form标签里的multipart/form-data指代的是什么,建议搜索或查阅HTTP标准文档。

6.开启服务器

(hunchentoot:start *acceptor*)

然后你可以在浏览器中访问http://localhost:4244/upload-file.html,在打开的页面中选择文件上传,之后,虽然网页会变成空白,但在你的网站根目录下(我的就是d:/apple/i686/.emacs.d/.quicklisp/dists/quicklisp/software/hunchentoot-v1.3.0/www/toptest/test1/),就会有一个名为hunchentoot-4.uppedfile的文件。
另外,如果你想关服务器,在repl中执行(hunchentoot:stop *acceptor*)的话,可能会卡住,我目前并不清楚具体的原因。




附注关于一次上传多个文件的简单示例:(除了下面所说的html文件和处理函数要改改外,别的没啥区别)

1. 首先是写个html文件:mulupload-file.html

<html>
  <head>
    <title>Hello!</title>
  </head>
  <body>
    <h1>Hello local server!</h1>
    <p>
    We just served our own files.
    </p>
	<form action="/test81" method="post" enctype="multipart/form-data" multiple>
	<input name="file1" type="file" class="file"/> <br/>
	<input name="file2" type="file" class="file"/> <br/>
	<input type="submit" class="button"/>
	</form>
  </body>
</html>

注意form标签那里多了个multiple。

2. 定义一个处理函数。

(hunchentoot:define-easy-handler (test9 :uri "/test81") ()
	 (setf (hunchentoot:content-type*) "text/plain")
	 (print (hunchentoot:post-parameters*))
	 (print (hunchentoot:post-parameter "file1"))
	 (print (hunchentoot:post-parameter "file2"))
	   (with-open-file (file1-stream (car (hunchentoot:post-parameter "file1")))
	     (print "the first line of file1")
	     (print (read-line file1-stream)))
	   (with-open-file (file2-stream (car (hunchentoot:post-parameter "file2")))
	     (print "the first line of file2")
	     (print (read-line file2-stream))))
posted on 2021-12-21 17:00  NJyO  阅读(108)  评论(0编辑  收藏  举报