开发者社区> pandamonica> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

Windchill的JSP页面跳转到Ext页面的分析

简介: 今天花了一天时间,看了一块代码,低效但是不得不看懂。具体内容是这样的:Windchill中按钮菜单栏嵌入了一个菜单项,点击它会触发弹出一个新的浏览器页面,相当于弹框,让你输入内容,然后点击保存按钮保存输入信息。
+关注继续查看

今天花了一天时间,看了一块代码,低效但是不得不看懂。
具体内容是这样的:
Windchill中按钮菜单栏嵌入了一个菜单项,点击它会触发弹出一个新的浏览器页面,相当于弹框,让你输入内容,然后点击保存按钮保存输入信息。
问题就在于菜单项本身是一个JSP页面,点击以后弹出窗体本身会是一个Ext的页面。
上图描述一下:
_
上图这样的一个菜单项
_
这样配置的一个菜单项
点击菜单项,也就是这个url以后会跳转到这个url地址代表的jsp页面
JSP的代码如下:

<%@page import="com.bplead.drawingApproval.util.QsWebUtil"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
    //重新定向action地址
    //QsWebUtil.forceNavigateNetmarketsURL(request, response);
      QsWebUtil.BbURL(request, response);
    //---------------//
    //获取对象oid
    String oid = request.getParameter("oid");
    //获取action type(编制、查看)
    String type = request.getParameter("type");
    if("view".equals(type)){
        type = "查看";
    }else if("edit".equals(type)){
        type = "编制";
    }
%>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>图纸发布审批流程 </title>
<!-- ExtJS4.2 css-->
<link rel="stylesheet" type="text/css" href="/Windchill/netmarkets/javascript/bplead/extjs-4.2/resources/css/ext-all.css"></link>
<!-- Util CSS -->
<link rel="stylesheet" type="text/css" href="app/css/util.css"></link>
<!-- ExtJS4.2 -->
<script src="/Windchill/netmarkets/javascript/bplead/extjs-4.2/bootstrap.js"></script>
<script src="/Windchill/netmarkets/javascript/bplead/extjs-4.2/locale/ext-lang-zh_CN.js"></script>
<!-- Custom App -->
<script src="app.js"></script>
<!-- JSP Params -->
<script type="text/javascript">
    var oid = '<%=oid%>';
    var type = '<%=type%>';
</script>
</head>
<body>

上述代码中的BbURL方法的代码如下:

public static boolean BbURL(HttpServletRequest request, HttpServletResponse response) throws Exception{
        
        String key = SB_MARKS;//一个无关紧要的普通字符串
        boolean hasRedirect = request.getSession().getAttribute(key) != null;
        
        if (!hasRedirect) {
            
            request.getSession().setAttribute(key, new Object());
            response.sendRedirect(request.getRequestURI() + "?" + request.getQueryString());
            
        } else {
            
            request.getSession().removeAttribute(key);
        }
            return !hasRedirect;
    }

上述代码中的BbURL()方法究竟起什么作用呢?
经过测试搞清楚了:
上述代码中的if和else代码块,在正常的访问中,会分别进入1次,也就是上述BbURL()方法一共被访问2次。
第一次,JSP页面首次加载,目的是JSP页面中的java代码获取type和oid这两个java变量的值,然后将java变量的值赋值给javascript的对应两个变量
第一次进入JSP页面的核心语句就是下面这一段

<script type="text/javascript">
    var oid = '<%=oid%>';
    var type = '<%=type%>';
</script>

第二次进入JSP页面的原因就是BbURL()方法,因为这个方法的java代码也就是If代码块中调用了

response.sendRedirect(request.getRequestURI() + "?" + request.getQueryString());

这句代码实际上是一句废话,目的是让同样的JSP页面被第二次访问。
在第二次访问JSP页面的时候,BbURL()方法进入else代码块,实际上并没有触发任何有实际意义的业务代码。
但是第二次访问JSP页面的时候,由于此时拥有了第一次访问时获取到的两个javascript变量:type和oid,因此第二次访问就可以顺利将这两个参数传递给ext的js代码,生成网页。
上述逻辑,记录一下。
上述内容总体来说,是无知的阐述,下面结合下一篇博文,详细阐述一下Windchill系统中的jsp页面跳转以及windchill与spring的关系
简单的说,Windchill的web.xml文件中配置了spring和springmvc。

Spring的配置文件较为简单,仅仅注册了1个ptc封装的bean,我估计用途就是,为日后java二次开发的时候,依靠依赖注入将这个bean导入到java代码中,用来后续通过这个bean访问windchill的数据库之类的。
SpringMVC的配置文件比较复杂,这个配置文件导入了133个其他的xml配置文件,非常壮观。
_
说了这么多,重点在于,springmvc的配置文件在web.xml中是怎么配置的呢?换句话说,web.xml文件中,有哪些和web访问有关的配置呢?这是我们考虑页面跳转的关键:
首先web.xml文件中配置了如下内容,也就是说:
所有访问路径中包含/ptc1/*的url的请求都会被springmvc单独处理
当然,具体怎么处理的通过这133个配置文件也许能找到头绪

  <servlet>
    <description>MVC Dispatcher Servlet</description>
    <servlet-name>MVCDispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextClass</param-name>
      <param-value>com.ptc.mvc.components.support.ComponentXmlWebApplicationContext</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>MVCDispatcher</servlet-name>
    <url-pattern>/servlet/WizardServlet/*</url-pattern>
    <url-pattern>/servlet/ActionsMenu/*</url-pattern>
    <url-pattern>/servlet/RecentList/*</url-pattern>
    <url-pattern>/servlet/Navigation/*</url-pattern>
    <url-pattern>/servlet/SuggestServlet/*</url-pattern>
    <url-pattern>/servlet/TypeBasedIncludeServlet/*</url-pattern>
    <url-pattern>/servlet/UIValidationAJAXServlet/*</url-pattern>
    <url-pattern>/ptc1/*</url-pattern>
    <url-pattern>/app/*</url-pattern>
    <url-pattern>/gwt/*</url-pattern>
  </servlet-mapping>

我们尝试在Windchill服务器的springmvc目录中检索133个配置文件中,哪些对ptc1这个字符串进行了配置
在上述目录中执行命令grep -nr "component-scan" *
下图所示的内容,就是这133个文件中都扫描了那些地方,这些地方就是controller的所在,也就是说,如果url中出现了ptc1,那么下面这些位置的controller中的java代码回针对性的对ptc1进行匹配,然后进行相应。但是这种分析是徒劳的,因为下图所示的所有包以及其中的java文件都是不公开的,而且也实在太多了。
_
以上分析说明,妄图去浩如烟海的java类中找到对ptc1这个字符串匹配的后续的service dao的处理代码,是徒劳的。
而且即使分析出ptc1字符串的处理代码,也是舍本求末,因为老大,你自己的二次开发代码压根没有主动向带有ptc1的url地址发送请求,你首先要搞清楚你的页面为什么会指向带有ptc1字样的url

所以我们继续分析web.xml文件,找到了如下代码:

  <filter>
    <description>Filter for converting Netmarkets URL's with 7.0 or 8.0 JSP's names to URL's having 10.0 JSP's names.</description>
    <filter-name>NetmarketsRedirectFilter</filter-name>
    <filter-class>com.ptc.core.components.filter.NetmarketsRedirect</filter-class>
  </filter>
    <filter-mapping>
    <filter-name>NetmarketsRedirectFilter</filter-name>
    <url-pattern>/netmarkets/jsp/*</url-pattern>
  </filter-mapping>

上述代码说明,web.xml中为Windchill配置了filter
只要主动访问windchill下/netmarkets/jsp/这个目录下的http request都会被com.ptc.core.components.filter.NetmarketsRedirect这个filter过滤一下
那我们最初关注的url哈记得是什么样子吗?就是Windchill中通过配置文件二次开发的按钮,我们看看
_
可以很清楚的看到,我们自己配置的url是:

url="/netmarkets/jsp/bplead/drawingApproval/drawingApproval.jsp?type=edit"

也就是我们主动访问的/netmarkets/jsp/目录下的地址
那么依据web.xml文件中filter的配置,这个request一定会被com.ptc.core.components.filter.NetmarketsRedirect这个filter过滤一下
下面我们看看这个filter的内容
_
_
_
如上图所示,web.xml文件中将NetmarketsRedirect类注册为url特征为/netmarkets/jsp/*的filter。ptc自行实现了Filter名为JCAFilter,而NetmarketsRedirect类是JCAFilter的子类。
当/netmarkets/jsp/*类型的url被web.xml文件中注册的filter过滤后,依据filter的规则,会调用NetmarketsRedirect类的dofilter()方法,由于NetmarketsRedirect类是JCAFilter的子类,因此就会调用它的dofilter()方法,如下图:

public abstract class JCAFilter implements Filter{

public void doFilter(ServletRequest paramServletRequest, ServletResponse paramServletResponse, FilterChain paramFilterChain)
    throws IOException, ServletException
  {
    paramServletRequest.setCharacterEncoding("UTF-8");
    paramServletResponse.setContentType("text/html; charset=UTF-8");
    
    if ((!(paramServletRequest instanceof HttpServletRequest)) || (!(paramServletResponse instanceof HttpServletResponse))) {
      log.debug("Request/Response was not HttpServlet");
      paramFilterChain.doFilter(paramServletRequest, paramServletResponse);
      return;
    }
    if (log.isDebugEnabled()) {
      log.debug("Requested " + ((HttpServletRequest)paramServletRequest).getRequestURL());
    }
    HttpServletRequest localHttpServletRequest = (HttpServletRequest)paramServletRequest;
    //
    String str = getURLForRedirect(localHttpServletRequest);
    
    }//doFilter()方法结束
    
    //父类中只有一个抽象方法,NetmarketsRedirect类继承后再实现
  protected abstract String getURLForRedirect(HttpServletRequest paramHttpServletRequest);
  
  public void destroy() {}
  
  public void init(FilterConfig paramFilterConfig)
    throws ServletException
  {}
    
    }//JCAFilter类结束

上述代码是JCAFilter类的部分代码,可以看到doFilter()方法的核心就是调用getURLForRedirect()方法。
那么NetmarketsRedirect类中getURLForRedirect()方法的内容是怎样的呢?

public class NetmarketsRedirect
  extends JCAFilter
{
  @SuppressWarnings(value={"BC_IMPOSSIBLE_CAST"}, justification="String[] portletValues = (String[])qs.get(NmContextBean.PORTLET) is possible cast becuase, the map adds string array as value")
  protected String getURLForRedirect(String paramString1, String paramString2, String paramString3)
  {
    String str1 = null;
    
    if ((paramString1.contains("ptc1")) || (paramString1.contains("app/#"))) {
      log.debug("No redirect, the url is already an X-20 style");
      return null;
    }
    if (!paramString1.endsWith(".jsp")) {
      log.debug("No redirect, this filter doesn't handle cases that don't end with \".jsp\"");
      return null;
    }
    
    if (paramString1.endsWith("/work/list.jsp")) {
      log.debug("Home -> Assignments");
      str1 = getNewURL("work/listAssignments", paramString2);
    } else if (paramString1.endsWith("/netmarkets/overview.jsp")) {
      log.debug("Home Overview");
      
      str1 = getNewURL("homepage", null);
    } else if (paramString1.endsWith("/events/list_mine.jsp")) {
      log.debug("Home -> Meetings");
      str1 = getNewURL("meeting/list_mine", paramString2);
    } else if (paramString1.endsWith("/subscription/list.jsp")) {
      log.debug("Home -> Subscriptions");
      str1 = getNewURL("subscription/listSubscriptions", paramString2);
    } else if ((paramString1.endsWith("/work/listProduct.jsp")) || (paramString1.endsWith("/work/listProduct2.jsp"))) {
      log.debug("Product -> Assignments");
      str1 = getNewURL("work/listProductAssignments", paramString2);
    } else if (paramString1.endsWith("listFiles.jsp")) {
      log.debug("Folder Browser listFiles.jsp");
      HashMap localHashMap = NmURLFactoryBean.parseQueryString(paramString2);
      
      String[] arrayOfString = (String[])localHashMap.get("portlet");
      String str2 = arrayOfString == null ? null : arrayOfString[0];
      if (!"component".equals(str2)) {
        str1 = getNewURL(NmURLFactoryBean.relativizeUrl(paramString1, false), paramString2);
      }
    } else if ((paramString1.endsWith("/folder/view.jsp")) || (paramString1.endsWith("/project/view.jsp"))) {
      log.debug("Folder Info Pages");
      str1 = null;
      
      if (paramString3.indexOf("PDMLinkProduct") > 0) {
        log.debug("Product -> Folder Info Page");
        str1 = getNewURL("product/listFiles", paramString2);
      } else if (paramString3.indexOf("Project2") > 0) {
        log.debug("Project -> Folder Info Page");
        str1 = getNewURL("project/listFiles", paramString2);
      } else if (paramString3.indexOf("WTLibrary") > 0) {
        log.debug("Library -> Folder Info Page");
        str1 = getNewURL("library/listFiles", paramString2);
      } else if (paramString3.indexOf("SubFolder") > 0) {
        log.debug("Folder Info Page");
        str1 = getInfoPageURL(paramString2);
      } else {
        log.debug("This case is not covered. Do not redirect.");
        return null;
      }
    } else if (paramString1.endsWith("/project/list3.jsp")) {
      log.debug("Project -> Project List (7.0 only)");
      str1 = getNewURL("project/list", null);
    } else if (paramString1.endsWith("/projectResource/list.jsp")) {
      log.debug("Project -> Resources (7.0 only)");
      str1 = getNewURL("project/listProjectResource", paramString2);
    } else if (paramString1.endsWith("/work/listProject.jsp")) {
      log.debug("Project -> Assignments");
      str1 = getNewURL("work/listProjectAssignments", paramString2);
    } else if (paramString1.endsWith("/report/projectReport.jsp")) {
      log.debug("Project -> Reports (7.0 only)");
      str1 = getNewURL("project/reports", paramString2);
    } else if (paramString1.endsWith("/wtcore/jsp/com/ptc/windchill/search/ExecuteSearch.jsp")) {
      log.debug("All -> Search");
      str1 = getNewURL("search/executeSearch?", null);
    } else if (paramString1.endsWith("/change/list3.jsp")) {
      log.debug("Change -> Problem Reports");
      str1 = getNewURL("change/list", null);
    } else if (paramString1.endsWith("/change/listChangeRequests2.jsp")) {
      log.debug("Change -> Change Requests");
      str1 = getNewURL("change/listChangeRequests", null);
    } else if (paramString1.endsWith("/change/listChangeNotices2.jsp")) {
      log.debug("Change -> Change Notices");
      str1 = getNewURL("change/listChangeNotices", null);
    } else if ((paramString1.endsWith("/work/listLibrary.jsp")) || (paramString1.endsWith("/work/listLibrary2.jsp"))) {
      log.debug("Library -> Assignments");
      str1 = getNewURL("work/listLibraryAssignments", paramString2);
    } else if (paramString1.endsWith("/library/list2.jsp")) {
      log.debug("Library -> Libraries List");
      str1 = getNewURL("library/list", paramString2);
    } else if (paramString1.endsWith("/site/listOrgs.jsp")) {
      log.debug("Site -> Organizations");
      str1 = getNewURL("org/listOrgs?tab=org", null);
    } else if (paramString1.endsWith("/org/view.jsp")) {
      log.debug("Org info page");
      str1 = getNewURL("org/details", paramString2);
    } else if ((paramString1.endsWith("/view.jsp")) && (
      (paramString1.endsWith("/part/view.jsp")) || (paramString1.endsWith("/document/view.jsp")) || 
      (paramString1.endsWith("/bookmark/view.jsp")) || (paramString1.endsWith("/milestone/view.jsp")) || 
      (paramString1.endsWith("/projectActivity/view.jsp")) || 
      (paramString1.endsWith("/summaryActivity/view.jsp")) || 
      (paramString1.endsWith("/projectProxy/view.jsp")) || (paramString1.endsWith("/meeting/view.jsp")) || 
      (paramString1.endsWith("/actionitem/view.jsp")) || (paramString1.endsWith("/epmdocument/view.jsp")))) {
      log.debug("Project Link info pages");
      
      str1 = getInfoPageURL(paramString2);
    } else {
      log.debug("This URL doesn't contain an oid, so we don't need to do anything.");
      return null;
    }
    return str1;
  }

上述代码其实调用了很多ptc自己封装的内容,至于具体这个filter到底做了什么,对url做了什么处理,我们编写测试代码查看一下。
我们修改web.xml配置1个单独的filter然后配置1个自定义的servlet
然后我们用浏览器访问servlet和filter对应的url,这样,我们在filter的代码中再现NetmarketsRedirect类的语句以及它引用的语句,这样我们就能搞清楚,Windchill中所谓重定向,在搞什么鬼了。
我们在自己的eclipse上的windchill项目上测试servlet和filter
_
_
_
_
在eclipse中创建servlet后,eclipse会帮助你在web.xml文件自动添加相关代码:
_
这并非我们想要的,所以修改一下:
_
servlet中的核心方法的代码如下:

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        response.getWriter().append("Served at: ").append(request.getContextPath());
    }

我们先测试一下效果:
_
说明servlet正常运行
下面创建一个filter

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
Canal binlog 日志 Dump 流程分析
Canal binlog 日志 Dump 流程分析
112 0
【译】Javascript中你需要知道的最出色的新特性:Optional Chaining
对于使用Javascript的每个人来说,可选链(Optional chaining)是游戏的规则的改变者。它与箭头函数或let和const一样重要。我们讨论下它可以解决什么问题,它如何工作,以及它如何使得你的生活更加轻松。
24 0
如何将bing搜索页面以HTML Mashup的方式嵌入到SAP C4C页面
创建一个HTML mashup,port binding选择Lead Info:
39 0
C#将DLL嵌入到exe当中
原文:C#将DLL嵌入到exe当中 一、将dll文件加入工程 1.找到dll文件 可以在项目的“引用”下找到dll,并且根据属性中的“路径”找到文件所在目录;也可以使用bin目录下自动生成(其实就是复制)的dll文件  这里需要注意,“引用”下的dll,需要设置“复制本地”为False,这样在bin目录下生成exe的时候就不会顺便复制dll了(感觉这步可要可不要)。
1822 0
[Servlet&JSP] 过滤器的使用
过滤器介于Servlet之前,可拦截过滤浏览器对Servlet的请求,也可以改变Servlet对浏览器的响应。 过滤器的概念 像性能测量、用户验证、字符替换、压缩等需求,应该设计为独立的组件,随时可以添加到应用程序之中,也可以随时移除,而不用修改原有的程序。Servlet/JSP提供了过滤器机制以实现这些组件服务,可视需求抽换过滤器或调整过滤器的顺序,也可以针对不同的
1340 0
如何将松散的dll打包进需要发布的exe
原文:如何将松散的dll打包进需要发布的exe     我们需要发布的exe文件很多时候都可能会依赖于一堆松散的dll,如果想在发布的时候只提供exe文件,而不想把一大堆dll一起放在和exe同一个文件夹下,是有方法的,该方法由CLR via C#作者提出,我在实践的过程中遇到的几点问题,现在记录下总体的流程和该注意的事项。
2796 0
Csharp:TinyMCE HTML Editor in .NET WindowsForms
/// <summary> /// /// </summary> public partial class Form2 : Form { private mshtml.IHTMLDocument2 hc; private mshtml.HTMLDocument hc1; /
994 0
+关注
159
文章
3
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载