对于maven多模块的spring web项目,本地开发时,启动的方式一般有如下几种:
-
使用容器(
tomcat
/
jetty
/
resin
等),该方式需要ide支持,而社区版的idea并不支持; -
maven插件(
jetty
/
tomcat
),该方式只需在web模块的
pom文件
中加入插件依赖,然后运行
mvn jetty:run
或
mvn tomcat7:run
即可,不过对于多模块项目而言,代码时改动需要使用
maven
进行构建,而
maven
构建需耗时良久; -
jetty
的
main()
方法启动,该方式启动时,并不需要使用maven进行构建,代码改动时仅需重新编译改动的源文件,且社区版的idea支持良好,本地开发时,是个不错的选择。
1. maven引入包
<!-- jetty相关依赖包,注意scope为test-->
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-webapp</artifactId>
<version>9.3.2.v20150730</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-annotations</artifactId>
<version>9.3.2.v20150730</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>apache-jsp</artifactId>
<version>9.3.2.v20150730</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>apache-jstl</artifactId>
<version>9.3.2.v20150730</version>
<scope>test</scope>
</dependency>
2. 编写启动类
由于引入包时,
scope
为
test
,因此该类需位于
src/test/java
下。
import org.eclipse.jetty.jsp.JettyJspServlet;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.webapp.WebAppContext;
import java.io.File;
public class JettyStart {
public static void main(String[] args) throws Exception {
//添加你的模块名,对于maven多模块项目,需要指定
String moduleName = "module";
String dir = System.getProperty("user.dir");
if (!dir.contains(moduleName)) {
dir = dir + File.separator + moduleName;
System.setProperty("user.dir", dir);
}
int port = 8081;
String contextPath = "/";
WebAppContext webContext = new WebAppContext("src/main/webapp", contextPath);
webContext.setClassLoader(Thread.currentThread().getContextClassLoader());
//处理jsp解析问题
webContext.addBean(new JspStarter(webContext));
webContext.addServlet(JettyJspServlet.class, "*.jsp");
//处理静态资源热加载问题
webContext.setDefaultsDescriptor("src/test/resources/webdefault.xml");
Server server = new Server(port);
server.setHandler(webContext);
server.setStopAtShutdown(true);
server.start();
server.join();
}
}
3. 解决jsp处理异常
如果项目中有jsp页面,访问时,可能会出现以下异常:
org.apache.jasper.JasperException: Unable to compile class for JSP
at org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:600)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:363)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:396)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:340)
at org.eclipse.jetty.jsp.JettyJspServlet.service(JettyJspServlet.java:107)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:816)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:583)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:566)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:226)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1114)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:511)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1048)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
at org.eclipse.jetty.server.Dispatcher.forward(Dispatcher.java:199)
at org.eclipse.jetty.server.Dispatcher.forward(Dispatcher.java:74)
at org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:168)
at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:303)
at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1246)
at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1029)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:973)
......
解决该异常的方法是,在
JettyStart.java
的同一包下,加入以下类:
import org.apache.tomcat.util.scan.StandardJarScanner;
import org.eclipse.jetty.apache.jsp.JettyJasperInitializer;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
public class JspStarter extends AbstractLifeCycle implements ServletContextHandler.ServletContainerInitializerCaller {
JettyJasperInitializer sci;
ServletContextHandler context;
public JspStarter(ServletContextHandler context) {
this.sci = new JettyJasperInitializer();
this.context = context;
this.context.setAttribute("org.apache.tomcat.JarScanner", new StandardJarScanner());
}
@Override
protected void doStart() throws Exception {
ClassLoader old = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(context.getClassLoader());
try {
sci.onStartup(null, context.getServletContext());
super.doStart();
} finally {
Thread.currentThread().setContextClassLoader(old);
}
}
}
4.解决jstl异常
项目的
jsp
页面中使用了
jstl
标签,还是会报错:
org.apache.jasper.JasperException: The absolute uri: http://java.sun.com/jsp/jstl/core cannot be resolved in either web.xml or the jar files deployed with this application
at org.apache.jasper.compiler.DefaultErrorHandler.jspError(DefaultErrorHandler.java:55)
at org.apache.jasper.compiler.ErrorDispatcher.dispatch(ErrorDispatcher.java:277)
at org.apache.jasper.compiler.ErrorDispatcher.jspError(ErrorDispatcher.java:75)
at org.apache.jasper.compiler.TagLibraryInfoImpl.generateTldResourcePath(TagLibraryInfoImpl.java:243)
at org.apache.jasper.compiler.TagLibraryInfoImpl.<init>(TagLibraryInfoImpl.java:124)
at org.apache.jasper.compiler.Parser.parseTaglibDirective(Parser.java:411)
at org.apache.jasper.compiler.Parser.parseDirective(Parser.java:469)
at org.apache.jasper.compiler.Parser.parseElements(Parser.java:1430)
at org.apache.jasper.compiler.Parser.parse(Parser.java:139)
at org.apache.jasper.compiler.ParserController.doParse(ParserController.java:227)
at org.apache.jasper.compiler.ParserController.parse(ParserController.java:100)
at org.apache.jasper.compiler.Compiler.generateJava(Compiler.java:199)
at org.apache.jasper.compiler.Compiler.compile(Compiler.java:356)
at org.apache.jasper.compiler.Compiler.compile(Compiler.java:336)
at org.apache.jasper.compiler.Compiler.compile(Compiler.java:323)
at org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:585)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:363)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:396)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:340)
at org.eclipse.jetty.jsp.JettyJspServlet.service(JettyJspServlet.java:107)
这时,需要找到
jstl
实现包,这里使用的是
glassfish
实现,在
maven
仓库路径为
C:\Users\Administrator\.m2\repository\org\glassfish\web\jstl-impl\1.2
,在该路径下找到
jstl-impl-1.2.jar
,用解压工具解压,在
META-INF
目录下找到以下几个文件:
复制到项目的
WEB-INF/jstl-tld
目录下(
jstl-tld
需要手动创建):
5.处理静态文件不能热加载问题
经过以上步骤后,项目能正常启动,也能正常访问了,但有一点特别坑:静态文件(
html
/
js
/
css
等)不能热加载,每次修改后要重启才能看到效果,大大地降低了开发效率,解决办法如下:
-
找到
jetty-webapp-{version}.jar
包 -
在
org/eclipse/jetty/webapp/
路径下找到
webdefault.xml
,复制一份放到
src/test/resources/
-
在
src/test/resources/webdefault.xml
中找到
<init-param>
<param-name>useFileMappedBuffer</param-name>
<param-value>true</param-value> <!-- 将值修改为false -->
</init-param>
将
param-value
值修改为true即可。
重启项目,接下来修改
html
/
js
/
css
等,只要刷新浏览器就能看到效果了。
最后,附上本人的代码结构:
转载于:https://my.oschina.net/funcy/blog/3039139