记录一次传统SSH项目升级springboot2经历

  1. 先交代一下改造前项目背景:
    1. 原始项目只迭代了2个大的版本,所以代码量也不算很大,但是旧项目连maven都不是,而且经过好多人手,管理混乱。
    2. 用的spring4.2+hibernate4+struts2,后来整合进的redis也是用jedis写的工具类,连配置都是直接写在java文件里面。
    3. 项目用了一些struts2拦截器,还有spring的AOP以及AspectJ和原生filter和servlet,总之项目的整体控制这块比较乱。
    4. 登录、权限都没有使用框架,使用的比较原始的方法。
    5. 项目前后端分离,所有接口都只返回JSON,只有几个接口有转发和重定向。
  2. 改造已经过去一个多月,通过测试验收之后马上在新框架上又迭代了新版本,所以不是实时记录没有截图,主要记录过程。
  3. 改造过程:
    1. 将项目改造成由maven管理的SSH项目,保证改造完项目能跑起来不报错。
    2. 加入springMVC的依赖,和springMVC配置文件(之后换SpringBoot其实还是会删除,但是先保证Struts2顺利被SpringMVC替换,戒骄戒躁毕竟我还是个菜鸟,慢慢来。),搞完先让项目跑起来。(其实Struts2和springMVC并不会冲突,所以一些很旧的陈年老项目也经常能看见各种框架混用。)
    3. 整理Struts2的拦截器全部用springMVC重写,BaseAction改写为BaseController。
    4. 将类上@NameSpace全部替换为@Controller \n @RequestMapping;将方法上的@Action全部替换为@RequestMapping;所有action包名替换为controller;类的后缀Action全部替换为Controller。(这一步工程量比较大,幸好idea比较智能,修改类名能同时修改文件名和引用,然后项目里面还有很多action没有Namespace,得加@Controller,还有没有继承BaseAction的类添加继承,重构的时候就能发现咱项目管理的多么混乱(┬_┬),发现好多问题,类名小写之类的低级错误一大堆,没有强大的内心,接手改造这样的项目大概只想跑路)。
    5. 改造request和response还有Struts2 属性注入的传参方式springMVC用不了。(这一步也是大坑,没啥技术含量就是繁琐。request可以自动注入直接抽取到BaseController,response是绑定在方法的入参的,其实也可以写拦截器、AOP统一处理参数。因为我们项目接口千奇百怪的写法,所以我选择了最笨的办法一个一个类的改,再者,我还能改前端,实在别扭的就连前端的传参方式一起改了。耐心渐渐消失的时候就懒得给别人改bug了,不然真的做不完了,遗留问题不处理,以后还是坑……但是……一把辛酸泪)
    6. 项目能正常跑起来,controller能访问,Struts2的依赖就能删了,还有Struts2的配置文件,web.xml关于Struts2的配置统统删光。
    7. --------Stringboot分割线,下面就是spring升级了
    8. 首先pom文件SSH的依赖去掉,换成springboot+jpa 
    9. 添加springboot启动类 ​​​​​​​
      import org.springframework.boot.SpringApplication;
      import org.springframework.boot.autoconfigure.SpringBootApplication;
      import org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration;
      import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
      import org.springframework.boot.builder.SpringApplicationBuilder;
      import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
      
      //改造过程中先使用旧版本的xml配置文件(后面把XML改造成注解版之后会去掉这个注解)
      @ImportResource(locations = {"classpath:applicationContext-base.xml"})
      //使用hibernate的 sessionFactory ,不使用JPA的自动配置
      @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, JpaRepositoriesAutoConfiguration.class})
      public class ProApplication extends SpringBootServletInitializer {
          public static void main(String[] args) {
              SpringApplication.run(ProApplication.class,args);
          }
      
      //这里使用这种方式是因为项目会打成war包,部署到tomcat。
      //因为服务器上的tomcat做了https的配置,别的部门同事弄的我也不太懂,没时间研究先这么用着比较简单。
          @Override
          protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
              return application.sources(ProApplication.class);
          }
      }

       

    10. 添加config包存放全局配置。

    11. springMVC配置

      import com.*.*.base.interceptor.LoginInterceptor;
      import com.*.*.base.interceptor.RepeatedRequestsInterceptor;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
      import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
      import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
      
      @Configuration
      public class WebMvcConfig implements WebMvcConfigurer {
      
          @Autowired
          private LoginInterceptor loginInterceptor ;
          @Autowired
          private RepeatedRequestsInterceptor repeatedRequestsInterceptor ;
      
          /** 因为原始项目Struts2使用了.action后缀,所以开启这个配置
           * -设置url后缀模式匹配规则
           * -该设置匹配所有的后缀
           */
          @Override
          public void configurePathMatch(PathMatchConfigurer configurer) {
              configurer.setUseSuffixPatternMatch(true)
                      .setUseTrailingSlashMatch(true);
          }
          /**
           * 拦截器
           */
          @Override
          public void addInterceptors(InterceptorRegistry registry) {
              //1、登录拦截器
              registry.addInterceptor(loginInterceptor)
              // 拦截路径
              .addPathPatterns("/**")
              // 排除请求
              .excludePathPatterns("/login.action")
              ……
              ;
      
              //2、重复请求拦截器        registry.addInterceptor(repeatedRequestsInterceptor).addPathPatterns("/**/*.action");
          }
      
      }

       

    12. 接下来还有跨域、jedis……等配置就不贴代码了,都很简单。

    13. 配置的难点就在hibernate的sessionFactory,因为旧项目写了工具类封装sessionFacroty的操作,依赖sessionFacroty注入。网上找遍很多教程都失败了,后来学习了一下@Bean这个注解的用法,直接照着XML里面的配置写了个baen就解决了。(果然还是太菜了,过去遇到问题只会百度然后复制代码,还停留在代码的搬运工阶段,继续努力↖(^ω^)↗)

      import org.hibernate.SessionFactory;
      import org.springframework.beans.factory.annotation.Qualifier;
      import org.springframework.beans.factory.annotation.Value;
      import org.springframework.boot.context.properties.ConfigurationProperties;
      import org.springframework.boot.jdbc.DataSourceBuilder;
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.context.annotation.Primary;
      import org.springframework.core.annotation.Order;
      import org.springframework.orm.hibernate5.HibernateTransactionManager;
      import org.springframework.orm.hibernate5.LocalSessionFactoryBuilder;
      
      import javax.sql.DataSource;
      
      /**
       * @author Castle
       * @version V1.0  2020/2/26 12:26
       */
      @Configuration
      public class DataSourceConfig {
      
          @Value("${hibernate.dialect}")
          private String dialect;
          @Value("#{'${hibernate.scanPackages}'.split(',')}")
          private String [] scanPackages;
          @Value("${hibernate.showSql}")
          private String showSql;
          @Value("${hibernate.releaseMode}")
          private String releaseMode;
      
      //连接池
          @Order(1)
          @Bean
          @Qualifier(value = "dataSource")
          @Primary
          @ConfigurationProperties(prefix = "c3p0")
          public DataSource dataSource(){
              return DataSourceBuilder.create().type(com.mchange.v2.c3p0.ComboPooledDataSource.class).build();
          }
      
      //sessionFactory
          @Order(2)
          @Primary
          @Bean
          public SessionFactory sessionFactory(DataSource dataSource){
              LocalSessionFactoryBuilder localSessionFactoryBuilder = new LocalSessionFactoryBuilder(dataSource);
              localSessionFactoryBuilder.scanPackages(scanPackages);
              localSessionFactoryBuilder.setProperty("hibernate.show_sql",showSql);
              localSessionFactoryBuilder.setProperty("hibernate.dialect",dialect);
              localSessionFactoryBuilder.setProperty("hibernate.connection.release_mode",releaseMode);
              return localSessionFactoryBuilder.buildSessionFactory();
          }
      
      //事务管理
          @Order(3)
          @Primary
          @Bean
          public HibernateTransactionManager transactionManager(SessionFactory sessionFactory){
              HibernateTransactionManager transactionManager = new HibernateTransactionManager();
              transactionManager.setSessionFactory(sessionFactory);
              return  transactionManager;
          }
      }

      到这里框架更换就基本完成了。

    14. 然后是所有的文件上传接口需要修改为SpringMVC方式。

    15. websocket配置(如果打war包用外部tomcat不配置的,不然会冲突)。

    16. 最后进行了登录的改造,之前用session,因为用天翼云的负载均衡搞不定session复制,用的源IP。乘这次改造一起改成redis。方案:前端的axios做拦截改造heard,后端将登录的用户对象hash值作为key,对象序列化存value,保存在存redis里。顺便实现不允许同一账号多出登录的需求、解决session串数据的问题。

    17. 最后做了一些配置和优化,工具类抽取,json包统一等等小问题,整个过程大概持续了两周。

  4. 最后总结一下:

    1. 准备着手做的时候,计划了三种方案:1、新建一个springboot项目,把业务代码复制过来,哪里报错改哪里;2、换springboot同时换Struts2;3、先换掉Struts2再换springboot。最后选择了方案三,一方面考虑到自己水平菜,求稳一步一步的来,每一步项目都能跑起来,快速定位到错误改完再进行下一项。另一方面是公司使用svn,我不想改完之后整个项目的变更记录都没了或者全是我新增的。代码里面的bug太多了,根本改不完,有些还是要留给写bug的人改,一些严重的地方可能是要追责的。

    2. 一力主张,独立完成,收获颇丰。最大的成就是认识自身甚多问题。年前就觉得自己走到了瓶颈,周遭的同事换了一波又一波,公司节约成本也一直招的刚毕业的初级。所以对比下来,我慢慢骄傲了,变得浮躁。而且公司不做自己的产品,赚快钱,不讲质量,所以3年下来不管是业务还是技术,都没有什么沉淀。主要责任还是在自己,太浮躁。沉不下心研究源码,学的新技术没有使用机会很快就忘记了。

你可能感兴趣的:(java)