还是之前公司需要整体升级到tomcat10的事情,最近交接了一个十多年的项目还是用structs1.x的版本开发的,看了一下Struts的文档,当前6.x的版本还是使用javax的命名空间,将来会在7.0的版本升到jakarta,日期未定。和领导讨论了一下决定由struts换成springboot
首先要把struts-config.xml
这个配置文件找出来,看一下都定义了哪些接口,对应的Action在什么位置,把TestCase梳理出来。然后把web.xml
文件仔细看一遍,看一下定义了哪些Servelet, Filter以及context-param。整理好这些和web相关的配置接下来就可以开始编码相关的工作了
pom推荐直接使用spring-boot-dependencies作为parent,方便进行版本控制
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-dependenciesartifactId>
<version>3.0.4version>
<relativePath/>
parent>
然后按需添加spring-boot的相关依赖,这里我们只是用到了web相关的,
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starterartifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-loggingartifactId>
exclusion>
<exclusion>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jclartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-tomcatartifactId>
<scope>providedscope>
dependency>
最后是打包相关的配置,我们是打成war包放到tomcat里。${start-class}
对应启动的main函数,可以配置在properties里
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<version>${maven-compiler-plugin.version}version>
<configuration>
<source>${java.version}source>
<target>${java.version}target>
configuration>
plugin>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-war-pluginartifactId>
<version>3.3.2version>
<configuration>
<failOnMissingWebXml>falsefailOnMissingWebXml>
<archive>
<manifest>
<mainClass>${start-class}mainClass>
<addDefaultImplementationEntries>trueaddDefaultImplementationEntries>
manifest>
archive>
configuration>
plugin>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<executions>
<execution>
<goals>
<goal>repackagegoal>
goals>
execution>
executions>
<configuration>
<classifier>binclassifier>
<mainClass>${start-class}mainClass>
configuration>
plugin>
plugins>
struts-config.xml
中定义的接口,我们可以划分为若干个controller@Component
,对输入输出参数进行修改,再注入到controller层对于web.xml里定义的filter,我们可以按照以下的方式来进行转换
<filter>
<filter-name>TestFilterfilter-name>
<filter-class>com.webapp.common.TestFilterfilter-class>
<init-param>
<param-name>paramNameparam-name>
<param-value>paramValueparam-value>
init-param>
filter>
<filter-mapping>
<filter-name>TestFilterfilter-name>
<url-pattern>/testUrl.dourl-pattern>
filter-mapping>
@Bean
public FilterRegistrationBean<TestFilter> testFilterRegister() {
FilterRegistrationBean<TestFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(new TestFilter());
registration.setOrder(Ordered.HIGHEST_PRECEDENCE);
registration.addUrlPatterns("/testUrl.do");
registration.addInitParameter(paramName,paramValue);
return registration;
}
对于web.xml里定义的Servlet,我们这里有两种场景:
第一种,直接继承HttpServlet
,比方说下面一个是处理healthcheck的servlet
public class HealthCheckService extends HttpServlet {}
<servlet>
<servlet-name>HealthCheckServiceservlet-name>
<servlet-class>com.webapp.health.HealthCheckServiceservlet-class>
<load-on-startup>4load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>HealthCheckServiceservlet-name>
<url-pattern>/health.dourl-pattern>
servlet-mapping>
@Bean
public ServletRegistrationBean<HealthCheckService> downloadServiceServletRegistrationBean() {
ServletRegistrationBean<TestServlet> registration = new ServletRegistrationBean<>();
registration.setServlet(new HealthCheckService());
registration.addUrlMappings("/health.do");
registration.setLoadOnStartup(4);
return registration;
}
第二种是继承了struts的ActionServlet
,这种类似于Spring中的dispatchServlet
public class TestServlet extends ActionServlet {
<servlet>
<servlet-name>actionservlet-name>
<servlet-class>com.webapp.common.struts.TestServletservlet-class>
<init-param>
<param-name>chainConfigparam-name>
<param-value>/WEB-INF/conf/chain-config.xmlparam-value>
init-param>
<servlet>
<servlet-mapping>
<servlet-name>actionservlet-name>
<url-pattern>*.dourl-pattern>
servlet-mapping>
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(WebMvcProperties.class)
public class WebDispatcherServletConfiguration {
@Primary
@Bean(name = DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
public DispatcherServletRegistrationBean dispatcherServletRegistration(DispatcherServlet dispatcherServlet,
WebMvcProperties webMvcProperties, ObjectProvider<MultipartConfigElement> multipartConfig) {
DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(dispatcherServlet, "*.do");
registration.setName(DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
registration.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());
multipartConfig.ifAvailable(registration::setMultipartConfig);
return registration;
}
}
@Configuration
@ComponentScan(basePackages = { "com.test" })
@EnableAutoConfiguration()
public class Application extends SpringBootServletInitializer implements ApplicationContextAware {
static private ApplicationContext ctx;
static private final String TOMCAT_HOME_KEY = "catalina.home";
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ctx = applicationContext;
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
setRegisterErrorPageFilter(false);
return application.sources(Application.class);
}
public static void main(String[] args) throws Exception {
//区分EmbeddedTomcat
System.setProperty(TOMCAT_HOME_KEY, "EmbeddedTomcat");
SpringApplication.run(Application.class, args);
}
server:
port: 8080
servlet:
context-path: /contxt
tomcat:
basedir: .
accesslog:
enabled: true
buffered: true
directory: logs
prefix: access
suffix: .log
rename-on-rotate: true
pattern: '"%{x-Forwarded-For}i" %l %u %t "%r" %s %b "%{Referer}i" "%{trackingID}o"
"%{User-agent}i" %D %F'
request-attributes-enabled: true
rotate: true
file-date-format: .yyyy-MM-dd
main:
allow-bean-definition-overriding: false
allow-circular-references: true
banner-mode: "off"
web-application-type: servlet
mvc:
pathmatch:
matching-strategy: ant-path-matcher
logging:
config: classpath:log4j2.xml
搞完这些基本就可以了。
这个是因为原本的项目路径为src/java/resources。SpringBoot读取的路径为src/main/java/resources,修改文件路径后解决
之前项目里通过tomcat配置了一些jndi的资源,本地更改为embeded tomcat后启动找不到,可以通过在Application
添加以下代码配置jnid资源
@Bean
//我们在main里执行了 System.setProperty(TOMCAT_HOME_KEY, "EmbeddedTomcat");确保只会在本地加载这个bean
@ConditionalOnExpression("'${catalina.home}' == 'EmbeddedTomcat'")
public TomcatServletWebServerFactory tomcatFactory() {
return new TomcatServletWebServerFactory() {
@Override
protected TomcatWebServer getTomcatWebServer(org.apache.catalina.startup.Tomcat tomcat) {
tomcat.enableNaming();
return super.getTomcatWebServer(tomcat);
}
@Override
protected void postProcessContext(Context context) {
// context
ContextResource resource = new ContextResource();
resource.setName("testjndi");
resource.setType(youCode.class.getName());
resource.setProperty("factory", "org.apache.naming.factory.BeanFactory");
resource.setProperty("maxSize", "50000");
context.getNamingResources()
.addResource(resource);
}
};
}