lisongchuang 2013-09-12
当前的项目中存在下面一种场景:web应用的某个功能中,jsp中加载的某个插件需要将数据提交给web服务端。插件中通过ObjectOutputStream向web端传输数据,但springmvc的拦截器会提前读取该流对象,那么配置指定的Action就无法再读取到该Stream的内容,会导致如下异常:
java.io.EOFException at java.io.ObjectInputStream$BlockDataInputStream.peekByte(Unknown Source) at java.io.ObjectInputStream.readObject0(Unknown Source) at java.io.ObjectInputStream.readObject(Unknown Source)
由于整个项目的controler层用的springmvc框架,所以目前的解决办法是编写一个独立的servlet来单独针对该数据的接收。
因为采用注解的方式将配置service并交给spring管理,而需要编写的servlet需要注入这些service,所以这边采用代理的方式实现:
第一步:编写代理类HttpServletProxy
import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import jxl.common.Logger; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; /** * @description * @author minux * @date 2013-9-2 下午2:16:22 */ public class HttpServletProxy extends HttpServlet { private static final long serialVersionUID = -2934353313384038254L; public static Logger logger = Logger.getLogger(HttpServletProxy.class); private String targetServlet; private HttpServlet proxy; public void init() throws ServletException { this.targetServlet = getInitParameter("targetServlet"); getServletBean(); proxy.init(getServletConfig()); logger.info(targetServlet + " was inited by HttpServletProxy successfully......"); } private void getServletBean() { WebApplicationContext wac = WebApplicationContextUtils .getRequiredWebApplicationContext(getServletContext()); this.proxy = (HttpServlet) wac.getBean(targetServlet); } public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, RuntimeException { proxy.service(request, response); } }
第二步:在web.xml中配置改代理servlet
<servlet> <servlet-name>ComplexWebLoadTestServletProxy</servlet-name> <servlet-class>cn.hxcomm.web.controller.HttpServletProxy</servlet-class> <init-param> <param-name>targetServlet</param-name> <param-value>complexWebLoadTestServlet</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>ComplexWebLoadTestServletProxy</servlet-name> <url-pattern>/complexWebLoadTestServlet.do</url-pattern> </servlet-mapping>
第三步:编写真正实现功能的ComplexWebLoadTestServlet并注解注入
import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.sql.Timestamp; import java.util.Calendar; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import jxl.common.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import cn.hxcomm.common.domain.ComplexWebLoadTestDetail; import cn.hxcomm.web.service.ComplexWebLoadTestService; /** * @description * @author minux * @date 2013-8-30 下午3:44:02 */ @Service("complexWebLoadTestServlet") public class ComplexWebLoadTestServlet extends HttpServlet { private static final long serialVersionUID = -371252886055302137L; public static Logger logger = Logger .getLogger(ComplexWebLoadTestServlet.class); @Autowired private ComplexWebLoadTestService complexWebLoadTestService; public ComplexWebLoadTestServlet() { super(); } public void init() throws ServletException { super.init(); } public void service(HttpServletRequest requeset, HttpServletResponse response) throws ServletException, IOException, RuntimeException { this.doWork(requeset, response); } private void doWork(HttpServletRequest request, HttpServletResponse response) { } }
这样基本就可以实现绕开拦截器提前读取stream的情况。
当然servlet注入service的也有其他的实现方式,比如可以直接不需要代理servlet,直接编写servlet读取需要的配置文件,然后取出需要的service的bean对象。
但是个人感觉代理的方式更方便扩展和管理。