zoukankan      html  css  js  c++  java
  • Struts2学习(七)

    Servlet实现下载

    1、Servlet 3.1之前实现文件上传

    package ecut.request;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    public class FirstUploadServlet extends HttpServlet {
    
        private static final long serialVersionUID = -7777691027208490971L;
    
        @Override
        protected void doGet( HttpServletRequest request , HttpServletResponse response ) throws ServletException, IOException {
            throw new RuntimeException( "不支持GET方式上传" );
        }
    
        @Override
        protected void doPost( HttpServletRequest request , HttpServletResponse response ) throws ServletException, IOException {
            
            request.setCharacterEncoding( "UTF-8" );
            
            // 上传文件时,只考虑文本文件,不考虑其它文件
            BufferedReader reader = request.getReader();
            //InputStream in = request.getInputStream();
    
            String s ; 
            while( ( s = reader.readLine() ) != null ){
                System.out.println( s );
            }
            
        }
        
        
    
    }

    2、Servlet 3.1 开始实现文件上传

    package ecut.request;
    
    import java.io.IOException;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.Part;
    
    public class SecondUploadServlet extends HttpServlet {
    
        private static final long serialVersionUID = 4485463572490572537L;
    
        @Override
        protected void doGet( HttpServletRequest request , HttpServletResponse response ) throws ServletException, IOException {
            throw new RuntimeException( "不支持GET方式上传" );
        }
    
        @Override
        protected void doPost( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException {
            
            // String username = request.getParameter( "username" ) ; // <input type="text" name="username" >
            
            Part part = request.getPart( "upfile" ) ; // <input type="file" name="upfile" >
            System.out.println( part );
            
            /* Servlet 3.0 中获得文件名的做法
            String cd = part.getHeader( "Content-Disposition" );
            System.out.println( cd );
            String s = "filename=""; 
            int index = cd.indexOf( s );//找到filename的位置
            String name = cd.substring( index + s.length() , cd.length() - 1 );//获取文件名
            System.out.println( name );
            */
            
            // part.getName() ; // name="upfile"
            String filename = part.getSubmittedFileName(); // Servlet 3.1 开始出现的方法
            
            part.write( filename );
            
        }
        
        
    
    }

    Struts2实现下载

    1、首先在配置文件中指定存储位置storePath,在配置文件中action标签中通过 param 为 当前的 Action 实例 指定一个参数 ,实际上是 Action 类中的一个 属性 。

    <?xml version="1.0" encoding="UTF-8"?>
    
    <!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
        "http://struts.apache.org/dtds/struts-2.5.dtd">
    
    <struts>
    <package name="upload" namespace="/upload" extends="struts-default" >
        
           <action name="action/single" class="ecut.upload.SingleFileUploadAction" >
               <!-- 通过 param 为 当前的 Action 实例 指定一个参数 ( 实际上是 Action 类中的一个 属性 ) -->
               <param name="storePath">D:/</param>
               
               <result name="success" type="redirectAction">
                   <param name="actionName">success/single</param>
               </result>
                <result name="fail" type="redirectAction">
                   <param name="actionName">fail/single</param>
               </result>
    </action> </struts>

    2、struts.xml中的包继承了struts-default包,struts-default包中指定了默认的拦截器栈,里面有一个fileUpload interceptor,Struts 2实现文件上传就是由这个拦截器来实现的。所以在struts.xml中最好先引用一下默认拦截器。

    3、参照fileUpload interceptor api 的完成Action类的编写,由图中可知需要添加以下参数

    • [File Name] : File - 实际文件名,和页面的文件名相对应,表单中是xxx,则Action类中也要有xxx属性,且名称保持一致
    • [File Name]ContentType : String - 文件的内容类型,命名前缀得和文件名称保持一致,xxxContentType
    • [File Name]FileName : String -上传文件的实际名称,命名前缀得和文件名称保持一致,xxxFileName 

    Jsp代码:

    <%@ page language = "java" pageEncoding = "UTF-8" %>
    <%@ page contentType = "text/html; charset= UTF-8"%>
    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Struts Upload</title> </head> <body> <h5>文件上传</h5> <!-- method 必须是 POST ,enctype 必须是 multipart/form-data --> <form action="${ pageContext.request.contextPath }/upload/action/single" method="post" enctype="multipart/form-data"> <input type="file" name="upload" > <input type="submit" value="上传" > </form> </body> </html>

     Action类代码:

    package ecut.upload;
    
    import java.io.File;
    import java.nio.file.Files;
    import java.nio.file.Path;
    import java.nio.file.Paths;
    import java.nio.file.StandardCopyOption;
    
    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    
    import com.opensymphony.xwork2.Action;
    
    public class SingleFileUploadAction implements Action {
        
        private static Logger logger = LogManager.getLogger();
        //保存文件的位置,上传文件到那个目录
        private String storePath ;
        // [File Name] : File - the actual File,与表单中的name保持一致
        private File upload ; 
        // [File Name]ContentType : String - the content type of the file,文件内容类型
        private String uploadContentType ; 
        // [File Name]FileName : String - the actual name of the file uploaded (not the HTML name),实际的文件名
        private String uploadFileName ;
    
        @Override
        public String execute() throws Exception {
            //临时文件
            logger.info( "upload : " + upload );
            logger.info( "content type : " + uploadContentType );
            logger.info( "file name : " + uploadFileName );
            
            //getCanonicalPath获取规范化路径
            Path source = Paths.get( upload.getCanonicalPath() );
            
            Path target = Paths.get( this.storePath , uploadFileName );
            
            //Replace an existing file if it exists.
            Files.copy( source , target , StandardCopyOption.REPLACE_EXISTING );
            
            return SUCCESS;
        }
    
        public String getStorePath() {
            return storePath;
        }
    
        public void setStorePath(String storePath) {
            this.storePath = storePath;
        }
    
        public File getUpload() {
            return upload;
        }
    
        public void setUpload(File upload) {
            this.upload = upload;
        }
    
        public String getUploadContentType() {
            return uploadContentType;
        }
    
        public void setUploadContentType(String uploadContentType) {
            this.uploadContentType = uploadContentType;
        }
    
        public String getUploadFileName() {
            return uploadFileName;
        }
    
        public void setUploadFileName(String uploadFileName) {
            this.uploadFileName = uploadFileName;
        }
        
    }

    Struts2  上传文件是先生成一个临时文件保存在临时目录下,上传成功后临时文件消失。

    4、上传默认的最大尺寸是,在 default.properties 中默认定义的大小是 2MB ,修改默认上传最大尺寸可以在xml中配置,可以指定全局的常量,也可以在action标签中设置某个action最大上传尺寸(struts.multipart.maxSize >= fileUpload.maximumSize )。

    struts.xml

    <?xml version="1.0" encoding="UTF-8"?>
    
    <!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
        "http://struts.apache.org/dtds/struts-2.5.dtd">
    
    <struts>
    
        <!-- 允许在 action 的 名称 中使用 / 字符  -->
         <constant name="struts.enable.SlashesInActionNames" value="true" />
        <!-- 启用动态方法调用  <constant name="struts.enable.DynamicMethodInvocation" value="true" /> -->
        
        <!-- 修改 action 请求路径的后缀 -->
        <constant name="struts.action.extension" value="do,," />
        <!-- 解析器的作用是对request.getInputStream()返回的字节流进行解析获取文件内容、类型、名称(和resultType="stream" 实现下载原理一致) -->
        <!-- 指定 对上传的 字节流进行解析的解析器 : jakarta 、cos 、pell -->
        <constant name="struts.multipart.parser" value="jakarta" />
        <!-- 指定上传文件的尺寸 ( 在 default.properties 中默认定义的大小是 2MB )-->
        <constant name="struts.multipart.maxSize" value="2097152000" />
        
        <package name="upload" namespace="/upload" extends="struts-default" >
        
           <action name="action/single" class="ecut.upload.SingleFileUploadAction" >
               <!-- 通过 param 为 当前的 Action 实例 指定一个参数 ( 实际上是 Action 类中的一个 属性 ) -->
               <param name="storePath">D:/</param>
               
               <result name="success" type="redirectAction">
                   <param name="actionName">success/single</param>
               </result>
                <result name="fail" type="redirectAction">
                   <param name="actionName">fail/single</param>
               </result>
               
                <exception-mapping result="fail" exception="java.lang.Exception" />
                
               <interceptor-ref name="defaultStack">
                   <!-- 必须满足 struts.multipart.maxSize >=  fileUpload.maximumSize -->
                   <param name="fileUpload.maximumSize">20971520</param>
               </interceptor-ref>
               
           </action>
           
           <action name="success/single">
               <result>/WEB-INF/pages/upload/success_single.jsp</result>
           </action>
           
           <action name="fail/single">
               <result>/WEB-INF/pages/upload/fail_single.jsp</result>
           </action>
           
        </package>
    
    </struts>

    在配置文件中还可以指定解析器,struts 2的上传的与FirstUploadServlet 中的方法一致(servlet3.0之前上传的方式),需要去解析inputstream,strust 2 默认是jakarta解析器,去对inputStream 进行解析。如果超出最大尺寸会抛出异常,可以在action标签中指定局部的异常映射。

    5、多文件上传测试案例

    index.jsp

    <%@ page language = "java" pageEncoding = "UTF-8" %>
    <%@ page contentType = "text/html; charset= UTF-8"%>
    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Struts Upload</title> </head> <body> <h5>文件上传</h5> <!-- method 必须是 POST ,enctype 必须是 multipart/form-data --> <form action="${ pageContext.request.contextPath }/upload/action/single" method="post" enctype="multipart/form-data"> <input type="file" name="upload" > <input type="submit" value="上传" > </form> <h5>文件上传</h5> <!-- method 必须是 POST ,enctype 必须是 multipart/form-data --> <form action="${ pageContext.request.contextPath }/upload/action/multiple" method="post" enctype="multipart/form-data"> <input type="file" name="upload" > <br> <input type="file" name="upload" > <br> <input type="file" name="upload" > <br> <input type="file" name="upload" > <br> <input type="submit" value="上传" > </form> </body> </html>

    success_single.jsp

    <%@ page language = "java" pageEncoding = "UTF-8" %>
    <%@ page contentType = "text/html; charset= UTF-8"%>
    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>上传成功</title> </head> <body> <h1>上传成功</h1> </body> </html>

    fail_single.jsp

    <%@ page language = "java" pageEncoding = "UTF-8" %>
    <%@ page contentType = "text/html; charset= UTF-8"%>
    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>上传失败</title> </head> <body> <h1>上传失败</h1> </body> </html>

    struts.xml

    <?xml version="1.0" encoding="UTF-8"?>
    
    <!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
        "http://struts.apache.org/dtds/struts-2.5.dtd">
    
    <struts>
    
        <!-- 允许在 action 的 名称 中使用 / 字符  -->
         <constant name="struts.enable.SlashesInActionNames" value="true" />
        <!-- 启用动态方法调用  <constant name="struts.enable.DynamicMethodInvocation" value="true" /> -->
        
        <!-- 修改 action 请求路径的后缀 -->
        <constant name="struts.action.extension" value="do,," />
        <!-- 解析器的作用是对request.getInputStream()返回的字节流进行解析获取文件内容、类型、名称(和resultType="stream" 实现下载原理一致) -->
        <!-- 指定 对上传的 字节流进行解析的解析器 : jakarta 、cos 、pell -->
        <constant name="struts.multipart.parser" value="jakarta" />
        <!-- 指定上传文件的尺寸 ( 在 default.properties 中默认定义的大小是 2MB )-->
        <constant name="struts.multipart.maxSize" value="2097152000" />
        
        <package name="upload" namespace="/upload" extends="struts-default" >
        
           <action name="action/single" class="ecut.upload.SingleFileUploadAction" >
               <!-- 通过 param 为 当前的 Action 实例 指定一个参数 ( 实际上是 Action 类中的一个 属性 ) -->
               <param name="storePath">D:/</param>
               
               <result name="success" type="redirectAction">
                   <param name="actionName">success/single</param>
               </result>
                <result name="fail" type="redirectAction">
                   <param name="actionName">fail/single</param>
               </result>
               
                <exception-mapping result="fail" exception="java.lang.Exception" />
                
               <interceptor-ref name="defaultStack">
                   <!-- 必须满足 struts.multipart.maxSize >=  fileUpload.maximumSize -->
                   <param name="fileUpload.maximumSize">20971520</param>
               </interceptor-ref>
               
           </action>
           
           <action name="action/multiple" class="ecut.upload.MultipleFileUploadAction" >
               <!-- 通过 param 为 当前的 Action 实例 指定一个参数 ( 实际上是 Action 类中的一个 属性 ) -->
               <param name="storePath">D:/</param>
               
               <result name="success" type="redirectAction">
                   <param name="actionName">success/single</param>
               </result>
                <result name="fail" type="redirectAction">
                   <param name="actionName">fail/single</param>
               </result>
               
               <exception-mapping result="fail" exception="java.lang.Exception" />
               
               <interceptor-ref name="defaultStack">
                   <!-- 必须满足全局上传的文件尺寸最大值 struts.multipart.maxSize >=  单前action上传文件尺寸最大值fileUpload.maximumSize -->
                   <param name="fileUpload.maximumSize">20971520</param>
               </interceptor-ref>
               
           </action>
           
           <action name="success/single">
               <result>/WEB-INF/pages/upload/success_single.jsp</result>
           </action>
           
           <action name="fail/single">
               <result>/WEB-INF/pages/upload/fail_single.jsp</result>
           </action>
           
        </package>
    
    </struts>

    Action类

    package ecut.upload;
    
    import java.io.File;
    import java.nio.file.Files;
    import java.nio.file.Path;
    import java.nio.file.Paths;
    import java.nio.file.StandardCopyOption;
    import java.util.List;
    
    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    
    import com.opensymphony.xwork2.Action;
    
    public class MultipleFileUploadAction implements Action {
        
        private static Logger logger = LogManager.getLogger();
        
        private String storePath ;
        
        private List<File> upload ; 
        private  List<String> uploadContentType ; 
        private  List<String> uploadFileName ;
    
        @Override
        public String execute() throws Exception {
            logger.info("upload.get(0)对应的类型是uploadContentType.get(0),对应的文件名是uploadFileName.get(0)");
            
            for(int i =0 ; i < upload.size(); i++){
                //getCanonicalPath获取规范化路径
                Path source = Paths.get( upload.get(i).getCanonicalPath() );
                
                Path target = Paths.get( this.storePath , uploadFileName.get(i) );
                
                //Replace an existing file if it exists.
                Files.copy( source , target , StandardCopyOption.REPLACE_EXISTING );
            }
            return SUCCESS;
        }
    
        public String getStorePath() {
            return storePath;
        }
    
        public void setStorePath(String storePath) {
            this.storePath = storePath;
        }
    
        public List<File> getUpload() {
            return upload;
        }
    
        public void setUpload(List<File> upload) {
            this.upload = upload;
        }
    
        public List<String> getUploadContentType() {
            return uploadContentType;
        }
    
        public void setUploadContentType(List<String> uploadContentType) {
            this.uploadContentType = uploadContentType;
        }
    
        public List<String> getUploadFileName() {
            return uploadFileName;
        }
    
        public void setUploadFileName(List<String> uploadFileName) {
            this.uploadFileName = uploadFileName;
        }
        
    }

    Struts2实现国际化

    1、简介

    •  国际化简称i18n,其来源是英文单词 internationalization的首末字符i 和n。18为中间的字符数。
    •  国际化即是对于Web应用来说,页面在不同的语言环境下需要显示不同的效果。
    • Struts2中使用到国际化的地方有: jsp页面的国际化、Action信息国际化、转换错误信息的国际化、校验错误信息的国际化;
    • Struts2国际化文件分类: 全局范围国际化文件 、包范围国际化文件 、Action类范围国际化文件 。

    2、普通实现表单方式和Struts 2 标签去完成表单比较

    <%@ page language = "java" pageEncoding = "UTF-8" %>
    <%@ page contentType = "text/html; charset= UTF-8"%>
    <%@ taglib prefix = "s" uri = "/struts-tags"%>
    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>国际化</title> <style type="text/css"> .login-form { width: 80% ; margin: 20px auto ; box-shadow: 0px 0px 5px 4px #d3d3d3; padding: 10px 10px ;} .login-form .form-row { height: auto ; overflow: hidden; border-bottom: 1px dotted #d3d3d3 ; padding-bottom: 5px ; } .login-form .form-row:last-child { border: none ; } .login-form .form-row i , .login-form .form-row b { height: 30px ; line-height: 30px ; } .login-form .form-row i { float: left ; width: 30% ; text-align: right ; font-style: normal ; font-size: 18px ; } .login-form .form-row b { float: right ; width: 70% ; text-align: left ; } .login-form .form-row b input { margin-left: 1% ; padding-left : 4px ; height: 20px ; line-height: 20px ; width: 96% ; border: 1px solid #dedede ; outline: none ; } .login-form .buttons { width: 70% ; margin-left: 30% ; } .login-form .buttons span { float : left ; width: 50% ; height: 30px ; line-height: 30px ; } .login-form .buttons span:first-child { text-align: center ; } .login-form .buttons span:last-child { text-align: center ; } .login-form .buttons span input { width: 80% ; } </style> </head> <body> <h3>原生HTML表单</h3> <div class="login-form"> <form action="${ pageContext.request.contextPath }/user/login" method="post" > <div class="form-row"> <i>用户名:</i> <b> <input type="text" name="username" ></b> </div> <div class="form-row"> <i>密码:</i> <b> <input type="password" name="password" > </b> </div> <div class=" form-row"> <div class="buttons"> <span > <input type="reset" value="重置"> </span> <span> <input type="submit" value="登录"> </span> </div> </div> </form> </div> <hr> <h3>Struts 2 表单(不支持国际化)</h3> <s:form namespace="/user" action="login" method="post" > <s:textfield label="用户名" name="username" /> <s:password label="密码" name="password" /> <s:reset value="重置" /> <s:submit value="登录" /> </s:form> </body> </html>

    Struts 2实现表单需要先导入标签库,查看Struts 2源码可以得知Struts的表单是用表格实现的,因此两个按钮不在同一行,不太美观,不介意使用Struts实现表单。但是Struts 2实现表单得依赖于Struts 2的标签,因此我们需要先了解Struts 2编写表单。

     3、配置文件编写

    • 国际化文件的命名规则

        基本名.properties 如:user_login.properties

        基本名_语言编码_国家编码.properties 如:user_login_en_US.properties, user_login_zh_CN.properties

        其中语言编码和国家编码是固定的,可以在JDK中Locale类的常量中找到。

    • 为了实现程序的国际化,必须先提供程序所需要的资源文件。资源文件的内容基本是key-value对,其中key是程序使用的部分(页面需要和配置文件中一致),而value是程序的显示部分。

    user_login_zh_CN.properties

    user.login.username.label= User Name
    user.login.password.label= Password
    user.login.reset.button= Reset
    user.login.submit.button= Login

    user_login_en_US.properties

    user.login.username.label=用户名
    user.login.password.label=密码
    user.login.reset.button=重置
    user.login.submit.button=登录

    index.jsp

    <%@ page language = "java" pageEncoding = "UTF-8" %>
    <%@ page contentType = "text/html; charset= UTF-8"%>
    <%@ taglib prefix = "s" uri = "/struts-tags"%>
    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>国际化</title> <style type="text/css"> .login-form { width: 80% ; margin: 20px auto ; box-shadow: 0px 0px 5px 4px #d3d3d3; padding: 10px 10px ;} .login-form .form-row { height: auto ; overflow: hidden; border-bottom: 1px dotted #d3d3d3 ; padding-bottom: 5px ; } .login-form .form-row:last-child { border: none ; } .login-form .form-row i , .login-form .form-row b { height: 30px ; line-height: 30px ; } .login-form .form-row i { float: left ; width: 30% ; text-align: right ; font-style: normal ; font-size: 18px ; } .login-form .form-row b { float: right ; width: 70% ; text-align: left ; } .login-form .form-row b input { margin-left: 1% ; padding-left : 4px ; height: 20px ; line-height: 20px ; width: 96% ; border: 1px solid #dedede ; outline: none ; } .login-form .buttons { width: 70% ; margin-left: 30% ; } .login-form .buttons span { float : left ; width: 50% ; height: 30px ; line-height: 30px ; } .login-form .buttons span:first-child { text-align: center ; } .login-form .buttons span:last-child { text-align: center ; } .login-form .buttons span input { width: 80% ; } </style> </head> <body> <h3>原生HTML表单</h3> <div class="login-form"> <form action="${ pageContext.request.contextPath }/user/login" method="post" > <div class="form-row"> <i>用户名:</i> <b> <input type="text" name="username" ></b> </div> <div class="form-row"> <i>密码:</i> <b> <input type="password" name="password" > </b> </div> <div class=" form-row"> <div class="buttons"> <span > <input type="reset" value="重置"> </span> <span> <input type="submit" value="登录"> </span> </div> </div> </form> </div> <hr> <h3>Struts 2 表单(不支持国际化)</h3> <s:form namespace="/user" action="login" method="post" > <s:textfield label="用户名" name="username" /> <s:password label="密码" name="password" /> <s:reset value="重置" /> <s:submit value="登录" /> </s:form> <h3>Struts 2 表单(支持国际化,只有使用Struts标签才可以支持)</h3> <s:form namespace="/user" action="login" method="post" > <s:textfield key="user.login.username.label" name="username" /> <s:password key="user.login.password.label" name="password" /> <s:reset key="user.login.reset.button" /> <s:submit key="user.login.submit.button" /> </s:form> <hr> <!-- 语言代码小写,国家大写 --> <a href="${ pageContext.request.contextPath }/user/index?request_locale=zh_CN">中文</a> <a href="${ pageContext.request.contextPath }/user/index?request_locale=en_US">English</a> </body> </html>

    4、struts.xml文件配置

    <!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
        "http://struts.apache.org/dtds/struts-2.5.dtd">
    
    <struts>
    
        <!-- 指定属性文件的 baseName 就是 除了 "_语言代码_国家或地区代码.properties" 之外的那部分 -->
        <constant name="struts.custom.i18n.resources" value="user_login" />
        
        <package name="user" namespace="/user" extends="struts-default" >
            
           <action name="index" >
               <result>/i18n/index.jsp</result>
           </action>
        
           <action name="login" ></action>
           
        </package>
    </struts>

    需要参照default.properites ( org/apache/struts2/default.properties,当需要找常量名称时候打开他)增加常量struts.custom.i18n.resources,指定属性文件的 baseName 就是 除了 "_语言代码_国家或地区代码.properties" 之外的那部分

    参考博客链接

    https://www.cnblogs.com/hellokitty1/p/5083663.html

    https://blog.csdn.net/weixin_36380516/article/details/72510292

    转载请于明显处标明出处

    https://www.cnblogs.com/AmyZheng/p/9230708.html

  • 相关阅读:
    用wamp配置的环境,想用CMD连接mysql怎么连
    Mysql删除表
    MySQL创建表
    Leetcode 130. Surrounded Regions
    Leetcode 111. Minimum Depth of Binary Tree
    Leetcode 110. Balanced Binary Tree
    Leetcode 98. Validate Binary Search Tree
    Leetcode 99. Recover Binary Search Tree
    Leetcode 108. Convert Sorted Array to Binary Search Tree
    Leetcode 105. Construct Binary Tree from Preorder and Inorder Traversal
  • 原文地址:https://www.cnblogs.com/AmyZheng/p/9230708.html
Copyright © 2011-2022 走看看