can not be cast to javax.servlet.Filter等问题的解决方法
问题1:can not be cast to javax.servlet.Filter
一位从测试转开发的同事首次更新代码,并编译在本地启动web项目时,报如下错误:
Exception starting filter encodingFilter
java.lang.ClassCastException:com.gaochao.platform.web.context.filter.ContextFilter2 can not be cast to javax.servlet.Filter
根据这一错误,在网上查找资料一般认为是tomcat/lib下的jar包跟webapps目录里的应用程序中WEB-INF/lib目录下有相同的包,存在版本上的冲突,解决方案就是为依赖加上一个标签<scope>
<dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>${servlet-version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jsp-api</artifactId> <version>${jsp-version}</version> <scope>provided</scope> </dependency>
顺着这个思路,我查找了关于<scope>标签的用法,如下:
* compile,缺省值,适用于所有阶段,会随着项目一起发布。
* provided,类似compile,期望JDK、容器或使用者会提供这个依赖。如servlet.jar。
* runtime,只在运行时使用,如JDBC驱动,适用运行和测试阶段。
* test,只在测试时使用,用于编译和运行测试代码。不会随项目发布。
* system,类似provided,需要显式提供包含依赖的jar,Maven不会在Repository中查找它。
但是,我们的代码里确认是有这个标签,且配置也没有错误,确实是provided。在已经打好的war包里查询,路径\oa-deploy\target\oa-deploy-0.0.1-SNAPSHOT\WEB-INF\lib中也确认没有servlet的jar包,也符合期望JDK、容器或使用者会提供这个依赖的解释。可见问题还不是出在这个地方,进一步搜索是不是还有其他解决思路。经过进一步查询资料,发现在http://jira.codehaus.org/有一个编号为MOJO-1076的bug,其bug描述与我们的错误基本一致,另外一名用户为其提供的解决思路也是在dependency中加入<scope>属性,提报bug的用户最后加备注如下:
My issue was introduced by gwt-user.jar that contains javax.servlet package.
Setting it as provided solved the issue.
我的问题是引入gwt-user.jar,而该包中包含servlet,将该包(也可能是该包中依赖servlet)的scope改为provided即ok了。目前我们的项目里引入百数十个包,里面是不是包含servlet查找起来将是较大的工程。另外,除了这名同事以外,其他同事的tomcat启动是不是问题的。所以以上的描述只是解决类似问题的一个思路,但并不是我们问题产生的原因。
再进一步查找资料,还有前辈提供的一种方案,用以解决不同依赖中包含版本冲突的servlet的问题。在其描述中,类似本题目中的问题是由tomcat6-maven-plugin和paoding-rose两个工程的maven依赖引起,这两个依赖都依赖了servlet-api包,而且两个包的scope都设置成了运行时可用,其中tomcat6-maven-plugin为runtime,paoding-rose为compile该方案提供的方法是使用<exclusions>元素实现。
如下:
<dependency> <groupId>net.paoding</groupId> <artifactId>paoding-rose</artifactId> <version>1.0-SNAPSHOT</version> <exclusions> <exclusion> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.3</version> <scope>provided</scope> </dependency> </dependencies> </dependencies>
以上是三种通过互联网查询的方案,未解决问题;又通过卸载jdk、tomcat、maven并重装等等。最终发现采用jetty可以启动项目。最后的解决方案,即为:重装机器,重新部署环境。
问题2:MYSQL里的ISNULL、IFNULL、NULLIF
在对工作流历史任务进行查询时,历史任务的审批人存储的用户表中的用户code,需要left join 用户表将对应的用户名称。如下:
<!-- 查询集合审批历史 --> <select id="queryByProcessExecutionIdForPage" resultMap="TaskResultMap" parameterType="String"> SELECT task.processExecutionId, process.name as processDefineName, task.activityName, user.userName as createUserCode, task.status, task.description, task.finishTime, task.createTime FROM T_BPM_PROCESS_TASK task LEFT JOIN T_BPM_PROCESS_EXECUTION execution ON task.processExecutionId = execution.id LEFT JOIN t_bpm_process_define process ON execution.processDefineId = process.id LEFT JOIN T_SYS_USER user ON task.createUserCode = user.userCode WHERE task.processExecutionId = #{id} ORDER BY task.createTime DESC, task.finishTime DESC </select>
而在抢办,也就是jbpm4_task的assignee为空,而jbpm4_participation中的参与类型为Candidate时,即形成所有参与人共同参与,均为候选审批人,一人审批结束,则该任务办理通过。由于assignee为空,无法像普通任务那样直接关联查询,所以使用ISNULL函数,如下:
ISNULL(user.userName,"抢办") as createUserCode
在执行该语句时,发现mysql并不支持ISNULL函数,在sql中具有相似功能或相似写法的函数还有:IFNULL以及NULLIF。在链接所指的文章中有对以上三种函数的详细介绍,这里仅作简介。
IFNULL(expr1,expr2)
如果expr1不是NULL,IFNULL()返回expr1,否则它返回expr2。IFNULL()返回一个数字或字符串值,取决于它被使用的上下文环境。
NULLIF(expr1,expr2)
如果expr1= expr2 成立,那么返回值为NULL,否则返回值为 expr1。
通过以上介绍,对于NULLIF为何如此命名感觉很奇怪,似乎与参数null与否无关。在MYSQL中我们就可以使用IFNULL来代替IFNULL实现我们想要的功能,修改后如下:
ISNULL(user.userName,"抢办") as createUserCode
修改后经测试,可以达到我们想要的结果。
问题3:MySQL关于txt格式字段的优化
在新建工作中,会查询出所有流程定义的list,随着新的流程表单不断上线,打开所有流程列表的动作越来越耗时。在查询语句中使用的select * from字样,在流程定义所有的属性中包括了text格式的jpdlXml属性,该属性中存储了该流程的xml定义的文本。因为该查询只需列出流程的id、分类、名称,其他属性是不必须的,将jpdlXml从select属性列表中移除,这也是sql优化的一个基础性的常识,不需要的字段就不要写进select。将jpdlXml移除后,耗时较长的问题并没有明显改善。我们继续向下阅读,发现还有另外一处,在查询出所有流程定义list后,会对该list进行筛选,之前的博文对这一处的逻辑进行过基于责任链模式的优化。其筛选逻辑中有这么一条——流程新发布或表单新保存后会更新流程/表单的某个字段,根据该字段决定新建工作中该流程是否可见。在此处代码里,会对所有流程定义list进行遍历,然后拿到流程对应的form,而查询该form时,也是使用的select *,而在form的定义表中,有两个字段是text类型的,分别为html和template。我们再将这两个非必须字段移除,耗时问题明显改善,用户几无等待就可以看到所有流程的列表。
这一问题给我们的提示就是,查询动作尽量不用*。
问题4:tools.jar not found
为解决问题2,我也尝试在我的笔记本里(已经有一个台式机和只有显示器连接云服务器的VDI盒子,因经常开会,新申请的笔记本电脑,用于远程连接台式机,一直没有安装开发环境),拉取新的代码,按照开发环境配置新的环境,包括jdk、tomcat等,在部署的时候,报出如下错误:
Fatal error compiling: tools.jar not found: C:\Program Files\Java\jre6\..\lib\tools.jar.
网上一般对该问题的定义是eclipse中的jre配置jdk中的jre,而正确的配置应该是jdk。查找后发现并没有配置错。最后查看环境变量配置,Win+R打开cmd,输入 java -version,并没有输出版本信息,发现环境变量配置有误。
修复完毕后,再次deploy没有再发现该问题。
本文出自 “南湖矿工技术空间” 博客,请务必保留此出处http://jncumter.blog.51cto.com/812546/1619492