SpringBoot多模块项目在IDEA下运行调试

一个SpringBoot多模块项目的工程目录如下:

myProject
--api
--ops
--share

现在要在IDEA中调试运行ops模块,程序启动后,所有页面无法访问,提示:

WARN  |-o.e.j.server.handler.ErrorHandler:106  - Error page loop /WEB-INF/jsp/common/404.jsp

这里提示错误页面循环,是因为程序找不到要渲染的jsp页面时,设置了跳转到404页面,结果404页面也找不到了,就出现了错误循环。Jetty查找JSP的文件路径为:

//WebAppContext.getResource(String path):
_baseResource + jsp.prefix + jsp.fileName + jsp.suffix
其中_baseResource 的路径查找步骤为:
//DocumentRoot.getValidDirectory()
getWarFileDocumentRoot();
getExplodedWarFileDocumentRoot();
getCommonDocumentRoot();//判断当前运行目录下是否存在src/main/webapp | public | static 这3个目录中的一个,如果存在,则将当前目录设置为_baseResource
如果根据上面的规则都找不到合适的DocumentRoot,则会使用创建一个运行时的临时目录,项目的JSP文件在临时目录里面肯定是找不到的,所以就不能正常显示了。

解决方案:
在IDEA的Run/Debug Configurations中,将Working directory设置为要运行的模块目录绝对路径,例如/opt/myProject/ops。

找不到JSP的问题算是解决了,如果项目中有用到freemarker和taglib,还会面临一个问题,

Caused by: freemarker.template.TemplateModelException: Error while loading tag library for URI “/my-taglib” from TLD location “servletContext:/my-taglib”; see cause exception.

freemarker查找taglib时,默认使用TaglibFactory.DEFAULT_META_INF_TLD_SOURCES  = Collections.singletonList(WebInfPerLibJarMetaInfTldSource.INSTANCE)
查找tld文件的路径为:sevletContext:/WEB-INF/lib/*.{jar,zip}/META-INF/**/*.tld
在IDEA下直接run SpringBoot,相关的依赖包并不会拷贝到/WEB-INF/lib/下面去,所以就查找不到这些jar包里面的tld文件了,需要让freemarker去classpath中的所有jar包里面去查找,解决方案:

public class IdeFreeMarkerConfigurer extends FreeMarkerConfigurer {

    @Override
    public void afterPropertiesSet() throws IOException, TemplateException {
        super.afterPropertiesSet();          

        super.getTaglibFactory().setMetaInfTldSources(Lists.newArrayList(
                TaglibFactory.WebInfPerLibJarMetaInfTldSource.INSTANCE,
                new TaglibFactory.ClasspathMetaInfTldSource(Pattern.compile(".*\\.jar$", Pattern.DOTALL))));
    }
}

在XML或者Java代码中,配置使用这个FreeMarkerConfigurer 就可以了