Jython在Web开发中的应用:Servlet与JSP实践
1. Jython在Web开发中的定位
Jython适用于Java适用的任何Web开发场景,尤其在需要快速开发和增加灵活性的Java项目中表现出色。服务器端Java Web编程主要通过Servlet和Java Server Pages(JSP)实现,因此Jython的主要应用也是Servlet和JSP。不过,Java企业级包(j2ee)在Web应用开发中也很重要,Jython在这些技术中同样有效。但需要注意的是,Jython并不适合用于实现CGI脚本,因为JVM的启动时间会导致性能不佳,而Servlet和JSP具有持久性,能在Web请求之间保持在内存中。
使用Jython进行Web编程有诸多优势,高质量的Servlet容器随处可得且广泛部署。Java Servlet应用可以受益于Jython的灵活性和高级语言特性,还能利用Java和Jython的库。常见的Servlet容器包括WebLogic、WebSphere、Tomcat、Jigsaw、Resin和Jetty等。
1.1 Jython Servlet容器
Jython可以与任何兼容的Java Servlet容器配合使用,常见的有以下几种:
-
Jakarta’s Tomcat
:是Servlet和Java Server Pages规范的参考实现,本章使用的版本是3.2.3,支持2.2 Servlet和1.1 JSP规范。Tomcat 4.0将实现2.3 Servlet和1.2 JSP规范。所有示例都应能在任何符合Servlet 2.2/JSP 1.1规范的容器中运行。Tomcat发行版包含本章所需的Servlet和JSP类,无需额外下载。
-
Apache JServ
:是为Apache创建的Servlet(版本2.0)引擎,常用于Jython Servlet开发。需要单独下载Java Servlet Development Kit 2.0,Java Server Pages需要一个外部模块。
-
Jigsaw
:是W3C的实验性Web服务器,实际上比“实验性”这个标签所暗示的更成熟。它是一个完全符合HTTP/1.1的Web服务器和缓存代理服务器,支持Servlet 2.2规范和Java Server Pages 1.1。
-
Jetty
:是一个紧凑高效的Java Web服务器,支持Servlet 2.2和JSP 1.1规范,支持HTTP 1.1,包含SSL支持,并能轻松与EJB服务器集成。
这些工具的安装指南可从各自的网站获取。
2. 定义简单的Servlet类
2.1 简单的Java Servlet
以下是一个基本的Java Servlet示例:
// Filename: JavaServlet.java
import javax.servlet.*;
import java.io.*;
public class JavaServlet extends GenericServlet {
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
res.setContentType("text/html");
PrintWriter toClient = res.getWriter();
toClient.println("<html><body>" +
"This is a Java Servlet." +
"</body></html>");
}
}
该示例使用了
GenericServlet
作为基类,
service
方法是抽象的,必须在子类中实现,用于响应Web请求。
2.2 简单的Jython Servlet
对应的Jython Servlet示例如下:
# Filename: JythonServlet.py
from javax import servlet
import random # Not used, just here to test module imports
class JythonServlet(servlet.GenericServlet):
def service(self, req, res):
res.setContentType("text/html")
toClient = res.getWriter()
toClient.println("""<html><body>
This is a Servlet of the Jython variety.
</body></html>""")
Jython Servlet与Java Servlet在导入、继承和实现方面类似,但使用了Jython的语法。
2.3 测试Java和Jython Servlet
2.3.1 安装Tomcat
- 从http://jakarta.apache.org 下载Tomcat,建议下载jakarta - tomcat - 3.2.3版本。
-
解压文件到有足够权限的目录,设置
TOMCAT_HOME环境变量。-
Windows系统:
set TOMCAT_HOME=c:\jakarta - tomcat - 3.2.3 -
*nix系统:
export TOMCAT_HOME=/usr/local/jakarta - tomcat3.2.3
-
Windows系统:
-
设置
JAVA_HOME环境变量,例如使用JDK1.3.1:-
Windows系统:
set JAVA_HOME=c:\jdk1.3.1 -
*nix系统:
export JAVA_HOME=/usr/java/jdk1.3.1
-
Windows系统:
-
启动Tomcat:
-
Windows系统:
%TOMCAT_HOME%\bin\startup.bat -
*nix系统:
$TOMCAT_HOME/bin/startup.sh
-
Windows系统:
-
停止Tomcat:
-
Windows系统:
%TOMCAT_HOME%\bin\shutdown.bat -
*nix系统:
$TOMCAT_HOME/bin/shutdown.sh
-
Windows系统:
2.3.2 安装Java Servlet
-
将
JavaServlet.java文件放在%TOMCAT_HOME%\webapps\jython\WEB - INF\classes目录下。 -
在该目录下编译文件:
javac -classpath %TOMCAT_HOME%\lib\servlet.jar JavaServlet.java -
启动Tomcat,在浏览器中访问
http://localhost:8080/jython/servlet/JavaServlet,应看到消息“This is a Java Servlet”。
2.3.3 安装Jython Servlet
有两种使用Jython Servlet的方法,这里使用
jythonc
编译。
-
编译Jython Servlet
:
- 将
JythonServlet.py
文件放在
%TOMCAT_HOME%\webapps\jython\WEB - INF\classes
目录下。
- 确保
CLASSPATH
包含
servlet.jar
,使用以下命令编译:
jythonc -w . JythonServlet.py
-
添加jython.jar到类路径
:有三种方式:
- 推荐将
jython.jar
添加到上下文的
lib
目录。
- 不建议将
jython.jar
添加到Tomcat的
lib
目录。
- 可以将
jython.jar
留在Jython的安装目录,在运行Tomcat前添加到类路径。
-
使Jython的lib目录对Servlet可用
:有三种方法:
- 设置
python.home
属性。
- 冻结所需模块。
- 让每个Servlet显式地将模块位置添加到
sys.path
。
测试Jython Servlet,在浏览器中访问
http://localhost:8080/jython/servlet/jythonServlet
,应看到消息“This is a Servlet of the Jython variety”。
3. 关于GenericServlet
GenericServlet
是一个不特定于任何协议的Servlet类,
HttpServlet
更常用于Web编程,它是
GenericServlet
的子类。以下是
GenericServlet
的一些方法及在Jython子类中的使用示例:
| Java Signature | Usage in Jython Subclass |
| — | — |
|
public void init(ServletConfig config) throws ServletException;
|
def init(self, config):
|
|
public void destroy();
|
def destroy(self):
|
|
public abstract void service(ServletRequest request, ServletResponse response) throws ServletException, IOException;
|
def service(self, request, response):
|
|
public String getServletInfo();
|
def getServletInfo(self): return "Info string"
|
|
public void log(String message);
|
self.log("message")
|
|
public ServletConfig getServletConfig();
|
config = self.getServletConfig()
|
|
public java.util.enumeration getInitParameterNames();
|
nameList = self.getInitParameterNames()
|
|
public String getInitParameter(String name)
|
param = self.getInitParameter("paramName")
|
|
public ServletContext getServletContext()
|
context = self.getServletContext
|
3.1 计数器Servlet示例
# filename: HitCounter.py
from javax import servlet
from time import time, ctime
import os
class HitCounter(servlet.GenericServlet):
def init(self, cfg=None):
if cfg:
servlet.GenericServlet.init(self, cfg)
else:
servlet.GenericServlet.init(self)
contextRoot = self.servletContext.getRealPath(".")
self.file = os.path.join(contextRoot, "counterdata.txt")
if os.path.exists(self.file):
lastCount = open(self.file, "r").read()
try:
self.totalHits = int(lastCount)
except:
self.totalHits = 0
else:
self.totalHits = 0
def service(self, req, res):
res.setContentType("text/html")
toClient = res.getWriter()
toClient.println("<html><body>")
toClient.println("Total Hits: %i<br>" % (self.totalHits,))
self.totalHits += 1
toClient.println("</body></html>")
def destroy(self):
f = open(self.file, "w")
f.write(str(self.totalHits))
f.close()
该示例展示了
init
、
service
和
destroy
方法的使用,这些方法对应Servlet生命周期的不同阶段。
4. HttpServlet
GenericServlet
适用于任何聊天类型的协议,而Web开发主要使用HTTP协议,因此
javax.Servlet.http.HttpServlet
是更好的选择。
HttpServlet
是
GenericServlet
的子类,它为每个HTTP方法定义了方法,如
doGet
、
doPost
等。
4.1 HttpServlet方法
| Java Signature | Usage in Jython Subclass |
|---|---|
doDelete(HttpServletRequest req, HttpServletResponse resp)
|
def doDelete(self, req, res):
|
doGet(HttpServletRequest req, HttpServletResponse resp)
|
def doGet(self, req, res):
|
doHead(HttpServletRequest req, HttpServletResponse resp)
|
def doHead(self, req, res):
|
doOptions(HttpServletRequest req, HttpServletResponse resp)
|
def doOptions(self, req, res):
|
doPost(HttpServletRequest req, HttpServletResponse resp)
|
def doPost(self, req, res):
|
doPut(HttpServletRequest req, HttpServletResponse resp)
|
def doPut(self, req, res):
|
doTrace(HttpServletRequest req, HttpServletResponse resp)
|
def doTrace(self, req, res):
|
getLastModified(HttpServletRequest req)
|
def getLastModified(self, req):
|
service(HttpServletRequest req, HttpServletResponse resp)
|
def service(self, req, res):
|
service(ServletRequest req, ServletResponse res)
|
def service(self, req, res):
|
4.2 HttpServlet示例
# file get_post.py
from time import time, ctime
from javax import servlet
from javax.servlet import http
class get_post(http.HttpServlet):
head = "<head><title>Jython Servlets</title></head>"
title = "<center><H2>%s</H2></center>"
def doGet(self, req, res):
res.setContentType("text/html")
out = res.getWriter()
out.println('<html>')
out.println(self.head)
out.println('<body>')
out.println(self.title % req.method)
out.println("This is a response to a %s request" %
(req.getMethod(),))
out.println("<P>In this GET request, we see the following " +
"header variables.</P>")
out.println("<UL>")
for name in req.headerNames:
out.println(name + " : " + req.getHeader(name) + "<br>")
out.println("</UL>")
out.println(self._params(req))
out.println("""
<P>The submit button below is part of a form that uses the
"POST" method. Click on this button to do a POST request.
</P>""")
out.println('<br><form action="get_post" method="POST">' +
'<INPUT type="hidden" name="variable1" value="one">' +
'<INPUT type="hidden" name="variable1" value="two">' +
'<INPUT type="hidden" name="variable2" value="three">' +
'<INPUT type="submit" name="button" value="submit">')
out.println('<br><font size="-2">time accessed: %s</font>'
% ctime(time()))
out.println('</body></html>')
def doPost(self, req, res):
res.setContentType("text/html");
out = res.getWriter()
out.println('<html>')
out.println(self.head)
out.println('<body>')
out.println(self.title % req.method)
out.println("This was a %s<br><br>" % (req.getMethod(),))
out.println(self._params(req))
out.println('<br> back to <a href="get_post">GET</a>')
out.println('<br><font size="-2">time accessed: %s</font>'
% ctime(time()))
out.println('</body></html>')
def _params(self, req):
params = "Here are the parameters sent with this request:<UL>"
names = req.getParameterNames()
if not names.hasMoreElements():
params += "None<br>"
for name in names:
value = req.getParameterValues(name)
params += "%s : %r<br>" % (name, tuple(value))
params += "</UL>"
return params
该示例实现了
doGet
和
doPost
方法,展示了如何根据客户端请求类型调用不同的方法。
5. HttpServletRequest和HttpServletResponse
与客户端的通信通过
HttpServletRequest
和
HttpServletResponse
对象进行,它们提供了更高级的HTTP特定方法。
5.1 HttpServletRequest方法和属性
| Method and Property | Description |
|---|---|
getAuthType()
/
AuthType
|
返回描述认证类型的字符串,用户未认证时为
None
|
getContextPath()
/
contextPath
| 返回标识请求上下文的路径信息 |
getCookies()
/
cookies()
| 返回客户端请求中发送的所有cookie |
getDateHeader(name)
| 以长类型检索指定头的值 |
getHeader(name)
| 以字符串形式返回指定头的值 |
getHeaderNames()
/
headerNames
| 返回请求中包含的所有头名称 |
getHeaders(name)
| 返回指定头名称的所有值 |
getIntHeader(name)
| 以Java int类型检索指定头的值 |
getMethod()
/
method
| 返回请求类型的字符串 |
getPathInfo()
/
pathInfo
| 客户端发送的所有额外路径信息 |
getPathTranslated()
/
pathTranslated
| 返回从客户端请求的额外路径信息派生的真实路径 |
getQueryString()
/
queryString
| 返回客户端请求的查询字符串 |
getRemoteUser()
/
remoteUser
|
返回客户端的登录名,未认证时为
None
|
getRequestedSessionId()
/
requestedSessionId
| 返回客户端的会话ID |
getRequestURI()
/
requestURI
| 返回协议名称和查询字符串之间的部分 |
getServletPath()
/
servletPath
| 返回指定当前Servlet的URL部分 |
getSession()
/
session
| 返回当前会话,需要时创建 |
getSession(create)
|
如果存在则返回当前会话,否则根据
create
值创建新会话
|
getUserPrincipal()
/
userPrincipal
|
返回包含当前认证信息的
java.security.Principal
对象
|
isRequestedSessionIdFromCookie()
| 根据当前会话ID是否来自cookie返回1或0 |
isRequestedSessionIdFromURL()
| 根据当前会话ID是否来自请求的URL字符串返回1或0 |
isRequestedSessionIdValid()
| 根据请求的会话ID是否仍然有效返回1或0 |
isUserInRole(role)
| 指示用户是否在指定角色中返回1或0 |
5.2 HttpServletResponse方法和属性
| Method and Property | Description |
|---|---|
addCookie(cookie)
| 向响应中添加cookie |
addDateHeader(headerName, date)
| 添加具有日期(长)值的头 |
addHeader(headerName, value)
| 添加头名称和值 |
addIntHeader(headerName, value)
| 添加具有整数值的头 |
containsHeader(headerName)
| 根据指定头是否存在返回1或0 |
encodeRedirectUrl(url)
|
为
sendRedirect
方法编码URL
|
encodeRedirectURL(url)
|
为
sendRedirect
方法编码URL
|
encodeURL(url)
| 通过包含会话ID对URL进行编码 |
sendError(sc)
| 使用状态码发送错误 |
sendError(sc, msg)
| 使用指定的状态码和消息发送错误 |
sendRedirect(location)
| 发送临时重定向到指定位置 |
setDateHeader(headerName, date)
| 将头名称设置为指定的日期(长)值 |
setHeader(headerName, value)
| 将头名称设置为指定的值 |
setIntHeader(headerName, value)
| 将头名称设置为指定的整数值 |
setStatus(statusCode)
/
status
| 设置响应状态码 |
5.3 HttpServletResponse状态码
| Error Code | Status |
|---|---|
| 100 |
SC_CONTINUE
|
| 101 |
SC_SWITCHING_PROTOCOLS
|
| 200 |
SC_OK
|
| 201 |
SC_CONTINUE
|
| 202 |
SC_ACCEPTED
|
| 203 |
SC_NON_AUTHORITATIVE_INFORMATION
|
| 204 |
SC_NO_CONTENT
|
| 205 |
SC_RESET_CONTENT
|
| 206 |
SC_PARTIAL_CONTENT
|
| 300 |
SC_MULTIPLE_CHOICES
|
| 301 |
SC_MOVED_PERMANENTLY
|
| 302 |
SC_MOVED_TEMPORARILY
|
| 303 |
SC_SEE_OTHER
|
| 304 |
SC_NOT_MODIFIED
|
| 305 |
SC_USE_PROXY
|
| 400 |
SC_BAD_REQUEST
|
| 401 |
SC_UNAUTHORIZED
|
| 402 |
SC_PAYMENT_REQUIRED
|
| 403 |
SC_FORBIDDEN
|
| 404 |
SC_NOT_FOUND
|
| 405 |
SC_METHOD_NOT_ALLOWED
|
| 406 |
SC_NOT_ACCEPTABLE
|
| 407 |
SC_PROXY_AUTHENTICATION_REQUIRED
|
| 408 |
SC_REQUEST_TIMEOUT
|
| 409 |
SC_CONFLICT
|
| 410 |
SC_GONE
|
| 411 |
SC_LENGTH_REQUIRED
|
| 412 |
SC_PRECONDITION_FAILED
|
| 413 |
SC_REQUEST_ENTITY_TOO_LARGE
|
| 414 |
SC_REQUEST_URI_TOO_LONG
|
| 415 |
SC_UNSUPPORTED_MEDIA_TYPE
|
| 500 |
SC_INTERNAL_SERVER_ERROR
|
| 501 |
SC_NOT_IMPLEMENTED
|
| 502 |
SC_BAD_GATEWAY
|
| 503 |
SC_SERVICE_UNAVAILABLE
|
| 504 |
SC_GATEWAY_TIMEOUT
|
| 505 |
SC_HTTP_VERSION_NOT_SUPPORTED
|
5.4 流程图:Servlet请求处理流程
graph TD;
A[客户端请求] --> B[HttpServletRequest];
B --> C{请求类型};
C -- GET --> D[doGet方法];
C -- POST --> E[doPost方法];
D --> F[处理请求];
E --> F;
F --> G[生成响应];
G --> H[HttpServletResponse];
H --> I[发送响应到客户端];
6. PyServlet
Jython发行版包含
org.python.util.PyServlet
,它可以加载、执行和缓存Jython文件,无需中间编译步骤。使用
PyServlet
需要进行Servlet映射,将特定的URL模式(如
*.py
)与
PyServlet
关联。
6.1 PyServlet的限制
Jython文件必须包含一个继承自
javax.servlet.http.HttpServlet
的类,类名必须与文件名(不含
.py
扩展名)匹配。除了这个类,使用模块全局标识符是不安全的。
6.2 安装PyServlet
-
定义Servlet映射,在
web.xml文件中进行配置。示例如下:
<web-app>
<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>PyServlet</servlet-name>
<url-pattern>*.py</url-pattern>
</servlet-mapping>
</web-app>
-
确保
jython.jar文件在上下文的lib目录中。
6.3 测试PyServlet
# File ServletMappingTest.py
from javax.servlet.http import HttpServlet
class ServletMappingTest(HttpServlet):
def doGet(self, req, res):
out = res.writer
res.contentType = "text/html"
print >> out, "Greetings from a jylet."
将测试文件保存为
%TOMCAT_HOME%\webapps\jython\ServletMappingTest.py
,在浏览器中访问
http://localhost:8080/jython/ServletMappingTest.py
,如果看到问候消息,则
PyServlet
映射正确。
7. Cookies
Cookies允许在客户端机器上存储信息,以便在后续请求中包含。可以使用
javax.Servlet.http.Cookie
类创建和操作Cookies。
7.1 创建和发送Cookie示例
from javax.servlet import http
name = "book1"
value = "Lewis Carroll, Alice In Wonderland"
MyNewCookie = http.Cookie(name, value)
res.addCookie(MyNewCookie)
7.2 Cookie属性
每个Cookie实例可以使用get和set方法或Jython的自动bean属性设置以下属性:
-
comment
-
domain
-
maxAge
-
name
-
path
-
secure
-
value
-
version
7.3 Cookies示例
# File: cookies.py
from javax import servlet
from javax.servlet import http
class cookies(http.HttpServlet):
def doGet(self, req, res):
res.setContentType("text/html")
out = res.getOutputStream()
print >>out, "<html><head><title>Cookies with Jython</title></head>"
print >>out, """
<body>\n<H2>Cookie list:</H2>
Remember, cookies must be enabled in your browser.<br><br>"""
for c in req.cookies:
print >>out, """
<b>Cookie Name</b>= %s
<b>Value</b>= %s<br><br>""" % (c.name,c.value)
print >>out, """<br><br><br>
<HR><P>Use this form to add a new cookie</P>
<form action="cookies.py" method="POST">
<P>Name:<br><INPUT type="text" name="name" size="30"></P>
<P>Value:<br><INPUT type="text" name="value" size="30"></P>
<P>Use the MaxAge field to set the cookie's time-to-expire.
A value of "0" deletes the cookie immediately,, a value of
"-1" saves the cookie until the browser exits,, and
any other integer represents seconds until it expires
(i.e.- using "10" would expire 10 seconds after being set)).</P>
<P>MaxAge:<br><INPUT type="text" name="maxAge" size="30"></P>
<INPUT type="submit" name="button" value="submit">
\n</body>
\n</html>
"""
def doPost(self, req, res):
res.setContentType("text/html");
out = res.getWriter()
name = req.getParameterValues("name")[0]
value = req.getParameterValues("value")[0]
maxAge = req.getParameterValues("maxAge")[0]
if name:
newCookie = http.Cookie(name, value)
newCookie.maxAge = int(maxAge or -1)
newCookie.comment = "Jython test cookie"
res.addCookie(newCookie)
print >>out, """
<html><body>Cookie set successfully\n\n
<P>click <a href="cookies.py">here</a>
to view the new cookie.</P>
<P>If cookies are enabled in your
browser that is.</P>
\n</body>
\n</html>"""
else:
print >>out, """
<html>\n<body>
Cookie not set
<P>No cookie "Name" provided<</P>
<P>click <a href="cookies">here</a>
to try again</P>
\n</body>
/n</html>"""
测试该示例,确保浏览器允许使用Cookies,访问
http://localhost:8080/jython/cookies.py
,添加Cookie并验证。
8. Sessions
Cookies是创建客户端会话的常见方式,但
Java HttpSession
类使会话跟踪更加容易。
8.1 创建会话示例
# File: session.py
from javax import servlet
from javax.servlet import http
class session(http.HttpServlet, servlet.RequestDispatcher):
def doGet(self, req, res):
sess = req.session
res.contentType = "text/html"
out = res.getWriter()
name = req.getParameterValues("name")
value = req.getParameterValues("value")
if name and value:
sess.putValue(name[0], value[0])
print >>out, ("""
<html>
<body>
<H3>Session Test</H3>
Created at %s<br>
Last Accessed = %s<br>
<u>Values:</u>""" %
(sess.creationTime, sess.maxInactiveInterval)
)
print >>out, "<ul>"
for key in sess.getValueNames():
print >>out, "<li>%s: %s</li>" % (key, sess.getValue(key))
print >>out, "</ul>"
print >>out, """
<HR><P>Use this form to add a new values to the session</P>
<form action="session.py" method="GET">
<P>Name:<br><INPUT type="text" name="name" size="30"></P>
<P>Value:<br><INPUT type="text" name="value" size="30"></P>
<INPUT type="submit" name="button" value="submit">
</body>
</html>
"""
将该文件保存到
%TOMCAT_HOME%\webapps\jython
目录,访问
http://localhost:8080/jython/session.py
,添加变量到会话并测试。
8.2 流程图:会话管理流程
graph TD;
A[客户端请求] --> B[检查会话ID];
B -- 存在 --> C[获取现有会话];
B -- 不存在 --> D[创建新会话];
C --> E[处理请求];
D --> E;
E --> F[更新会话数据];
F --> G[生成响应];
G --> H[发送响应到客户端];
9. 数据库和Servlet
在Jylet中连接数据库、执行语句和遍历结果集与其他Jython数据库应用类似,但管理数据库连接和资源是一个主要问题。
9.1 数据库资源管理方法
-
每个Jylet一个连接
:在Jylet的
init方法中建立数据库连接,在Jylet卸载时关闭连接。这种方法消耗资源较多,仅在连接数量在资源限制范围内时适用。 - 连接池 :维护一定数量的活动数据库连接,Jylet在响应客户端请求时借用连接,完成后归还。这是一种更谨慎的资源管理方法。
9.2 示例:Jython Servlet与数据库连接
# file: DBDisplay.py
from javax.servlet import http
from com.ziclix.python.sql import zxJDBC
class DBDisplay(http.HttpServlet):
def init(self, cnfg):
url = "jdbc:mysql://192.168.1.77/products"
usr = "productsUser"
passwd = "secret"
driver = "org.gjt.mm.mysql.Driver"
self.db = zxJDBC.connect(url, usr, passwd, driver)
self.c = self.db.cursor()
def doGet(self, req, res):
res.setContentType("text/html")
out = res.getWriter()
print >>out, """
<html>
<head>
<title>Jylet Database Connection</title>
</head>
<body>
<table align="center">
<tr>
<td><b>ID</b></td>
<td><b>Title</b></td>
<td><b>Description</b></td>
<td><b>Price</b></td>
</tr>"""
self.c.execute("select code, name, description, price from products")
for row in self.c.fetchall():
print >>out, """
<tr>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td>%s</td>""" % row
print >>out, """
</table>
</body>
</html>"""
def destroy(self):
self.c.close()
self.db.close()
创建数据库和表的SQL语句如下:
create database products;
CREATE TABLE products (
primarykey int(11) NOT NULL auto_increment,
code varchar(55) default NULL,
name varchar(255) default NULL,
description text,
price float(5,2) default NULL,
PRIMARY KEY (primarykey)
) TYPE=MyISAM;
将
DBDisplay.py
文件放在上下文的根目录,访问
http://localhost:8080/jython/DBDisplay.py
查看数据库数据。
10. JSP
Java Server Pages(JSP)是Sun推荐的与Servlet互补的模板系统。目前Tomcat仅在JSP中实现Java语言,使用Jython与JSP有以下几种方式:
10.1 jythonc编译的类与JSP
-
创建与Java兼容的Jython类,类名与模块名相同,继承自Java类,并为每个非从超类派生的方法包含
@sig字符串。 -
将
jythonc生成的类文件放在上下文的classes目录中,JSP页面可以像使用任何本地Java类一样使用这些类。 -
JSP文件可以通过两种方式使用
jythonc编译的类:- 作为脚本片段 :可以使用任何类。
-
作为Bean
:Jython类必须符合Bean约定,为每个读写属性包含
getProperty和setProperty方法。
示例:
<%@ page import="fully.qualified.path.to.class" %>
<html>
<body>
<% ClassName obj = new ClassName(); %>
<%= obj.method() %>
</body>
</html>
10.2 嵌入PythonInterpreter在JSP中
<%@ page contentType="text/html" %>
<%@ page import="org.python.util.PythonInterpreter" %>
<% PythonInterpreter interp = new PythonInterpreter();
interp.set("out, out); %>
<html>
<body bgcolor="white">
<% interp.exec("out.printIn('Hello from JSP and the Jython interpreter.')"); %>
</body>
</html>
将
interp.jsp
文件放在上下文的根目录,访问
http://localhost:8080/jython/interp.jsp
查看消息。
10.3 Jython标签库
可以使用
jythonc
将Jython标签库模块编译成Java类,创建自定义标签库。
10.3.1 创建标签库示例
# file: JythonTag.py
from javax.servlet.jsp import tagext
class JythonTag(tagext.Tag):
def __init__(self):
self.context = None
self.paren = None
def doStartTag(self):
return tagext.Tag.SKIP_BODY
def doEndTag(self):
out = self.context.out
print >>out, "Message from a taglib"
return tagext.Tag.EVAL_PAGE
def release(self):
pass
def setPageContext(self, context):
self.context = context
def setParent(self, parent):
self.paren = parent
def getParent(self):
return self.paren
10.3.2 编译标签库
jythonc -w %TOMCAT_HOME%\webapps\jython\WEB-INF\classes JythonTag.py
10.3.3 创建标签库描述文件
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE taglib
PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
"http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<taglib>
<tlibversion>1.0</tlibversion>
<jspversion>1.1</jspversion>
<shortname>JythonTag</shortname>
<info>A simple Jython tag library</info>
<tag>
<name>message</name>
<tagclass>JythonTag</tagclass>
</tag>
</taglib>
将描述文件保存为
%TOMCAT_HOME%\webapps\jython\WEB - XML\jython - taglibs.tld
。
10.3.4 在JSP中使用标签库
<%@ taglib uri="/WEB-INF/jython-taglibs.tld" prefix="jython" %>
<html>
<body>
<jython:message />
</body>
</html>
将
test.jsp
文件放在上下文的根目录,访问
http://localhost:8080/jython/test.jsp
查看自定义标签消息。
10.4 BSF
IBM的Bean Scripting Framework(BSF)支持Jython,结合BSF标签库可以在JSP文件中直接插入Jython脚本片段和表达式。
10.4.1 安装BSF相关文件
-
下载
bsf.jar文件,放在上下文的lib目录中。 -
下载BSF标签库和
bsf.tld文件,分别放在上下文的lib目录和WEB - INF目录中。
10.4.2 在JSP中使用BSF脚本片段
<%@ taglib uri="/WEB-INF/bsf.tld" prefix="bsf" %>
<html>
<body>
<bsf:scriptlet language="jython">
import random
print >> out, random.randint(1, 100)
</bsf:scriptlet>
</body>
</html>
将
scriptlets.jsp
文件放在上下文的根目录,访问
http://localhost:8080/jython/scriptlets.jsp
查看结果。
通过以上内容,我们详细介绍了Jython在Web开发中与Servlet和JSP的结合应用,包括容器选择、Servlet编写、数据库连接和JSP使用等方面,希望能帮助你更好地利用Jython进行Web开发。
11. 总结与最佳实践
在使用 Jython 进行 Web 开发时,有一些总结和最佳实践可以帮助我们更高效地完成项目。
11.1 容器选择
- Tomcat :作为参考实现,稳定性和兼容性较好,适合大多数开发场景。尤其对于初学者和小型项目,其易于安装和配置的特点使其成为首选。
- Jetty :如果项目对性能和资源占用有较高要求,Jetty 的紧凑和高效特性会是一个不错的选择。它还能轻松与 EJB 服务器集成,适用于企业级应用。
11.2 Servlet 编写
-
继承选择
:如果开发的应用主要基于 HTTP 协议,优先选择
HttpServlet,它为 HTTP 方法提供了专门的处理方法,如doGet和doPost,使代码更具可读性和可维护性。 -
资源管理
:在
init方法中初始化资源,在destroy方法中释放资源,确保资源的正确使用和释放,避免资源泄漏。
11.3 数据库连接
- 连接池 :对于高并发的 Web 应用,使用连接池是管理数据库资源的最佳实践。它可以减少连接开销,提高性能和资源利用率。
- 异常处理 :在数据库操作中,要进行充分的异常处理,确保应用在遇到数据库错误时能够稳定运行。
11.4 JSP 使用
-
避免脚本片段
:脚本片段会使 JSP 页面变得复杂,建议使用
jythonc编译的 Bean 或自定义标签库来实现动态内容,提高代码的可维护性和可测试性。
12. 常见问题与解决方案
在使用 Jython 进行 Web 开发过程中,可能会遇到一些常见问题,以下是一些解决方案。
12.1 编译问题
-
ClassCastException
:如果在编译 Jython Servlet 时出现
ClassCastException,可能是因为servlet.jar文件不在类路径中,或者文件名和类名不一致(包括大小写)。检查类路径和文件名、类名的一致性。 -
AttributeError
:如果编译生成的类文件不在上下文的
classes目录中,可能会出现AttributeError。确保类文件正确放置在指定目录中。
12.2 资源访问问题
-
ImportError
:如果 Jython 的模块不可用,会出现
ImportError。可以通过设置python.home属性、冻结所需模块或让每个 Servlet 显式地将模块位置添加到sys.path来解决。 -
Cookie 和 Session 问题
:如果客户端禁用了 Cookie,会话管理可能会出现问题。可以使用
res.encodeUrl()方法对 URL 进行重写,支持无 Cookie 会话。
12.3 性能问题
- 连接开销 :如果每个请求都创建和关闭数据库连接,会导致连接开销过大。可以使用连接池来减少连接开销,提高性能。
- 脚本片段 :过多使用脚本片段会影响 JSP 页面的性能和可维护性。尽量使用 Bean 或自定义标签库来实现动态内容。
13. 未来发展趋势
随着 Web 开发技术的不断发展,Jython 在 Web 开发中的应用也可能会有一些新的发展趋势。
13.1 与新兴技术的融合
- 微服务 :Jython 可以与微服务架构相结合,开发独立的微服务。通过容器化技术,如 Docker 和 Kubernetes,可以实现微服务的快速部署和管理。
- 人工智能和机器学习 :Jython 可以与 Python 的人工智能和机器学习库相结合,在 Web 应用中实现智能功能,如智能推荐、图像识别等。
13.2 性能优化
- Jython 编译器的改进 :未来 Jython 编译器可能会进行性能优化,提高编译速度和生成代码的执行效率。
- 异步编程 :引入异步编程模型,提高 Web 应用的并发处理能力,减少响应时间。
13.3 社区支持
- 开源项目 :随着 Jython 在 Web 开发中的应用越来越广泛,可能会有更多的开源项目出现,为开发者提供更多的工具和资源。
- 文档和教程 :社区可能会提供更多的文档和教程,帮助开发者更好地使用 Jython 进行 Web 开发。
14. 案例分析
为了更好地理解 Jython 在 Web 开发中的应用,以下是一个简单的案例分析。
14.1 项目背景
某小型电商网站需要开发一个商品展示和管理系统,要求能够快速开发,并且具有一定的灵活性。
14.2 技术选型
- 服务器端 :选择 Jython 作为服务器端开发语言,结合 Tomcat 作为 Servlet 容器。
- 数据库 :使用 MySQL 数据库,通过 zxJDBC 进行数据库连接。
- 前端 :使用 HTML、CSS 和 JavaScript 实现页面的展示和交互。
14.3 实现步骤
- 创建 Servlet :使用 Jython 编写 Servlet 来处理商品的展示和管理请求。
-
数据库连接
:在 Servlet 的
init方法中建立数据库连接,在destroy方法中关闭连接。 - JSP 页面 :使用 JSP 页面作为模板,展示商品信息和管理界面。
- 测试和部署 :对系统进行测试,确保系统的稳定性和正确性,然后部署到生产环境中。
14.4 项目成果
通过使用 Jython 进行开发,项目在短时间内完成了开发和部署,并且具有良好的灵活性和可维护性。系统能够稳定运行,满足了电商网站的需求。
15. 对比分析
将 Jython 与其他 Web 开发技术进行对比分析,可以帮助我们更好地了解 Jython 的优势和劣势。
15.1 与 Java 对比
- 开发效率 :Jython 的语法更加简洁,开发效率更高。它可以减少代码量,提高开发速度。
- 灵活性 :Jython 具有更高的灵活性,支持动态类型和脚本编程,适合快速迭代的开发项目。
- 性能 :Java 在性能方面通常优于 Jython,尤其是在处理大规模数据和高并发请求时。
15.2 与 Python 对比
- 与 Java 生态系统的集成 :Jython 可以无缝集成 Java 生态系统,使用 Java 的类库和框架,这是 Python 所不具备的优势。
- Web 开发框架 :Python 有许多成熟的 Web 开发框架,如 Django 和 Flask,而 Jython 在 Web 开发框架方面相对较少。
16. 学习资源推荐
如果你想深入学习 Jython 在 Web 开发中的应用,以下是一些学习资源推荐。
16.1 官方文档
- Jython 官方文档 :提供了 Jython 的详细文档和教程,是学习 Jython 的重要资源。
- Servlet 和 JSP 官方文档 :了解 Servlet 和 JSP 的规范和使用方法,对于使用 Jython 进行 Web 开发非常有帮助。
16.2 在线教程
- W3Schools :提供了丰富的 Web 开发教程,包括 Servlet 和 JSP 的教程。
- Codecademy :提供了交互式的编程学习平台,可以帮助你快速掌握 Jython 和 Web 开发技术。
16.3 书籍
- 《Effective Jython》:深入介绍了 Jython 的使用技巧和最佳实践。
- 《Servlet & JSP: A Tutorial》:详细讲解了 Servlet 和 JSP 的原理和使用方法。
17. 总结
Jython 在 Web 开发中具有独特的优势,它结合了 Python 的简洁性和 Java 的强大生态系统。通过本文的介绍,我们了解了 Jython 在 Web 开发中的应用场景、技术细节和最佳实践。希望这些内容能够帮助你更好地利用 Jython 进行 Web 开发,开发出高效、灵活的 Web 应用。
18. 流程图:Jython Web 开发整体流程
graph TD;
A[需求分析] --> B[技术选型];
B -- Jython、Servlet、JSP --> C[环境搭建];
C -- 安装 Tomcat、配置 Jython --> D[Servlet 开发];
D -- 编写 Java 或 Jython Servlet --> E[数据库连接];
E -- 选择连接方式 --> F[JSP 开发];
F -- 使用 jythonc 编译类或自定义标签库 --> G[测试];
G -- 功能测试、性能测试 --> H[部署];
H -- 部署到生产环境 --> I[维护和优化];
19. 表格:Jython Web 开发技术对比
| 技术 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| Jython Servlet | 开发效率高、灵活性好 | 性能相对较低 | 快速迭代的小型项目 |
| Java Servlet | 性能高、稳定性好 | 开发效率低、代码量大 | 高并发的企业级应用 |
| Python Web 框架 | 丰富的框架和工具 | 与 Java 生态系统集成困难 | 纯 Python 开发的 Web 应用 |
通过以上内容,我们全面介绍了 Jython 在 Web 开发中的应用,从基础概念到实际应用,再到常见问题和未来发展趋势。希望这篇博客能够帮助你更好地理解和应用 Jython 进行 Web 开发。
超级会员免费看
26

被折叠的 条评论
为什么被折叠?



