原来一直使用SSM 觉得也够用了,但是目前主流都是SpringBoot,于是计划着把自己的项目也来个升级,当中当然是各种坑不断。
花费两天时间,基础坑都趟了一遍。记录一下~
原项目:
SSM -> SpringBoot2.3 + Maven
jar包管理升级->Maven
旧项目依旧使用老的lib方式管理。但是为了利用Jenkins自动构建,简单升级为Maven导入本地jar的方式构建项目
1.Maven 导入本地lib(很多老项目升级时用的办法)lib置于${project.basedir}/src/main/webapp/WEB-INF/lib
<defaultGoal>compile</defaultGoal> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <skip>true</skip> <source>8</source> <target>8</target> <encoding>UTF-8</encoding> <compilerArgs> <verbose /> <!-- windows下使用分号(;)分隔,linux/mac下使用冒号(:)分隔 为了避免环境引起的问题,推荐使用${path.separator}--> <!-- <bootclasspath>${java.home}/lib/rt.jar:${java.home}/lib/jce.jar</bootclasspath>--> <!-- <etxdir>${project.basedir}/web/WEB-INF/lib</etxdir>--> <arg>-verbose</arg> <arg>-Xlint:unchecked</arg> <arg>-Xlint:deprecation</arg> <arg>-bootclasspath</arg> <arg>${java.home}/lib/rt.jar${path.separator}${java.home}/lib/jce.jar</arg> <arg>-extdirs</arg> <arg>${project.basedir}/src/main/webapp/WEB-INF/lib</arg> </compilerArgs> </configuration> </plugin> <plugins>
2.jar包升级为Maven依赖(这是一个大工程~)
1)利用IDEA提示,前提需要知道应该要导入哪个包,有些可能就是没有。
2)定位到类,然后去maven仓库自己搜索相关的包。
查看原来的项目,定位到具体jar,然后进行搜索
1.关于仓库无法搜索到jar的处理方案。
a.利用1当中的,建立lib文件夹,并引入。
b.利用maven中的scope为system的jar,进行本地引入。缺点如果是打成war包可能会有些问题
<dependency> <groupId>com.baidu.ueditor</groupId> <artifactId>ueditor</artifactId> <version>1.1.2</version> <scope>system</scope> <systemPath>${project.basedir}/lib/ueditor-1.1.2.jar</systemPath> </dependency>
c.自己建立一个maven仓库。
SpringBoot
1.搭建脚手架
写博客居然遇上官网挂掉~
官方提供的搭建工具非常棒,可以满足绝大部分需求。
按需填写,以及引入相关依赖,下载即可
2.Mybatis迁移
迁移到springBoot只需要几个配置项即可
#配置扫描实体类 mybatis.type-aliases-package=com.ls.entity,com.ls.domain #配置原来的配置文件 mybatis.config-location=classpath:sqlMapConfig.xml #配置xml位置 mybatis.mapper-locations=classpath:mapper/*.xml #数据库四要素 spring.datasource.url=xxx spring.datasource.username=xxx spring.datasource.password=xxx spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
配置文件主要是配置了plugin
<plugins> <!--分页过滤器--> <plugin interceptor="com.github.pagehelper.PageInterceptor"/> <!--自定义sql过滤器--> <plugin interceptor="com.ls.interceptors.MybatisInterceptors"/> </plugins>
如果顺便升级了mybatis的版本,可能会遇到以下问题:
StatementHandler 出现异常,原因是作者修改了参数,导致拦截器配置出现问题。
@Intercepts({ // 之前 @Signature(method = "prepare", type = StatementHandler.class, args = {Connection.class}) @Signature(method = "prepare", type = StatementHandler.class, args = {Connection.class,Integer.class})})
3.FreeMarker迁移
FreeMarker Only
抛弃原来的配置文件,都走向了参数化
## 是否允许HttpServletRequest属性覆盖(隐藏)控制器生成的同名模型属性。 #spring.freemarker.allow-request-override=true ## 是否允许HttpSession属性覆盖(隐藏)控制器生成的同名模型属性。 #spring.freemarker.allow-session-override=true ## 是否启用模板缓存。 #spring.freemarker.cache=false ## 模板编码。 #spring.freemarker.charset=UTF-8 ## 是否检查模板位置是否存在。 #spring.freemarker.check-template-location=true ## Content-Type value. #spring.freemarker.content-type=text/html ## 是否启用freemarker #spring.freemarker.enabled=true ## 设定所有request的属性在merge到模板的时候,是否要都添加到model中. #spring.freemarker.expose-request-attributes=true ## 是否在merge模板的时候,将HttpSession属性都添加到model中 #spring.freemarker.expose-session-attributes=true ## 设定是否以springMacroRequestContext的形式暴露RequestContext给Spring’s macro library使用 #spring.freemarker.expose-spring-macro-helpers=false ## 是否优先从文件系统加载template,以支持热加载,默认为true #spring.freemarker.prefer-file-system-access=true ## 设定模板的后缀. #spring.freemarker.suffix=.ftl ## 设定模板的加载路径,多个以逗号分隔,默认: #spring.freemarker.template-loader-path=classpath:/templates/ftl/ ## 设定FreeMarker keys. #spring.freemarker.settings.template_update_delay=0 #spring.freemarker.settings.default_encoding=UTF-8 #spring.freemarker.settings.classic_compatible=true #spring.freemarker.request-context-attribute=request
依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency>
JSP Only
因为一些特殊原因、我需要引入JSP
如果不引入模板,只引入JSP可以这么配置
#配置jsp相关解析功能 spring.mvc.view.prefix =classpath:/templates/jsp/ spring.mvc.view.suffix =.jsp
这些依赖必不可少,否则无法解析jsp
<!-- jstl依赖 (jsp) --> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> </dependency> <!-- jasper依赖 (jsp) --> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> <scope>provided</scope> </dependency> <!-- --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </dependency>
JSP + FreeMarker
我需要同时解析JSP与FTL
依据官方提供的一种方案,此时我们不能再通过配置进行编写,而是需要通过编写对应类来注入。配置文件中的配置需要进行屏蔽。
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.view.InternalResourceViewResolver; import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer; import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver; @Configuration public class FreeMarkerAndJspConfiguration { @Bean public ViewResolver getJspViewResolver() { InternalResourceViewResolver internalResourceViewResolver = new InternalResourceViewResolver(); internalResourceViewResolver.setPrefix("/WEB-INF/jsp/"); internalResourceViewResolver.setSuffix(".jsp"); internalResourceViewResolver.setOrder(2); return internalResourceViewResolver; } @Bean public FreeMarkerViewResolver getFreeMarkerViewResolver() { FreeMarkerViewResolver freeMarkerViewResolver = new FreeMarkerViewResolver(); freeMarkerViewResolver.setCache(false); freeMarkerViewResolver.setSuffix(".ftl"); freeMarkerViewResolver.setRequestContextAttribute("request"); freeMarkerViewResolver.setOrder(1); freeMarkerViewResolver.setContentType("text/html;charset=UTF-8"); freeMarkerViewResolver.setAllowRequestOverride(true); freeMarkerViewResolver.setAllowSessionOverride(true); freeMarkerViewResolver.setExposeRequestAttributes(true); freeMarkerViewResolver.setExposeSpringMacroHelpers(false); freeMarkerViewResolver.setRequestContextAttribute("request"); freeMarkerViewResolver.setViewClass(org.springframework.web.servlet.view.freemarker.FreeMarkerView.class); return freeMarkerViewResolver; } @Bean public FreeMarkerConfigurer getFreeMarkerConfigurer(){ FreeMarkerConfigurer freeMarkerConfigurer = new FreeMarkerConfigurer(); freeMarkerConfigurer.setTemplateLoaderPath("classpath:/templates/ftl/"); freeMarkerConfigurer.setDefaultEncoding("UTF-8"); freeMarkerConfigurer.setPreferFileSystemAccess(true); return freeMarkerConfigurer; } }
这里需要特别注意的一点,就是jsp存放位置
/src/main/resources/META-INF/resources/WEB-INF/jsp/controller.jsp
找了好半天问题,因为基本都说是在WEB-INF 绝大部分都说明是在webapp下,结果试了,还是不行。此处应该还是与springBoot版本有关。我目前直接使用的为2.3
4.外置Jetty 转 内置Tomcat
磁盘映射
其实主要就是涉及到原来磁盘静态文件的读取,俗称磁盘映射。
@Configuration public class WebMvcConfiguration implements WebMvcConfigurer { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { //意思就是,前端浏览器访问路径带有/file/**就转到对应磁盘下读取图片, //类似前端访问tomcat webapp下file文件夹中文件 //**注意/结尾 否则可能出现无法匹配 registry.addResourceHandler("/resource/**").addResourceLocations("file:" + EnvConfig.getConfig(EnvConfig.PathConfig.RESOURCE_PATH) + File.separator); } }
RealPath路径获取
其中jsp中包含下面一句
application.getRealPath("/")
如果经过测试,可以发现此路径是一个private开头,但是里面什么内容都没有的路径。说明并没有获取到项目真正的路径
此时需要我们在主项目根目录下,可以创建一个public文件夹,然后该代码就可以找到正确的绝对路径了。
可以参考:
SpringBoot 内置tomcat 的 request.getServletContext().getRealPath(“/”) 问题与tomat-docbase 和 basedir的关系
5.其他问题
关于动态加载的静态参数问题
例如此静态属性:
//其具体值是通过java启动进过condition计算得出的 public static final String DOCUMENT_HTML_BASE_PAHT = EnvConfig.getConfig(EnvConfig.PathConfig.BASE_PATH)+ File.separator+"document"+File.separator+"html";
关于springBoot devTool不同类加载器的问题
如果springBoot在加载应用代码的时候 使用
org.springframework.boot.devtools.restart.classloader.RestartClassLoader
类加载器,但是加载某些jar包的时候,又会使用
sun.misc.Launcher$AppClassLoader
可能某些代码会破坏单例性质,也可能像我遇到了一个静态属性类被初始化了2次,原因是我调用某个jar包,此jar包的类又被我重写调用了,然后就出现这个情况了。
此类问题解决办法:
1.关闭devTools
spring.devtools.restart.enabled=false
2.把这个jar包加入配置,让jar包中的类加载也通过RestartClassLoader加载
restart.include.companycommonlibs=/ueditor-[\\w-]+\\.jar restart.include.projectcommon=/cxxz/core/
可以参考:
Springboot之devtools类加载问题研究
SpringBoot配置devtools实现热部署
写在最后
自己的项目也不是什么大项目,花费了2天时间,终于调整完毕,但是后续加入Jenkins集成,还有好多路要走。
产生这种改变的想法原因是在将项目部署到阿里云的时候,需要先布置jetty,配置映射。再上传war。感觉就一个小项目,却要四处配置。
而springBoot 的jar形式,则更像java宣传的,一次编译,到处跑。
当然这种约定优先,感觉还是需要先去熟悉他的默认配置,否则就是从一个坑进入另一个坑~
如果有天遇到一个问题,解决不了,试试官网文档,也许会有你想要的答案~