You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Ratpack实现类似Apache的动态目录列表?

Ratpack Dynamic Directory Listing in Groovy

Hey there! Nice to see you experimenting with Ratpack. The bad news is that Ratpack's built-in files handler doesn't include a native dynamic directory listing feature like Apache does out of the box. The good news is it's super easy to add this functionality with a custom handler—let me walk you through it.

The Approach

We'll add a top-level handler that checks if the requested path points to a directory (that doesn't have an index.html file). If it does, we'll generate a simple HTML directory listing on the fly. If not, we'll pass the request along to the existing files handler so it can serve static files or index pages as usual.

Full Working Code

Here's how to modify your script to add directory listing:

#!/usr/bin/env groovy
@Grab('io.ratpack:ratpack-groovy:1.5.1')
import static ratpack.groovy.Groovy.ratpack
import java.net.URLEncoder

ratpack {
  handlers {
    // Custom handler for directory listings
    all { ctx ->
      def requestPath = ctx.request.path
      
      // Only process paths that end with a slash (likely directory requests)
      if (requestPath.endsWith('/')) {
        def targetDir = ctx.fileSystemBinding.file(requestPath)
        
        // Check if the path exists and is a directory
        if (targetDir.exists() && targetDir.isDirectory()) {
          // Check if an index file exists—if so, let the files handler serve it
          def indexFile = targetDir.resolve("index.html")
          if (!indexFile.exists()) {
            // Generate directory listing HTML
            def listingHtml = new StringBuilder()
            listingHtml.append("""
              <html>
                <head>
                  <title>Directory: ${requestPath}</title>
                  <style>
                    body { font-family: Arial, sans-serif; margin: 2rem; }
                    h1 { color: #2c3e50; }
                    ul { list-style-type: none; padding-left: 0; }
                    li { margin: 0.5rem 0; }
                    a { text-decoration: none; color: #3498db; }
                    a:hover { text-decoration: underline; }
                    .dir { font-weight: bold; }
                  </style>
                </head>
                <body>
            """)
            listingHtml.append("<h1>Directory Listing: ${requestPath}</h1>")
            listingHtml.append("<ul>")
            
            // Add link to parent directory (if not at root)
            if (!requestPath.equals('/')) {
              def parentPath = requestPath.substring(0, requestPath.lastIndexOf('/')) ?: '/'
              listingHtml.append("<li><a href=\"${parentPath}\">.. (Parent Directory)</a></li>")
            }
            
            // Sort files alphabetically (case-insensitive) and list them
            targetDir.listFiles().sort { a, b ->
              a.name.compareToIgnoreCase(b.name)
            }.each { file ->
              def encodedFileName = URLEncoder.encode(file.name, 'UTF-8')
              def fileUrl = requestPath + encodedFileName + (file.isDirectory() ? '/' : '')
              def fileClass = file.isDirectory() ? "class='dir'" : ""
              
              listingHtml.append("""
                <li>
                  <a href="${fileUrl}" ${fileClass}>${file.name}</a>
                  ${file.isDirectory() ? '/' : ""}
                </li>
              """)
            }
            
            listingHtml.append("</ul></body></html>")
            
            // Send the generated HTML response
            ctx.response.contentType("text/html")
            ctx.render(listingHtml.toString())
            return // Stop processing further handlers
          }
        }
      }
      // If we get here, pass the request to the next handler (files)
      ctx.next()
    }

    // Your original static files handler
    files {
      dir "static"
      index // Still serves index.html when present
    }
  }
}

Key Details Explained

  • Handler Order: The custom all handler runs first, so it can intercept directory requests before the files handler takes over.
  • Index File Priority: We check for an index.html first—if it exists, we let the files handler serve it just like before.
  • Clean HTML & Styling: I added basic CSS to make the listing look nicer, but you can tweak this to match your needs.
  • URL Encoding: We use URLEncoder to handle filenames with spaces or special characters correctly.
  • Sorting: Files are sorted alphabetically (case-insensitive) for a more user-friendly listing.

How to Use It

  1. Save this script (e.g., ratpack-server.groovy)
  2. Create a static directory in the same folder
  3. Add some files/subdirectories to static
  4. Run the script with groovy ratpack-server.groovy
  5. Visit http://localhost:5050/ in your browser—you'll see the directory listing if there's no index.html present.

内容的提问来源于stack exchange,提问作者wu-lee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:12:55