开发者

How to remove .py from urls for pyservlet using jython

I'm looking at the jython servlet tutorial and have got everything working. How do I make the url be

localhost:8080/jythondemo/JythonServlet1

instead of

localhost:8080/jythondemo/JythonServlet1.py

http://seanmcgrath.blogspot.com/JythonWebAppTutorialPart1.html

Here is the relevant part from web.xml

<web-app>      
    <servlet>
        <servlet-name>ServletTest</servlet-name>
        <servlet-class>ServletTest</servlet-class>
    </servlet>
    <servlet>
        <servlet-name>PyServlet</servlet-name>
        <servlet-class>org.python.util.PyServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

  开发者_如何学C  <servlet-mapping>
        <servlet-name>ServletTest</servlet-name>
        <url-pattern>/ServletTest</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>PyServlet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
</web-app>

I've also tried with

<servlet-mapping>
    <servlet-name>PyServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

It seems with the above changes pyservlet is getting the url JythonServlet1 but it does not know what to do with it. Here is the error message:

javax.servlet.ServletException: I can't guess the name of the class from /.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/testjython3/JythonServlet1
org.python.util.PyServlet.createInstance(PyServlet.java:202)
org.python.util.PyServlet.loadServlet(PyServlet.java:188)
org.python.util.PyServlet.getServlet(PyServlet.java:178)
org.python.util.PyServlet.service(PyServlet.java:155)


As noted by @Jigar there's a restriction in the actual Jython Servlet code. However, you may get around that issue by creating a simple URL translator. It consists in a Servlet that internally forwards the request to the Py Servlet.

Use the following code for web.xml:

<web-app>      
    <servlet>
        <servlet-name>AliasServlet</servlet-name>
        <servlet-class>juanal.AliasServlet</servlet-class>
    </servlet>
    <servlet>
        <servlet-name>PyServlet</servlet-name>
        <servlet-class>org.python.util.PyServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>AliasServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>PyServlet</servlet-name>
        <url-pattern>*.py</url-pattern>
    </servlet-mapping>
</web-app>

Create a new class, say, juanal.AliasServlet, with the following content:

package juanal;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class AliasServlet extends HttpServlet
{

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
    {
        String URI = request.getRequestURI();
        String newURI = URI + ".py";
        getServletConfig().getServletContext().getRequestDispatcher(newURI).forward(request, response);
    }
}

So, for a URL like this: localhost:8080/jythondemo/JythonServlet1, it will internally forward the request to JythonServlet1.py


Try this

<url-pattern>/*</url-pattern>

After that every request will be served by PyServlet


It looks like the problem is inherent to PyServlet.java. PyServlet uses regular expressions to find the name of the Python class to load based on the path of the request. The regular expression used is defined as follows (line 245 in my copy of the source):

private static final Pattern FIND_NAME = Pattern.compile("([^/]+)\\.py$");

Unfortunately, this regular expression will break if the input URL path doesn't contain a ".py" extension - this raises the error that you saw. From line 200:

Matcher m = FIND_NAME.matcher(file.getName());
if (!m.find()) {
    throw new ServletException("I can't guess the name of the class from "
            + file.getAbsolutePath());
}

Since FIND_NAME is defined as private and final, I don't see a good way to override this behavior by just subclassing PyServlet - I think you'll have to make a copy of PyServlet and redefine this behavior in a fresh class.


I'm new to python. But if you have Apache, you could rewrite all .py URLs!


Just for the record: @Juanal AliasServlet trick works nicely. I just had to use request.getServletPath() instead of getRequestURI(). (working with Eclipse)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜