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结果字符串必须要严格的格式等知识点。

      

    每多学一点知识,就少写一行代码。
  • 相关阅读:
    君の知らない物語
    2.OSI各层概述
    [ unittest ] 使用初体验
    1.分层结构、协议、接口、服务
    [flask] jinja自定义filter来过滤html标签
    [Flask] Flask问题集(后端模板渲染项目)
    [服务器部署] Flask + virtualenv + uWSGI + Nginx 遇到的问题
    android控件的对齐方式(转)
    AIDL
    歌词的获取
  • 原文地址:https://www.cnblogs.com/guanmu/p/4878358.html
Copyright © 2011-2022 走看看