java – 没有HTTP的Tomcat JSP / JSTL

我有一个在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.

上一篇:在JSTL / JSP中,给定一个java.util.Date,如何找到第二天?


下一篇:java-关于tomcat TLD扫描的ClassNotFoundException oracle.i18n.util.LocaleMapper. ojdbc7 maven dep(xmlparser