structs1.x到SpringBoot3

背景

还是之前公司需要整体升级到tomcat10的事情,最近交接了一个十多年的项目还是用structs1.x的版本开发的,看了一下Struts的文档,当前6.x的版本还是使用javax的命名空间,将来会在7.0的版本升到jakarta,日期未定。和领导讨论了一下决定由struts换成springboot

  1. 公司对于Tomcat10的升级有deadline,需要9月底完成
  2. struts1.x -> 7.0变化也很大,相对来说我们对Springboot的技术储备更加充实,已经有多个项目完成Springboot3的升级
  3. 项目本身接口较少,风险较低

准备工作

首先要把struts-config.xml这个配置文件找出来,看一下都定义了哪些接口,对应的Action在什么位置,把TestCase梳理出来。然后把web.xml文件仔细看一遍,看一下定义了哪些Servelet, Filter以及context-param。整理好这些和web相关的配置接下来就可以开始编码相关的工作了

编码

POM

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>

Controller

  1. 根据struts-config.xml中定义的接口,我们可以划分为若干个controller
  2. 对Action进行改造,将action加上@Component,对输入输出参数进行修改,再注入到controller层

Filter

对于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;
    }

Servlet

对于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;
    }
}

Application

@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);

    }

application.yml

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

搞完这些基本就可以了。

遇到的坑

application.yml读取不到。

这个是因为原本的项目路径为src/java/resources。SpringBoot读取的路径为src/main/java/resources,修改文件路径后解决

jndi

之前项目里通过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);
            }
        };
    }

你可能感兴趣的:(Spingboot3,struts,java,spring)