我有一个在Tomcat 7下运行的非常标准的Web应用程序.
我现在要做的是利用JSP / JSTL作为独立于Tomcat的HTTP / Web服务方面的模板语言来生成可以通过电子邮件发送并转换为PDF的HTML.
有没有其他人试图这样做,可以帮助我一些指示?
提前致谢.
解决方法:
与Stephen C所说的相反,是的,JSP是Servlets等等(并且Velocity非常好且易于使用)
但是,什么是Servlet?
这是一个界面.一个主要方法的接口:
service(ServletRequest req, ServletResponse res)
找到JSP类,将其转换为Servlet,创建ServletRequest和ServletResponse的实现,然后……
String jspClassName = findJspClassForJSP("your.jsp");
Class jspClass = Class.forName(jspClassName);
Servlet jspServlet = (Servlet)jspClass.newInstance();
MyServletRequest req = new MyServletRequest();
MyServletResponse resp = new MyServletResponse();
jspServlet.init();
jspServlet.service(req, resp);
jspServlet.destroy();
String results = reps.getContent();
这会有用吗?好吧,经过一些工作,它会.显然,您需要实现ServletRequest / Response的最小外观以及您需要的JSP.但是,您可能只需要属性和流量.如果你让你的Response返回一个StringWriter,你就到了一半.
下一部分是从JSP创建servlet.很方便,Jasper编译器为您做到了 – 游戏正在调用它.我从来没有直接完成它,但显然可以完成,因为servlet容器都可以完成它,以及JSPC脚本/ bat文件,ant任务,以及大多数使用Jasper的Servlet容器.所以,那可以做到.一旦你知道如何调用它,你就会知道JSP的最终生成的类名. (参见样本的第一行.)
我做过这个吗?不.但我打赌在不到一天的时间里,你会知道这是否可行.我敢打赌,特别是如果你没有参加任何类加载器恶作剧.如果让用户更改并重新生成JSP,那么您可能会遇到问题(因此MyEmail.jsp会被编译到MyEmail.class,MyEmail_2.class等).但是如果你自己调用Jasper,你可能会对此有更多的控制权.
另一个难点是确定JSP的类名.大多数容器都遵循这里的基本模式,因此如果您在WAR生成的代码中找到它,您可能会发现它.
保持JSP相当简单(并且电子邮件模板不需要超级复杂的嵌入式Java或任何随机调用),它更有可能工作.
您的解决方案可能无法从Tomcat开箱即用,但您可能不会关心.我与之交谈的人使用JSP作为模板,只需打开一个套接字到他们自己的服务器并提出请求.他们也没走这么远.
但从表面上看,保存一些糟糕的类装载机黑洞地狱,我打赌你可以很快地使用它.尽可能少地执行请求和响应,打几个NPE作为JSP和JSTL调用你没有计划的东西,并且正如圣诞老人所说,
Hack away, Hack away, Hack away all!
附加物:
所以,对于所有的反对者……
public void runJsp() {
JspC jspc = new JspC();
jspc.setUriroot("/tmp/app");
jspc.setOutputDir("/tmp/dest");
jspc.setJspFiles("newjsp.jsp");
jspc.setCompile(true);
try {
jspc.execute();
Class cls = Class.forName("org.apache.jsp.newjsp_jsp");
Servlet s = (Servlet) cls.newInstance();
MyRequest req = new MyRequest();
MyResponse resp = new MyResponse();
s.init(getServletConfig());
s.service(req, resp);
s.destroy();
System.out.println(resp.getSw().toString());
} catch (JasperException ex) {
throw new RuntimeException(ex);
} catch (ClassNotFoundException ex) {
throw new RuntimeException(ex);
} catch (InstantiationException ex) {
throw new RuntimeException(ex);
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
} catch (ServletException ex) {
throw new RuntimeException(ex);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
令人惊讶的是,调试器中的源代码和1/2小时将为您做什么.
我在/tmp/app/newjsp.jsp中创建了一个简单的JSP.
jspc.setUriroot告诉编译器“web app”的基础所在的位置. jspc.setOutputDir告诉jspc将生成的Java和Class文件放在何处. jspc.setJspFiles根据URI Root告诉jspc要编译哪些文件. jspc.setCompile告诉它实际编译代码.最后,jspc.execute()执行契约.
默认情况下,Jasper使用包org.apache.jsp,并根据JSP文件名创建一个新类.对于我的简单实验,我只需将“/ tmp / dest”放到我的Glassfish容器的类路径上,这样容器就可以找到生成的类.
我加载类,并获得一个实例.
最后,我创建了MyRequest,MyRequest,最终创建了MySession.我的IDE方便地为各个接口创建了存根.在这种情况下,我实现了:MyRequest.getSession(),MyResponse.setContentType(),MyResponse.setBufferSize()和MyResponse.getWriter().
public PrintWriter getWriter() throws IOException {
if (sw == null) {
sw = new StringWriter();
pw = new PrintWriter(sw);
}
return pw;
}
显然,sw和pw是MyResponse的实例变量.
MyRequest返回了MySession的一个实例.我对MySession的实现确实没有.但是运行时需要一个Session,它本身并不是为了我的非常简单的JSP而单独使用它,而且我没有动机从Servlet中填充它.
我在Glassfish v2.1上测试了这个.我只是将appserv_rt.jar(来自glassfish / lib)添加到我的构建类路径(因此它可以找到JspC jar),但我没有将它捆绑在WAR中(因为它已经在容器中).
而且,shazam,它的工作原理.在“现实生活”中,假设想要利用JSP的进程实际上来自Web请求,我只需创建一个HttpServletResponseWrapper并覆盖之前的三种方法,其余的可能就是Just Work.如果Web请求根本不在图片中,那么您需要创建自己的Session实现(真的没什么大不了的,它只是一张地图).
我还使用私有URLClassLoader来加载虚假的JSP类.如果我知道我永远不会重新加载JSP,那么只需将目标作为我的WEB-INF / classes目录并给它自己的包并让系统加载它们.
但是,是的,它有效.没什么大不了.这只是java.