zoukankan      html  css  js  c++  java
  • OSGi框架嵌入servlet开发Web应用问题(1)——servlet实例唯一

    一、环境简介

      项目以前使用的是RCP框架,现想支持web请求,为了减少后台逻辑处理工作量,重用之前的RCP程序代码,通过添加一个新的插件用于处理web请求。具体实现可见http://blog.csdn.net/rongyongfeikai2/article/details/39577237。

    二、问题现象

      在前台的一个页面中有两种ajax请求device和plan。页面显示的表格内容是通过plan请求填充,操作需要用到的数据通过定时的device请求来获取。这两个请求的后台处理类为同一个HttpServlet类。在重复刷新的过程中,出现plan请求失败的现象,出现请求失败时device请求也会出现异常,但成功返回。

      关键代码如下:

    AbstractServlet类

     1 import javax.servlet.http.HttpServlet;
     2 import javax.servlet.http.HttpServletRequest;
     3 import javax.servlet.http.HttpServletResponse;
     4 
     5 public abstract class AbstractServlet extends HttpServlet {
     6     
     7     /** 请求*/
     8     protected HttpServletRequest request;
     9     
    10     /** 响应*/
    11     protected HttpServletResponse response;
    12     
    13     /** 操作名称*/
    14     protected String action;
    15     
    16     /** 请求结果*/
    17     protected boolean result;
    18     
    19     @Override
    20     protected void doGet(HttpServletRequest request, HttpServletResponse response){
    21         this.request = request;
    22         this.response = response;
    23         
    24         getActionParam();
    25         
    26         excetue();
    27         
    28         returnResult();
    29         
    30     }
    31     
    32     /**
    33      * 获取前端的action字段
    34      */
    35     protected void getActionParam() {
    36         action = request.getParameter("action");    
    37     }
    38     
    39     
    40     abstract  public void excetue();
    41     
    42     abstract protected void returnResult();
    43 }
    View Code

    TestServlet类

     1 import java.io.IOException;
     2 
     3 import org.codehaus.jackson.JsonNode;
     4 
     5 import com.macrosan.core.nonui.util.JsonMapper;
     6 
     7 public class TestServlet extends AbstractServlet {
     8     
     9     private JsonNode resultNode;
    10     
    11     @Override
    12     public void excetue() {
    13         if ("plan".equals(action)) {
    14             queryAllPlans();
    15         } else if ("device".equals(action)) {
    16             queryAllDevices();
    17         }     
    18     }
    19 
    20     private void queryAllDevices() {
    21         /// .......
    22         resultNode = JsonMapper.toNormalTree("device response json string");
    23 
    24     }
    25 
    26     private void queryAllPlans() {
    27         /// .......
    28         resultNode = JsonMapper.toNormalTree("plan response json string");
    29     }
    30     
    31     /**
    32      * 
    33      */
    34     protected void returnResult() {
    35         
    36         try {
    37             String resultStr = resultNode.toString();
    38             
    39             String callBack = request.getParameter("callback");
    40             
    41             // 普通访问
    42             String responseStr = "";
    43             if (callBack == null) {
    44                 responseStr = resultStr;                
    45             } else {
    46                 responseStr = callBack + "(" + resultStr + ")";                
    47             }
    48             
    49             response.getWriter().print(responseStr);
    50         } catch (IOException e) {
    51             e.printStackTrace();
    52         }
    53     }
    54 }
    View Code

    三、问题定位

      复现问题后,通过浏览器调试工具,找出后台返回的结果,如下:

      jQuery110102986526135296296_1444812367854([{plan}])jQuery110102986526135296296_1444812367854([{device1},{device2}])

      正常情况下应该只返回一个jQuery110102986526135296296_1444812367854字符串,很显然是一个请求结果中包含了两个请求的结果,由于是jsonp跨域请求,所以第二个ajax请求失败。那第一个请求出现error的原因是什么呢?

      从结果上看,应该是plan请求先来处理完成后在returnResult方法中将结果先写入,且device请求也来了,接着讲device的结果也写入导致的该字符串。

      习惯了使用Struts2等框架,每次action请求都是一个单独的实例来处理请求,跟上一次请求无关。但servlet插件则不同,每次处理请求的实例是同一个对象,所以上一次请求将该实例中的属性修改了会影响到下一次请求。该问题的出现原因是plan请求先来,request和response都是plan请求的,当完成数据收集后,device请求来了,将request和response修改为device的信息,导致plan请求流程中的returnResult方法中的response是device请求的,故导致device请求的结果有两个字符串,而plan请求由于没有返回数据导致请求失败。

    四、问题解决

      解决方法非常简单,在doGet方法前添加同步关键字,如下:

     1     @Override
     2     synchronized protected void doGet(HttpServletRequest request, HttpServletResponse response){
     3         this.request = request;
     4         this.response = response;
     5         
     6         getActionParam();
     7         
     8         excetue();
     9         
    10         returnResult();
    11         
    12     }
    View Code

    五、问题总结
      该问题包含多线程处理同一对象,导致信息达不到预期的效果;请求没有任何返回会作为error处理;jsonp结果字符串必须要严格的格式等知识点。

      

    每多学一点知识,就少写一行代码。
  • 相关阅读:
    记第一场省选
    POJ 2083 Fractal 分形
    CodeForces 605A Sorting Railway Cars 思维
    FZU 1896 神奇的魔法数 dp
    FZU 1893 内存管理 模拟
    FZU 1894 志愿者选拔 单调队列
    FZU 1920 Left Mouse Button 简单搜索
    FZU 2086 餐厅点餐
    poj 2299 Ultra-QuickSort 逆序对模版题
    COMP9313 week4a MapReduce
  • 原文地址:https://www.cnblogs.com/guanmu/p/4878358.html
Copyright © 2011-2022 走看看