zoukankan      html  css  js  c++  java
  • ring.util.servlet 简短注释

    最近在写Clojure web的后台。用的是ring,前端还可以。看看说明文档就可以搞了。后端,真心不懂怎么调用的。所以看了一下源代码。
    做了一点注释。分析一下。

    (ns ring.util.servlet
      "Compatibility functions for turning a ring handler into a Java servlet."
      (:require [clojure.java.io :as io]
                [clojure.string :as string])
      (:import (java.io File InputStream FileInputStream) ; 文件处理类
               (javax.servlet.http HttpServlet
                                   HttpServletRequest
                                   HttpServletResponse))) ; http处理类
    
    (defn- get-headers
      "Creates a name/value map of all the request headers." ; 创建请求映射
      [^HttpServletRequest request]
      (reduce
        (fn [headers, ^String name]
          (assoc headers
            (.toLowerCase name) ; 全部小写
            (->> (.getHeaders request name) ; 返回指定的请求
                 (enumeration-seq) ; 返回枚举序列
                 (string/join ","))))
        {}
        (enumeration-seq (.getHeaderNames request)))) ; 返回处理过的序列
    
    (defn- get-content-length
      "Returns the content length, or nil if there is no content." ; 获得内容大小
      [^HttpServletRequest request]
      (let [length (.getContentLength request)]
        (if (>= length 0) length)))
    
    (defn get-client-cert
      "Returns the SSL client certificate of the reqest, if one exists." ; 获得SSL证书
      [^HttpServletRequest request]
      (first (.getAttribute request "javax.servlet.request.X509Certificate")))
    
    (defn build-request-map
      "Create the request map from the HttpServletRequest object." ; 创建来自HttpServletRequest对象
      [^HttpServletRequest request]
      {:server-port        (.getServerPort request)
       :server-name        (.getServerName request)
       :remote-addr        (.getRemoteAddr request)
       :uri                (.getRequestURI request)
       :query-string       (.getQueryString request)
       :scheme             (keyword (.getScheme request))
       :request-method     (keyword (.toLowerCase (.getMethod request)))
       :headers            (get-headers request)
       :content-type       (.getContentType request)
       :content-length     (get-content-length request)
       :character-encoding (.getCharacterEncoding request)
       :ssl-client-cert    (get-client-cert request)
       :body               (.getInputStream request)}) ; 内容
    
    (defn merge-servlet-keys
      "Associate servlet-specific keys with the request map for use with legacy
      systems." ; 包装servlet类 形式是映射 给其他调用
      [request-map
       ^HttpServlet servlet
       ^HttpServletRequest request
       ^HttpServletResponse response]
      (merge request-map
        {:servlet          servlet
         :servlet-request  request
         :servlet-response response
         :servlet-context  (.getServletContext servlet)})) ; 上下文
    
    (defn set-status
      "Update a HttpServletResponse with a status code." ; 响应状态设置
      [^HttpServletResponse response, status]
      (.setStatus response status))
    
    (defn set-headers
      "Update a HttpServletResponse with a map of headers."
      [^HttpServletResponse response, headers]
      (doseq [[key val-or-vals] headers]
        (if (string? val-or-vals) ; 字符串格式
          (.setHeader response key val-or-vals)
          (doseq [val val-or-vals] ; 映射格式
            (.addHeader response key val))))
      ; Some headers must be set through specific methods
      (when-let [content-type (get headers "Content-Type")] ; 条件绑定到content-type
        (.setContentType response content-type)))
    
    (defn- set-body
      "Update a HttpServletResponse body with a String, ISeq, File or InputStream." ; 更新内容
      [^HttpServletResponse response, body]
      (cond
        (string? body) ; 字符串
          (with-open [writer (.getWriter response)]
            (.print writer body))
        (seq? body) ; 序列
          (with-open [writer (.getWriter response)]
            (doseq [chunk body]
              (.print writer (str chunk))
              (.flush writer)))
        (instance? InputStream body) ; 输入流
          (with-open [^InputStream b body]
            (io/copy b (.getOutputStream response)))
        (instance? File body) ; 对象
          (let [^File f body]
            (with-open [stream (FileInputStream. f)]
              (set-body response stream)))
        (nil? body)
          nil
        :else
          (throw (Exception. ^String (format "Unrecognized body: %s" body)))))
    
    (defn update-servlet-response
      "Update the HttpServletResponse using a response map." ; 更新输出内容
      [^HttpServletResponse response, {:keys [status headers body]}]
      (when-not response
        (throw (Exception. "Null response given.")))
      (when status
        (set-status response status))
      (doto response
        (set-headers headers)
        (set-body body)))
    
    (defn make-service-method
      "Turns a handler into a function that takes the same arguments and has the
      same return value as the service method in the HttpServlet class." ; 服务方法
      [handler]
      (fn [^HttpServlet servlet
           ^HttpServletRequest request
           ^HttpServletResponse response]
        (let [request-map (-> request
                            (build-request-map)
                            (merge-servlet-keys servlet request response))]
          (if-let [response-map (handler request-map)] ; 关键在于用handler来处理request-map 并且把结果更新到response中
            (update-servlet-response response response-map)
            (throw (NullPointerException. "Handler returned nil"))))))
    
    (defn servlet
      "Create a servlet from a Ring handler.." ; 从处理器创建servlet
      [handler]
      (proxy [HttpServlet] []
        (service [request response]
          ((make-service-method handler)
             this request response))))
    
    (defmacro defservice 
      "Defines a service method with an optional prefix suitable for being used by
      genclass to compile a HttpServlet class.
      e.g. (defservice my-handler)
           (defservice \"my-prefix-\" my-handler)"
      ([handler]
       `(defservice "-" ~handler))
      ([prefix handler]
       `(defn ~(symbol (str prefix "service"))
          [servlet# request# response#]
          ((make-service-method ~handler)
             servlet# request# response#))))

    其实写Clojure还是很清楚的。没有想象当中那么复杂。

  • 相关阅读:
    physicslectureGriavity
    electromagnetic
    dp
    physicsmechanic wave
    C# 2.0 Specification(迭代器)(二)
    C#类、接口、虚方法和抽象方法接口与抽象类的区别实例
    web.config connectionStrings 数据库连接字符串的解释(转载)
    onpropertychange事件
    C#中ParameterizedThreadStart和ThreadStart区别
    C# 文件操作全收录
  • 原文地址:https://www.cnblogs.com/snakevash/p/3021687.html
Copyright © 2011-2022 走看看