为什么80%的码农都做不了架构师?>>>
对于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 JSPat 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());}@Overrideprotected 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 applicationat 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
等,只要刷新浏览器就能看到效果了。
最后,附上本人的代码结构: