用dropwizard创建嵌入式webapp并支持JSP及struts2。
dropwizard启动时默认提供了一个基于jetty的HTTP Server,得益于jetty良好的模块化设计以及dropwizard插件式的架构,我们很容易在dropwizard创建jetty HTTP Server时为其配置WebApp支持。
通过定制ServerFactory来替换dropwizard默认创建Server流程。 dropwizard通过application.yml配置中的server节点来定义创建的Server参数,默认支持的Server类型有:[simple, default]。
如下配置将创建支持RESTful API的Servlet Container:
server:
type: simple
applicationContextPath: /application
adminContextPath: /admin
connector:
type: http
port: 8080
但默认创建的Servlet Conainer不能支持WebApp,这里扩展一个新的Server类型webapp来实现对WebApp的支持。
application.yml:
server:
type: webapp #webapp 为新扩展的类型标志
applicationContextPath: /application
adminContextPath: /admin
webAppContextPath: /webapp
connector:
type: http
port: 8080
在重写ServerFactory的build方法,为Jetty Server增加WebAppContext即可为Server增加Webapp支持。 WebAppServerFactory(可以根据SimpleServerFactory的源码进行改写):
@JsonTypeName("webapp")
public class WebAppServerFactory extends AbstractServerFactory {
@Override
public Server build(Environment environment) {
configure(environment);
...
final ThreadPool threadPool = createThreadPool(environment.metrics());
final Server server = buildServer(environment.lifecycle(), threadPool);
final Handler applicationHandler = createAppServlet(server, ...);
final Handler adminHandler = createAdminServlet(server, ...);
final Connector conn = connector.build(server, environment.metrics(),
environment.getName(),
null);
server.addConnector(conn);
final ContextRoutingHandler routingHandler = new ContextRoutingHandler(ImmutableMap.of(
applicationContextPath, applicationHandler,
adminContextPath, adminHandler,
webAppContextPath, createWebAppContext(server)
));
final Handler gzipHandler = buildGzipHandler(routingHandler);
server.setHandler(addStatsHandler(addRequestLog(server, gzipHandler, environment.getName())));
return server;
}
private Handler createWebAppContext(Server server){
WebAppContext context = new WebAppContext(new PathResource( new File("webapp")), webAppContextPath);
context.setDescriptor("webapp/WEB-INF/web.xml");
context.setServer(server);
return context;
}
}
jackson通过JsonTypeName注解可以实现反序列化时指定抽象类型具体实例化时的子类型。 但是,需要在将子类型注册到ObjectMapper中。
dropwizard启动前在bootstrap中初始化了系统中反序列化使用的ObjectMapper,通过重写Application.initialize函数可以往ObjectMapper对象新增
public class App extends Application<AppConfig>
{
...
@Override
public void initialize(Bootstrap<AppConfig> bootstrap) {
super.initialize(bootstrap);
bootstrap.getObjectMapper().registerSubtypes(WebAppServerFactory.class);
}
}
- 创建程序的工作目录:
conf/
application.yml
webapp
WEB-INF/
web.xml
index.html
index.jsp
target/
cn.tranq.dwebapp.jar
- 添加JSP引擎实现
启动程序,可以通过http://localhost:8080/webapp/index.html来访问页面,但是若访问jsp页面会提示:
HTTP ERROR 500:
JSP support not configured
即表明当前WebAppContext还不支持jsp,将jsp的引擎添加到classpath即可。 Jetty 9.2(含)用jetty-jsp(glassfish提供),之后用apache-jsp(apache提供)。例如:
<properties>
<jetty.version>9.4.18.v20190429</jetty.version>
</properties>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>apache-jsp</artifactId>
<version>${jetty.version}</version>
<scope>provided</scope>
</dependency>
为了支持JSTL标签解析,还需要apache-jstl库。
- 开启 Servlet Specification Annotations 默认WebAppContext中没有开启此功能,但支持JSP必须开启。 在WebAppContext配置的ClassList中增加AnnotationConfiguration(需要增加到JettyWebXmlConfiguration之前), 修订WebAppServerFactory的createWebAppContext:
private Handler createWebAppContext(Server server){
WebAppContext context = new WebAppContext(new PathResource( new File("webapp")), webAppContextPath);
context.setDescriptor("webapp/WEB-INF/web.xml");
context.setServer(server);
Configuration.ClassList classList = Configuration.ClassList.setServerDefault(server);
classList.addBefore(
"org.eclipse.jetty.webapp.JettyWebXmlConfiguration",
"org.eclipse.jetty.annotations.AnnotationConfiguration");
return context;
}
以上classlist需要确保classpath中添加了jetty-annotations:
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-annotations</artifactId>
<version>${jetty.version}</version>
</dependency>
注:否则访问jsp页面,还会出现:org.apache.jasper.JasperException: Unable to compile class for JSP错误。
- 在IntelliJ中运行程序