百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程网 > 正文

Struts2.3.32升级到2.5.26详细步骤(无敌版)

yuyutoo 2024-12-19 17:36 5 浏览 0 评论


Struts2真是三天两头爆出漏洞来,特别是一爆出漏洞就建议升级到最新版,也是无语的,并且最新版相比老板还相差挺大的,这部这次需要从Struts2.3.32一下子就必须升级到最新版,这可让人头大,谷歌百度了几天都没有解决方案,大概是因为每个人的项目都是不同的吧,有些用纯注解,有些用配置文件,所以可能适合你的解决方案却不适合别人,最终还是得靠自己解决,下面整理了一下我的解决方案,其中有些错误只能通过修改源码来搞定的。

一、项目背景

这里先要说一下要升级的项目背景,因为不同架构的项目升级方法可能有差异,我用的项目是Struts2.3.32,然后用纯注解动态方法调用的模式,也就是直接在Action上面加上请求的注解,然后每个方法都是请求路径,不需要修改配置文件,格式如下:

@ParentPackage(value = "default")
@Namespace(value = "/")
@Action(value = "indexAction",results = {
        @Result(name = "test",location = "/test.jsp"),
        @Result(name = "test2",location = "/test2.jsp")
})
public class IndexAction{
    public String test(){
        System.out.println("我是action,被test1调用");
        return "test";
    }
    public String test2(){
        System.out.println("我是action,被test2调用");
        return "test2";
    }
}

后面如果想要加请求也很简单,直接多加一个方法,然后多加一个@Result返回值就可以了。这个是我的项目结构,下面的升级步骤也是基于这个结构来的,不过就算大家的结构有区别,那么也应该有借鉴的地方,反正我基于的逻辑就是,实在是解决不了就从源码下手。

二、环境准备

我觉得,升级之前的第一步就是自己用最新版的Struts2搭建一个项目,保证自己的升级包是可以用的先,然后在对比自己项目的区别逐个攻破,所以我先自己搭建了一个例子:Strtus2.5.26动态方法调用注解模式环境搭建:https://www.suibibk.com/topic/788791049202958336

这里需要去官网下载struts2.5.26的环境包和源码包:http://struts.apache.org/download.cgi#struts2526

struts-2.5.26-all.zip (65MB) [PGP] [SHA256]
struts-2.5.26-src.zip (7MB) [PGP] [SHA256]

我本地搭建的时候貌似tomcat需要为tomcat8,但是在我的项目上貌似用apache-tomcat-7.0.96也可以,不过jdk好像就需要1.8,不然会报各种各样的错误,得看每个人的具体情况。

三、Struts2.3.32升级到Struts2.5.26步骤

1、修改web.xml

在2.5.26后,struts的过滤器也改了一下,少了ng的包路径

<filter>
    <filter-name>struts2</filter-name>
    <filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>

2、修改struts.xml

struts.xml的配置文件也需要修改下,比如主动开启动态方法调用,然后加上全局方法允许访问的配置,如下:

<constant name="struts.enable.DynamicMethodInvocation" value="true"/>
<constant name="struts.enable.SlashesInActionNames" value="true"/>
<constant name="struts.action.extension" value="do" />
<package name="default" extends="struts-default">
    ...
    <global-allowed-methods>regex:.*</global-allowed-methods>
</package>

然后配置文件头部的版本也要改为2.5

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
    "http://struts.apache.org/dtds/struts-2.5.dtd">

注意事项:
注1:这里的package中的name一定要跟你Action中的@ParentPackage注解对应的一样
我注2:我看网上还有些需要加上:strict-method-invocation=”false”,我升级发现并不需要

3、整理需要的jar包

这里导入的jar包应该是你自己搭建测试的里面的jar包,也就是从struts-2.5.26\apps\struts2-showcase\WEB-INF\lib获取jar包,但是还要做如下处理

  • 把spring开头的删除
  • 把tiles开头的删除

4、删除原来的多余的jar包

删除你原来项目中在你新准备的jar包中已经存在的版本不同的jar包,也就是替换老的jar包,我这里就直接根据前缀来删除了,不过删除之前必须先备份,因为可能会多删除,那么需要把相应的jar包还原:

rm -rf struts*
rm -rf asm*
rm -rf commons*
rm -rf velocity*
rm -rf log*
rm -rf antlr*
rm -rf dom4j-1.6.1.jar
rm -rf dwr.jar 
rm -rf freemarker-2.3.22.jar
rm -rf xwork-core-2.3.32.jar

其实在后面的启动阶段就会报如下错误:

报错1:Caused by: java.lang.NoClassDefFoundError: Lorg/apache/log4j/Logger;
是因为新的log4j-api-2.12.1.jar包没有这个包路径,所以要把上面log4j-1.2.13.jar还原回去

报错2:找不到commons下面的http包
所以要把commons-httpclient-3.0.jar还原回去

当然每个人的老项目都可能不一样,所以不一定会遇到这两个错误。

5、上传jar包

把你在第3步骤整理的jar包上传。

6、启动项目

在启动之前,需要先准备一下,准备测试链接,我这里要做这一步是因为我们这个项目只有一个开发环境,所以不能影响正常开发,我就再nginx做了一个路径拦截,拦截某一路径然后转发到我这个应用下面。

如果启动报某些类找不到,那么应该是上面自己多删了,还原回去多删的就好,如果还有找不到的,就网上找到放进去就好,这些都不是问题,遇到的最最最棘手,最最最让人崩溃的问题是下面这个问题:

convention.annotation.Result.name()(Found data of type calss java.lang.String[index])

这个怎么搞,看了下@Result的源码,果然发现在以前的版本name是一个字符串,现在这个新的版本name是一个字符串数组,我的天,也就是说需要在注解上用如下模式?

@Result(name = {"test"},location = "/test.jsp"),

我看网上有一个人的解决方案就是把把项目中所有的name=”xxx”改为name={“xxx”},这当然可以解决,但是注解其实就算你要求的是:

String[] name;

你还是可用name=”xxx”的模式的,所以这个原因我们应该可以排除。然后网上说重新编译一下项目就好了,那当然,其实上面的改为{“xxxx”}的模式的方法应该也是重新编译一下项目就好了,但是我们的项目是在是太老了,重新编译不了,并且有些类跟生产环境的对不上,如果每个文件都要重新登记下版本重新取一下编译好的字节码class换到生产环境,可能性不大,并且我们的老项目本地丢启动不了,有些还有报错,所以这种解决方案我这边也用不了。

后面我想,得先看看现在的name解析的是什么,然后我就拷贝了一份struts2.5.26的源码,找到使用这个注解的地方,其实也就是在如下类中:

org/apache/struts2/convention/DefaultResultMapBuilder#createFromAnnotations

按相同的路径新建这个类然后修改下源码,打印出来:

for (Result result : results) {
    System.out.println("result:"+result);
    for (String name : result.name()) {
         ResultConfig config = createResultConfig(actionClass, new ResultInfo(
                name, result, packageConfig, resultPath, actionClass,
                resultsByExtension), packageConfig, result);
        if (config != null) {
            resultConfigs.put(config.getName(), config);
        }
}

将编译后的文件放入项目的class目录下,重新启动,发现打印出的日志如下:

@org.apache.struts2.convention.annotation.Result(name=sun.reflect.annotation.AnnotationTypeMismatchExceptionProxy@46e93c84, location=/chinapost/weixin/activitys/posterSharing/index.jsp, type=, params=[])

很明显name既不是字符串也不是数组,是一个异常对象:

sun.reflect.annotation.AnnotationTypeMismatchExceptionProxy@46e93c84,

百度了下该异常:AnnotationTypeMismatchException异常。

public class AnnotationTypeMismatchExceptionextends RuntimeException若某个注释的类型在对该注释进行编译(或序列化)后发生了更改,而程序试图访问该注释的元素时,抛出此异常。

那应该是我们之前的源码编译是基于name为字符串的,现在直接不重新编译,替换jar包后,新的注解Result和DefaultResultMapBuilder类不能对之前的编译的类进行处理了,然后就报错了,那也解释了为什么网上的解决方案都是重新编译就可以了,那我既然不能重新编译怎么办呢,解决方案如下:重写Result和DefaultResultMapBuilder。

7、重写Result和DefaultResultMapBuilder

重写org.apache.struts2.convention.annotation.Result注解和org.apache.struts2.convention.DefaultResultMapBuilder

Result将String[] name 改为String name

DefaultResultMapBuilder的方法createFromAnnotations for循环改为直接取

for (Result result : results) {
            System.out.println("result:"+result);
            String name = result.name();
          //  for (String name : result.name()) {
                ResultConfig config = createResultConfig(actionClass, new ResultInfo(
                        name, result, packageConfig, resultPath, actionClass,
                        resultsByExtension), packageConfig, result);
                if (config != null) {
                    resultConfigs.put(config.getName(), config);
                }
          //  }
        }

然后项目可以启动了,打印出来的Result的name也是一个字符串啦。也就相当于有如下两个解决方案

解决方案1:重新编译项目即可
解决方案2:不能重新编译项目则重写Result和DefaultResultMapBuilder,兼容以前的模式。

注:目前不清楚改了这两个地方是否有太大影响,但是知道的是name不能用数组的模式,必须按以前的单个值的模式开发。

8、访问测试

访问发现报如下错误

Exception occurred during processing request: javax.servlet.ServletException: java.lang.NoSuchMethodError: org.apache.struts2.views.jsp.PropertyTag.setEscape(Z)Vorg.apache.jasper.JasperException: javax.servlet.ServletException: java.lang.NoSuchMethodError: org.apache.struts2.views.jsp.PropertyTag.setEscape(Z)V

这个是jsp报错,因为最新版本有一些标签页变了,这个要相应的改一下:
如果你有这样的代码

<s:url id="url" action="login">
<s:set id="str1" value="'string1 value'" />
<s:property escape="true" var="someProperty"/>

需要改成:

<s:url var="url" action="login">
<s:set var="str1" value="'string1 value'" />
<s:property escapeHtml="true" var="someProperty"/>

然后再访问就成功进入啦。

四、总结

1、升级步骤

  • 修改web.xml,将过滤器改为最新版本
  • 修改struts.xml 主动开启动态方法调用
  • 替换最新版本的jar包
  • 若可以重新编译项目,则直接重新编译项目
  • 若不可重新编译项目,则修改对应源码做兼容处理这里修改的额源码为:Result和DefaultResultMapBuilder
  • 修改JSP相应标签

2、遗留问题

  • 需要对所有jsp进行检查看看是否需要改标签
  • 还未对是否兼容spring做检查,因为我们这个项目是直接调用微服务来处理的,不过也用了spring,还需要继续测试看看是否会有问题
  • 源码的修改为验证是否对其他功能有影响,唯一知道的是@Result中name不能用数组name{“xxxx”}模式,必须按以前的字符串模式name=”xxxx”
  • 待续…

相关推荐

Mysql和Oracle实现序列自增(oracle创建序列的sql)

Mysql和Oracle实现序列自增/*ORACLE设置自增序列oracle本身不支持如mysql的AUTO_INCREMENT自增方式,我们可以用序列加触发器的形式实现,假如有一个表T_WORKM...

关于Oracle数据库12c 新特性总结(oracle数据库19c与12c)

概述今天主要简单介绍一下Oracle12c的一些新特性,仅供参考。参考:http://docs.oracle.com/database/121/NEWFT/chapter12102.htm#NEWFT...

MySQL CREATE TABLE 简单设计模板交流

推荐用MySQL8.0(2018/4/19发布,开发者说同比5.7快2倍)或同类型以上版本....

mysql学习9:创建数据库(mysql5.5创建数据库)

前言:我也是在学习过程中,不对的地方请谅解showdatabases;#查看数据库表createdatabasename...

MySQL面试题-CREATE TABLE AS 与CREATE TABLE LIKE的区别

执行"CREATETABLE新表ASSELECT*FROM原表;"后,新表与原表的字段一致,但主键、索引不会复制到新表,会把原表的表记录复制到新表。...

Nike Dunk High Volt 和 Bright Spruce 预计将于 12 月推出

在街上看到的PandaDunk的超载可能让一些球鞋迷们望而却步,但Dunk的浪潮仍然强劲,看不到尽头。我们看到的很多版本都是为女性和儿童制作的,这种新配色为后者引入了一种令人耳目一新的新选择,而...

美国多功能舰载雷达及美国海军舰载多功能雷达系统技术介绍

多功能雷达AN/SPY-1的特性和技术能力,该雷达已经在美国海军服役了30多年,其修改-AN/SPY-1A、AN/SPY-1B(V)、AN/SPY-1D、AN/SPY-1D(V),以及雷神...

汽车音响怎么玩,安装技术知识(汽车音响怎么玩,安装技术知识视频)

全面分析汽车音响使用或安装技术常识一:主机是大多数人最熟习的音响器材,有关主机的各种性能及规格,也是耳熟能详的事,以下是一些在使用或安装时,比较需要注意的事项:LOUDNESS:几年前的主机,此按...

【推荐】ProAc Response系列扬声器逐个看

有考牌(公认好声音)扬声器之称ProAcTablette小音箱,相信不少音响发烧友都曾经,或者现在依然持有,正当大家逐渐掌握Tablette的摆位设定与器材配搭之后,下一步就会考虑升级至表现更全...

#本站首晒# 漂洋过海来看你 — BLACK&amp;DECKER 百得 BDH2000L无绳吸尘器 开箱

作者:初吻给了烟sco混迹张大妈时日不短了,手没少剁。家里有了汪星人,吸尘器使用频率相当高,偶尔零星打扫用卧式的实在麻烦(汪星人:你这分明是找借口,我掉毛是满屋子都有,铲屎君都是用卧式满屋子吸的,你...

专题|一个品牌一件产品(英国篇)之Quested(罗杰之声)

Quested(罗杰之声)代表产品:Q212FS品牌介绍Quested(罗杰之声)是录音监听领域的传奇品牌,由英国录音师RogerQuested于1985年创立。在成立Quested之前,Roger...

常用半导体中英对照表(建议收藏)(半导体英文术语)

作为一个源自国外的技术,半导体产业涉及许多英文术语。加之从业者很多都有海外经历或习惯于用英文表达相关技术和工艺节点,这就导致许多英文术语翻译成中文后,仍有不少人照应不上或不知如何翻译。为此,我们整理了...

Fyne Audio F502SP 2.5音路低音反射式落地音箱评测

FyneAudio的F500系列,有新成员了!不过,新成员不是新的款式,却是根据原有款式提出特别版。特别版产品在原有型号后标注了SP字样,意思是SpecialProduction。Fyne一共推出...

有哪些免费的内存数据库(In-Memory Database)

以下是一些常见的免费的内存数据库:1.Redis:Redis是一个开源的内存数据库,它支持多种数据结构,如字符串、哈希表、列表、集合和有序集合。Redis提供了快速的读写操作,并且支持持久化数据到磁...

RazorSQL Mac版(SQL数据库查询工具)

RazorSQLMac特别版是一款看似简单实则功能非常出色的SQL数据库查询、编辑、浏览和管理工具。RazorSQLformac特别版可以帮你管理多个数据库,支持主流的30多种数据库,包括Ca...

取消回复欢迎 发表评论: