2011-08-16 17 views
3

私はラケットWebサーバ用のサーブレットを作って、サイトに写真をアップロードし、既にアップロードされたファイルを同じページ。私はPostgreSQLデータベースの中や外に直接写真をディスクやメモリ上の一時ファイルに保存するのではなく、ストリーミングしたいと思います。出来ますか?もしそうなら、それを行う最良の方法は何ですか?ステートレスなサーブレットでこれを行うことはできますか?どんな助けでも大歓迎です!Racket ServerとPostgreSQL - メモリやディスクに保存しないでBLOBをアップロード/ダウンロードする

答えて

4

する必要があります。私はPLaneTからdb packageを(私はそれを書いたので)お勧めします。あなたはthe docsをオンラインで読むことができます。

PostgreSQLのテーブルには、画像コンテンツのフィールドがbyteaである必要があります。ラケット側ではバイト文字列として表されます。

サーブレットでは、イメージの内容がresponse/fullの構造体を返しているはずです。あなたはリターンコード、MIMEタイプなどを自分で扱わなければなりません。 (ドキュメントの例を参照してください)

1

科学の名前で、私は自分の質問に答えの半分を掲示しています。このページには、すでにデータベースにある画像が表示されます。アップロードページは開いたままの質問です。

Ryan Culpepperは、ここに掲載されている内容を超えた私的な対応で私を助けました。私は彼の助けを彼に感謝します。黒い魔法のように見えるすべてのものが彼から来て、すべての不器用なものは私のものです。コードを改善する方法に関するすべての提案に感謝します。

#lang racket 
#| 
================================================================================================================ 
We are assuming that the PostgreSQL database we are connecting to 
    has a table "person" with columns 
     "id", "firstname", "lastname" and "portrait". 

The "portrait" column contains the OID of a BLOB 
    that stores the image file we want to display. 

Suppose further that the table "person" has a legitimate entry with 
    id=22, firstname="John", lastname="Doe" 
Then the page 
    http://127.0.0.1/page/22 
should display greetings "Hello, John Doe!" 
    and show the portrait of the person below the greeting. 
The portrait itself should be at 
    http://127.0.0.1/portrait/22.jpg 

The program should be run via Racket -t "<filename>" 
    after defining the environment variables 
     "DB_USER", "DB_NAME", "DB_PORT", "DB_PASSWORD". 
================================================================================================================ 
|# 

(require 
    web-server/servlet 
    web-server/servlet-env 
    web-server/dispatch 
    web-server/stuffers/hmac-sha1 
    web-server/http 
    web-server/http/response-structs 
    (planet ryanc/db:1:4) 
    (planet ryanc/db:1:4/util/connect) 
    net/base64) 
;--------------------------------------------------------------------------------------------------------------- 
; response 
;--------------------------------------------------------------------------------------------------------------- 
(define (start given-request) 
    (site-dispatch given-request)) 

(define-values (site-dispatch given-request) 
    (dispatch-rules 
     [("page" (integer-arg)) show-page] 
     [("portrait" (string-arg)) show-portrait])) 

(define (show-page given-request given-person-id) 
    (let* ([db-person_firstname_lastname 
       (query-maybe-row my-connection 
        "SELECT firstname, lastname FROM person WHERE id = $1" 
         given-person-id)] 
      [my-firstname (vector-ref db-person_firstname_lastname 0)] 
      [my-lastname (vector-ref db-person_firstname_lastname 1)]) 
     (response/xexpr 
      `(html ([xmlns "http://www.w3.org/1999/xhtml"]) 
       (head 
        (title "Page with a portrait")) 
       (body 
        (div ([id "greetings"]) 
         ,(string-append 
          "Hello, " my-firstname " " my-lastname "! ")) 
         (img ( [src ,(string-append "/portrait/" 
          (number->string given-person-id) ".jpg")]))))))) 

(define (show-portrait given-request given-portrait-file) 
    (let* ([my-user-id (car (regexp-match #rx"^([0-9]+)" 
       given-portrait-file))] 
      [my-portrait-oid (query-value my-connection 
       "SELECT portrait FROM person WHERE id = $1" 
        (string->number my-user-id))] 
      [STREAMOUT_CHUNK_SIZE 1000] 
      [INV_READ #x00040000]) 
    (response 
      200         ; code 
      #"Okay"        ; message 
      (current-seconds)     ; seconds 
      #"image/jpeg"      ; mime type 
      empty        ; headers 
      (lambda (given-output-stream)  ; body generator 
       (start-transaction my-connection) 
       (define object-descriptor 
        (query-value my-connection 
         "SELECT LO_OPEN($1, $2)" my-portrait-oid INV_READ)) 
       (define (stream-next-chunk) 
        (begin 
         (define my-next-chunk 
          (query-value my-connection 
           "SELECT LOREAD($1, $2)" 
            object-descriptor STREAMOUT_CHUNK_SIZE)) 
         (if (> (bytes-length my-next-chunk) 0) 
          (begin 
           (write-bytes my-next-chunk given-output-stream) 
           (stream-next-chunk) 
           #t) 
          #f))) 
       (stream-next-chunk) 
       (commit-transaction my-connection))))) 
;--------------------------------------------------------------------------------------------------------------- 
; database connection 
;--------------------------------------------------------------------------------------------------------------- 
(define my-connection 
    (virtual-connection 
     (connection-pool 
      (lambda() 
       (eprintf "(Re)establishing database connection...\n") 
       (postgresql-connect 
        #:user (getenv "DB_USER") 
        #:database (getenv "DB_NAME") 
        #:port (string->number (getenv "DB_PORT")) 
        #:socket #f 
        #:password (getenv "DB_PASSWORD")  
        #:allow-cleartext-password? #f 
        #:ssl 'optional ; other choices: 'yes 'no 
        ))))) 
;--------------------------------------------------------------------------------------------------------------- 
; servlet parameters 
;--------------------------------------------------------------------------------------------------------------- 
(serve/servlet start 
    #:command-line? #t    ; #t to use serve/servlet in a start up script for a Web application, and don't want a browser opened or the DrRacket banner printed 
    #:connection-close? #f   ; #t to close every connection after one request. (Otherwise, the client decides based on what HTTP version it uses.)  
    #:launch-browser? #f  
    #:quit? #f      ; #t makes the URL "/quit" end the server 
    #:banner? #t     ; #t to print an informative banner 
    #:listen-ip #f     ; give an IP to accept connections from external machines 
    #:port 80      ; 443 is the default for SSL, 80 - for open connections 
    #:servlet-regexp #rx""   ; #rx"" captures top-level requests 
    #:stateless? #t 
    #:server-root-path    ; where the server files are rooted, default=(the distribution root) 
     (build-path ".") 
    #:ssl? #f 
    #:log-file (build-path "server.log")) 
関連する問題