zoukankan      html  css  js  c++  java
  • (七)Action之ActionContext(OGNL表达式的使用)

    一、ActionContext的重要性

    • struts中的数据都存放在ActionContext里,所以这部分是Action中的核心。
    •  ActionContext又称广义值栈,既然有广义值栈就有侠义值栈。

        1.广义值栈,指的是ActionContext对象,是Action运行的上下文,包含着request、session、application、attr、parameters、和侠义值栈(Value Stack)等。以后说值栈的时候默认指的就是广义值栈。

        2.侠义值栈,ActionContext以侠义值栈作为被OGNL访问的根,在没有特别指明(即用#打头)情况下,默认访问的的侠义值栈的数据。

    二、ActionContext组成

    • 分为上述六大块。
    • 用代码查看上述ActionContext结构
    • index.jsp
    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <%String path=request.getContextPath(); %>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Insert title here</title>
    </head>
    <body>
        <a href="<%=path%>/action/actioncontext">查看ActionContext结构内容</a>
    </body>
    </html>
    • struts.xml
    <struts>
        <constant name="struts.enable.DynamicMethodInvocation" value="true" />
        <constant name="struts.devMode" value="true" />
    
        <package name="default" namespace="/action" extends="struts-default">
            <action name="actioncontext" class="action.ActionContext_1">
                <result name="actionContext">/actionContext.jsp</result>
            </action>
        </package>
    </struts>
    • ActionContext_1.java, 执行成功返回到<result name="actionContext">/actionContext.jsp</result>页面,我
    package action;
    
    public class ActionContext_1 {
        public String execute()
        {
      /**
      *我们在ActionContext的request里存放一个值
      */
        request.setAttribute("hello", "world");
    return "actionContext"; } }
    • actionContext.jsp
    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
     <%@ taglib prefix="s" uri="/struts-tags" %>
    <!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>Insert title here</title>
    </head>
    <body>
        <s:debug></s:debug>
    </body>
    </html>
    •  <s:debug></s:debug>标签用于显示ActionContext的结构内容。

    结果:


     三、ActionContext各组成部分简介

      3.1 值栈(ValueStack)位于最顶端,即上图的:

    • a上述例子中的ction包的ActionContext_1类的对象引用存放在这里。

      3.2 其他5个组成部分(request、session、application、attr、parameters)存在值栈的下方。


    四、取出ActionContext中的数据(使用OGNL表达式)

      4.1  如果要取出valueStack值栈中的值,直接<s:property  value="值栈中的变量名"/> 即可。

      4.2  如果要取出非valueStack值栈中的值,就得用<s:property  value="#非值栈中的变量名"/>才能获取,而"#变量名" 这种表达方法为OGNL表达式。

      4.3  示例(上述例子在ActionContext_1.java中我们对request设置了一个值"hello"="world",现在我们把它取出来):

    •  除了actionContextjsp页面外其他文件均与上述例子一样。 actionContextjsp:
    <body>
        <pre>
            <h3>用debug标签显示ActionContext结构</h3>
            <s:debug></s:debug>
            <h3>取出ActionContext中的值</h3>
            <s:property value="#request.hello"/>
    
        </pre>
    </body>

    结果:



    五、OGNL表达式

       5.1  OGNL表达式的特点

       5.2  OGNL表达式的使用:


    # 符号的用法
    • 获得context中的数据
    1. <s:property value="#request.name"/>  
    2. <s:property value="#session.name"/>  
    3. <s:property value="#application.name"/>  
    4. <s:property value="#attr.name"/>  
    5. <s:property value="#parameters.id"/>  
    6. <s:property value="#parameters.name"/>  
    • 构建一个map集合
    1. <%-- list --%>  
    2. <s:radio name="sex" list="{'男','女'}"></s:radio>  
    3. <%-- map --%>  
    4. <s:radio name="sex" list="#{'0':'男','1':'女'}"></s:radio>  

    % 符号的用法
    • 强制字符串解析成OGNL表达式。
    例如:在request域中存入值,然后在文本框(<s:textfield>)中取值,写在value里。
    1. <s:textfield value="%{#request.msg}"/>  

     

    • { }中值用引号引起来,此时不再是ognl表达式,而是普通的字符串,到底使用单引号还是双引号是由外层引号决定的。
    1. <s:property value="%{'#request.msg'}"/>  

    $ 符号的用法

         在配置文件中可以使用OGNL表达式,例如:文件下载的配置文件。EL表达式也是使用$

      1. <action name="download1" class="cn.itcast.demo2.DownloadAction">  
      2.      <result name="success" type="stream">  
      3.           <param name="contentType">${contentType}</param>  
      4.           <param name="contentDisposition">attachment;filename=${downFilename}</param>  
      5.      </result>  
      6. </action

      5.2.1  访问成员变量和成员方法

    •   成员变量和成员方法都是存放在侠义值栈里的,可以直接访问。
    •   成员方法不现实在侠义值栈里,但是也可以直接访问。
      •   index.jsp
    <body>
        <a href="<%=path%>/action/actioncontext">OGNL访问成员变量和成员方法</a>
    </body>
      •   struts.xml
    <struts>
    
        <constant name="struts.enable.DynamicMethodInvocation" value="true" />
        <constant name="struts.devMode" value="true" />
    
        <package name="default" namespace="/action" extends="struts-default">
            <action name="actioncontext" class="action.ActionContext_1">
                <result name="actionContext">/actionContext.jsp</result>
            </action>
        </package>
    </struts>
      •   ActionContext_1.java
    package action;
    
    import actionUtil.BaseAction;
    /**
     * OGN表达式访问成员变量和成员方法
     * @author hj
     *
     */
    
    public class ActionContext_1 extends BaseAction{  //BaseAction类提供了servlet的原生对象
        private String userName="张三";  //成员变量并设值
        
        public int add(int x,int y){    //成员方法
            return x+y;    
        }
        public String getUserName() {
            return userName;
        }
        public void setUserName(String userName) {
            this.userName = userName;
        }
    
    
        public String execute()
        {
            return "actionContext";
    
        }
    }
      •   actionContext.jsp
    <body>
        <pre>
            <h3>用debug标签显示ActionContext结构</h3>
            <s:debug></s:debug>
            <h3>OGNL访问成员变量和成员方法</h3>
            userName=<s:property value="userName"/>   
            年龄=<s:property value="add(10,25)"/>
        </pre>
    </body>

     结果:


      5.2.2  访问静态变量和静态方法(访问静态方法的功能在struts高版本被取消,无法使用)

    • 访问静态变量语法:<s: property  value="@完整包名@静态变量名"/> 如 <s:property value="@actionUtil.StaticClass@PI"/> 表示输出actionUtil包下的StaticClass类中的PI静态变量。
    • 访问静态方法语法与上面类似。

      5.2.3  访问集合

    • index.jsp
    <body>
        <a href="<%=path%>/action/actioncontext">OGNL访问集合</a>
    </body>
    • struts.xml
    <struts>
    
        <constant name="struts.enable.DynamicMethodInvocation" value="true" />
        <constant name="struts.devMode" value="true" />
    
        <package name="default" namespace="/action" extends="struts-default">
            <action name="actioncontext" class="action.ActionContext_1">
                <result name="actionContext">/actionContext.jsp</result>
            </action>
        </package>
    </struts>
    • ActionContext_1.java(集合的定义与初始化)
    package action;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    import actionUtil.BaseAction;
    import bean.UserBean;
    /**
     * OGNL表达式访问集合Set/List/Map
     * @author hj
     *
     */
    
    public class ActionContext_1 extends BaseAction{
        
        private Set<String> strSet;
        private List<UserBean> list;
        private Map<String,Object> map;
        
        public Set<String> getStrSet() {
            return strSet;
        }
        public void setStrSet(Set<String> strSet) {
            this.strSet = strSet;
        }
        public List<UserBean> getList() {
            return list;
        }
        public void setList(List<UserBean> list) {
            this.list = list;
        }
        public Map<String, Object> getMap() {
            return map;
        }
        public void setMap(Map<String, Object> map) {
            this.map = map;
        }
    
    
        public String execute()
        {
            //set集合的初始化
            this.strSet=new HashSet<String>();
            this.strSet.add("a");
            this.strSet.add("b");
            this.strSet.add("c");
                //List的初始化
            this.list=new ArrayList<UserBean>();
            for(int i=0;i<4;i++){
                UserBean user=new UserBean(i+1,"姓名"+i);
                list.add(user);
            }
            //Map的初始化
            this.map=new HashMap<String,Object>();
            this.map.put("map中的第一个值", "key1");
            this.map.put("map中的第二个值", this.list);
            
    
            return "actionContext";
    
        }
    }
    • actionContext.jsp  (获取广义值栈中的Set、map、list的值)
    <body>
        <pre>
            <h3>用debug标签显示ActionContext结构</h3>
            <s:debug></s:debug>
            <h3>OGNL访问集合</h3>
            set元素共有:<s:property value="strSet"/>
            set长度=<s:property value="strSet.size()" />
            add=<s:property value="strSet.add('d')" />
            set元素共有:<s:property value="strSet"/>
            remova=<s:property value="strSet.remove("b")" />
            set元素共有:<s:property value="strSet"/>
            
            Map
             Map全部值=<s:property value="map"/>
             map中的第一个值:<s:property value="map. map中的第一个值"/>
             map中的第二个值:<s:property value="map.get('map中的第二个值')"/>
             map中的第二个值中的UserBean的userName:<s:property value="map.get('map中的第二个值').get(0).getUserName()"/>
             map中的第二个值中的UserBean的userId::<s:property value="map['map中的第二个值'].get(0).getUserId()"/>
             
             List
                 List全部元素:<s:property value="list"/>
                 list的第一个UserBean的ID:<s:property value="list.get(0).getUserId()"/>
             
        </pre>
    </body>
    • Map中数字开头或者特殊符号要用[]来获取值。例:<s:property value="map['map中的第二个值'].get(0).getUserId()"/>

    结果:

     

    • 注意:

     上述的actionContext.jsp文件中的remova=<s:property value="strSet.remove("b")" />如果没有加“”反斜杠,则该函数调用错误。


      5.2.4  访问作用域中的数据

    • index.jsp
    <body>
        <a href="<%=path%>/action/actioncontext">OGNL访问作用域</a>
    </body>
    • struts.xml
    <struts>
    
        <constant name="struts.enable.DynamicMethodInvocation" value="true" />
        <constant name="struts.devMode" value="true" />
    
        <package name="default" namespace="/action" extends="struts-default">
            <action name="actioncontext" class="action.ActionContext_1">
                <result name="actionContext">/actionContext.jsp</result>
            </action>
        </package>
    </struts>
    • ActionContext_1.java(在这个Action中把值存放到作用域中,以供jsp获取显示)
    package action;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    import actionUtil.BaseAction;
    import bean.UserBean;
    /**
     * OGNL表达式访问作用域中的数据,要用#来获取
     * @author 夏洛克的喵~
     *
     */
    
    public class ActionContext_1 extends BaseAction{
        
    
    
        public String execute()
        {
            request.setAttribute("request_key", "request_value");
            session.setAttribute("session_key", "session_value");
            servletContext.setAttribute("sevletContext_key", "servletContext_value");
    
            return "actionContext";
    
        }
    }
    • actionContext.jsp(在这个页面显示出作用域中的数据)
    <body>
        <pre>
            <h3>用debug标签显示ActionContext结构</h3>
            <s:debug></s:debug>
            <h3>OGNL作用域中的数据</h3>
            request作用域中的数据=<s:property value="#request.request_key"/>
            session作用域中的数据=<s:property value="#session.session_key"/>
            application作用域中的数据=<s:property value="#application.sevletContext_key"/>
        </pre>
    </body>

      5.2.5  访问请求参数

    • 请求参数存放在广义值栈组成部分之一的parameters中。
    • struts封装的作用域,把reuqest、session、servletContext作用域封装成Map,
      所以struts的OGNL表达式在获取请求参数值的时候是并不是调用request.getParameter()或getParameterValues方法 而是调用request.getParameterMap()方法。
      要解决struts2中OGNL获取parameters中请求参数值乱码的问题,只要覆盖request.getParameterMap()方法既可。
    • index.jsp(设置请求参数)
    <body>
        <a href="<%=path%>/action/actioncontext?userId=001&userName=张三">OGNL访问请求参数</a>
    </body>
    • struts.xml
    <struts>
    
        <constant name="struts.enable.DynamicMethodInvocation" value="true" />
        <constant name="struts.devMode" value="true" />
    
        <package name="default" namespace="/action" extends="struts-default">
            <action name="actioncontext" class="action.ActionContext_1">
                <result name="actionContext">/actionContext.jsp</result>
            </action>
        </package>
    </struts>
    • ActionContext_1.java
    package action;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    import actionUtil.BaseAction;
    import bean.UserBean;
    /**
     * @author 夏洛克的喵~
     *
     */
    
    public class ActionContext_1 extends BaseAction{
    
        public String execute()
        {
    
            return "actionContext";
    
        }
    }
    • actionContext.jsp(读取请求参数的值)
    <body>
        <pre>
            <h3>用debug标签显示ActionContext结构</h3>
            <s:debug></s:debug>
            <h3>OGNL访问请求参数</h3>
            请求参数中的为userId=<s:property value="#parameters.userId"/>
            请求参数中的userName=<s:property value="#parameters.userName"/>
        </pre>
    </body>
    • EncodingFilter.java(编码过滤器)
    package filter;
    
    import java.io.IOException;
    import java.io.UnsupportedEncodingException;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletRequestWrapper;
    import javax.servlet.http.HttpServletResponse;
    
    
    
    /**
     * 此过滤器用于解决get和post请求中问乱码的问题。
     */
    public class EncodingFilter implements Filter {
    
        public EncodingFilter() {
          
        }
    
        public void destroy() {
            
        }
    
    /**
     *     要解决乱码问题首先区别对待POST方法和GET方法,
     *     1.如果是POST方法,则用request.setCharacterEncoding("UTF-8"); 即可
     *     2.如果是GET方法,则麻烦一些,需要用decorator设计模式包装request对象来解决
     */
        public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
             HttpServletRequest request=(HttpServletRequest)req;
             HttpServletResponse response=(HttpServletResponse)res;
            
    
             //获取request请求是get还是post
             String method=request.getMethod();
            
             if(method.equals("GET") || method.equals("get")){  //注意大小写都要判断,一般来说是大写的GET
                 /**
                  * request请求为get请求,则用包装类对request对象的getParameter方法进行覆盖。
                  */
                 response.setContentType("text/html;charset=UTF-8");
                 MyGetHttpServletRequestWrapper requestWrapper=new MyGetHttpServletRequestWrapper(request);
                 chain.doFilter(requestWrapper, response); 
                
                 
             }else{
                 //post请求
                  response.setContentType("text/html;charset=UTF-8");
                 request.setCharacterEncoding("UTF-8");
                 chain.doFilter(request, response); 
                
             }
    
        }
    
        public void init(FilterConfig fConfig) throws ServletException {
        }
    
    }
    
    
    class MyGetHttpServletRequestWrapper extends HttpServletRequestWrapper{
    
            HttpServletRequest request;
        public MyGetHttpServletRequestWrapper(HttpServletRequest request) {
            super(request);
            this.request=request;
            
        }
    
        /**
         *       servlet API中提供了一个request对象的Decorator设计模式的默认实现类HttpServletRequestWrapper,
         *               (HttpServletRequestWrapper类实现了request接口中的所有方法,但这些方法的内部实现都是仅仅调用了一下所包装的的
         *               request对象的对应方法) 以避免用户在对request对象进行增强时需要实现request接口中的所有方法。
         *               所以当需要增强request对象时,只需要写一个类继承HttpServletRequestWrapper类,然后在重写需要增强的方法即可
         * 具体步骤:
          *1.实现与被增强对象相同的接口 
          *2、定义一个变量记住被增强对象
         *3、定义一个构造函数,接收被增强对象 4、覆盖需要增强的方法 5、对于不想增强的方法,直接调用被增强对象(目标对象)的方法
         */
        
        @Override
        public String getParameter(String name) {
        
            String old_value=super.getParameter(name);
            String new_value=null;
            
            if(old_value!=null && !old_value.equals("")){
                try {
                    new_value=new String(old_value.getBytes("ISO-8859-1"),"UTF-8");
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
                
            }
            
            return new_value;
        }
    
        @Override
        public String[] getParameterValues(String name) {
            
            String[] old_value=request.getParameterValues(name);
            String[] new_value=new String[old_value.length];
            
            if(old_value!=null && !old_value.equals("")){
                String temp_value=null;
                for(int i=0;i<old_value.length;i++){
                    try {
                        temp_value=new String(old_value[i].getBytes("ISO-8859-1"),"UTF-8");
                        new_value[i]=temp_value;
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                    }
                    
                }
                
            }
            
            return new_value;
        }
    
        /**
         * 使用struts封装的作用域,把reuqest、session、servletContext作用域封装成Map,
         * 所以struts的OGNL表达式在获取请求参数值的时候是并不是调用request.getParameter()或getParameterValues方法
         * 而是调用request.getParameterMap()方法。
         * 要解决struts2中OGNL获取parameters中请求参数值乱码的问题,只要覆盖request.getParameterMap()方法既可。
         */
        @Override
        public Map getParameterMap() {
            try {
                if (!this.request.getMethod().equals("GET")) {// 判断是否是get请求方式,不是get请求则直接返回
                    return this.request.getParameterMap();
                }
    
                Map<String, String[]> map = this.request.getParameterMap(); // 接受客户端的数据
                Map<String, String[]> newmap = new HashMap();
                for (Map.Entry<String, String[]> entry : map.entrySet()) {
                    String name = entry.getKey();
                    String values[] = entry.getValue();
    
                    if (values == null) {
                        newmap.put(name, new String[] {});
                        continue;
                    }
                    String newvalues[] = new String[values.length];
                    for (int i = 0; i < values.length; i++) {
                        String value = values[i];
                        value = new String(value.getBytes("iso8859-1"), this.request.getCharacterEncoding());
                        newvalues[i] = value; // 解决乱码后封装到Map中
                    }
    
                    newmap.put(name, newvalues);
                }
    
                return newmap;
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        
    }

    结果:

    • 注意: 虽然OGNL表达式取值并非通过request.getParameter()或者getParameterValues()方法,但是El表达式确实通过这两种方法取值。

      5.2.6  访问valueStack广义值栈和操作valueStack广义值栈

    5.2.6.1
    •  读取、修改狭义值栈中的值。

    • 要修改狭义值栈中的值,首先要获得ValueStack狭义值栈对象,这个对象封装了一系列的方法可以来操作这个狭义值栈。 方法如下:

        A、 ValueStack.set()  //新增狭义值栈中的属性与值并产生一个新的Object为java.util.HashMap

        B、 ValueStack.setValue()  //修改狭义值栈中的值。

        C、 valueStack.push()  //往栈顶压入一个对象,这里的对象为java.util.LinkedHashMap

    • index.jsp
    <body>
        <a href="<%=path%>/action/actioncontext">OGNL访问valueStack狭义值栈和操作valueStack狭义值栈</a>
    </body>
    • struts.xml
    <struts>
    
           <constant name="struts.i18n.encoding" value="UTF-8"></constant>
        <constant name="struts.multipart.maxSize" value="209715200"></constant>
        <constant name="struts.action.extension" value="action,,"></constant>
        <constant name="struts.enable.DynamicMethodInvocation" value="true" />
        <constant name="struts.devMode" value="true" />
        <constant name="struts.i18n.reload" value="true"></constant>
        <constant name="struts.ui.theme" value="xhtml" />
        <constant name="struts.configuration.xml.reload" value="true"></constant>
        <constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant>
        <constant name="struts.handle.exception" value="true"></constant>
    
        <package name="default" namespace="/action" extends="struts-default">
            <action name="actioncontext" class="action.ActionContext_1">
                <result name="actionContext">/actionContext.jsp</result>
            </action>
        </package>
    • ActionContext_1.java
    package action;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.LinkedHashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    import com.opensymphony.xwork2.ActionContext;
    import com.opensymphony.xwork2.util.ValueStack;
    
    import actionUtil.BaseAction;
    import bean.UserBean;
    /**
     * 访问狭义值栈与操作狭义值栈
     * 步骤:
     * 获取ActionContext对象,ActionContext对象再获取ValueStack值栈。
     * @author 夏洛克的喵~
     */
    
    public class ActionContext_1 extends BaseAction{
    
        public String execute()
        {
            ActionContext actionContext=ActionContext.getContext();
            ValueStack valueStack=actionContext.getValueStack();
            
            valueStack.set("userName", "张三"); //新增狭义值栈中的属性与值,在狭义值栈中产生新的Object为java.util.HashMap
            valueStack.set("userName2", "傻逼"); 
            valueStack.setValue("userName2", "你才是傻逼"); //修改狭义值栈中某一个属性的值
            Map<String,String> m=new LinkedHashMap<String,String>();
            m.put("map_key", "map_value");
            valueStack.push(m);  //往栈顶压入一个对象,这里的对象为java.util.LinkedHashMap
            return "actionContext";
    
        }
    }
    • actionContext.jsp
    <body>
        <pre>
            <h3>用debug标签显示ActionContext结构</h3>
            <s:debug></s:debug>
            <h3>OGNL访问valueStack狭义值栈和操作valueStack狭义值栈</h3>
            userName=<s:property value="userName"/>
            修改后的userName2=<s:property value="userName2"/>
            
            栈顶元素=<s:property value="map_key"/>
            
        </pre>
    </body>

    结果:

    • 注意狭义值栈中的属性名可以重复,如果取值越靠近栈顶的被取到。

    比如上图中的java.util.LinkedHashMap有一个属性为userName=“张三”而java.util.HashMap有一个属性为userName=“李四”,此时LinkedHashMap靠近栈顶,所以如果

    <s:property value="userName"/> 取到的值为:张三 。栈的排序原理为:先进后出。 如果想要取到HashMap中的userName的值的话,可以用<s:property value="[1].userName"/>

     [1].userName表示狭义值栈中的第二个对象的userName属性

    • 值栈中最好不要出现属性名相同的属性。
    5.2.6.2  访问非侠义值栈和操作非狭义值栈
    • 操作非狭义值栈可以用ActionContext类的put()方法往非侠义值栈添加对象。

    如:

    ActionContext actionContext=ActionContext.getContext();
            actionContext.put("userName", "libai");

    获取这个对象:

    <s:property value="#userName"/>
  • 相关阅读:
    Linux基础--安装搭建tomcat+java+mysql
    使用ArcGIS JavaScript API 3.18 加载天地图
    关于ArcGIS的Web 3D GIS问答
    ArcGIS 10.5新功能预览
    如何选择合适分辨率的遥感影像
    如何正确响应ArcGIS JavaScript API中图形的鼠标事件
    安装Portal for ArcGIS时如何正确配置HTTPS证书
    ArcGIS地图文档优化 mxdPerfstat工具使用体验
    Web AppBuilder Widget使用共享类库的方式
    如何通过ArcMap Add-in机制实现十字叉线地理配准工具
  • 原文地址:https://www.cnblogs.com/shyroke/p/6560043.html
Copyright © 2011-2022 走看看