项目背景:
tomcat 6 + JDK6 + Linux
现有应用(无维护厂商, 有知识产权不得改代码, 总之就是不能动) : WebApp0,
提供一个WebService作为入口: /WebApp0/Service
新系统(实现了新的业务逻辑,作为老系统的补充, 能够完全控制代码): WebApp1,
同样提供WebService作为入口:/WebApp1/Service
分析:
由于所有的业务都指向了WebApp0/Service, 然而现有系统不能二次开发, 只能在用户请求到达WebApp0之前做分发. Tomcat的过滤器(filter)可以帮助我们实现这一目标.
Tomcat过滤器是针对根(/)进行过滤,也就是全局过滤. 配置文件放在{tomcatRoot}/conf/web.xml
同时,由于需要跨域(/WebApp0和/WebApp1),需要修改Tomcat的安全配置.{tomcatRoot}/conf/context.xml
代码实现:
Filter:
xx
package org.mylab.container.filter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
/**
* Created by CasparLi on 03/03/2015.
* 所有的用户请求都指向http://localhost/WebApp0/Service,
* 而新逻辑部署在http://localhost/WebApp1/Service.
* 根据请求内容中是否包含关键字"OOXX"判断走新逻辑还是老逻辑.
*/
public class TestFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("TestFilter init!");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
String requestURL = httpRequest.getRequestURL().toString();
System.out.println("TestFilter requestURL : " + requestURL);
String msg;
BufferedReader reader = request.getReader();
msg = reader.readLine();
if (msg == null || msg.isEmpty()) {
System.out.println("TestFilter read msg failed.");
chain.doFilter(request, response);
return;
} else {
System.out.println("TestFilter read msg success: " + msg);
}
reader.reset(); // 这里必须要reset, 否则转发后取不到数据.
if (msg.contains("OOXX")) {
System.out.println("TestFilter got OOXX forward to WebApp1");
ServletContext rootContext = httpRequest.getServletContext(); //取根的上下文. 根路径是: http://localhost/
ServletContext app01Context = rootContext.getContext("/WebApp1");
System.out.println("Got context:" + app01Context);
RequestDispatcher dispatcher = app01Context.getRequestDispatcher("/Service"); //这里取的是WebApp1的上下文, 根路径就成了: http://localhost/WebApp1/ 所以只需要写/Service
System.out.println("Got dispatcher :" + dispatcher);
dispatcher.forward(request, response);
} else {
chain.doFilter(request,response);
}
}
@Override
public void destroy() {
System.out.println("TestFilter has be destroyed");
}
}
Filter写好后需要打成jar包, 放到{tomcatRoot}/lib中才能被Tomcat使用. 付一个maven的打包脚本:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.mylab</groupId>
<artifactId>ContainerFilter</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<jdk.version>1.6</jdk.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>${jdk.version}</source>
<target>${jdk.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
</dependency>
</dependencies>
</project>
Tomcat的web.xml配置
<!-- MyFilter -->
<filter>
<filter-name>MyDispatcher</filter-name>
<filter-class>org.mylab.container.filter.TestFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>MyDispatcher</filter-name>
<!-- 这里是全局过滤器, 必须mapping到根上, 否则过滤器不起效 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
这时运行Tomcat, 过滤器应该已经生效, 并能够根据内容对用户请求分发. 但会报空指针错误. 这是因为请求跨域了(从/跨到/WebApp1). 要解决这个问题就要配置Tomcat的参数, 使得支持跨域.
修改{tomcatRoot}/conf/context.xml 在 Context节点上添加 crossContext="true"属性, 其默认值是false, 跨域取ServletContext会返回null.
<Context crossContext="true">
现在重启Tomcat, 请求就能正确分发了.