zoukankan      html  css  js  c++  java
  • day49_BOS项目_01

    • 项目12天安排:
      • 1-2天:项目概述、搭建开发环境、主页设计、持久层和表现层设计
      • 3-6天:项目业务开发(取派员、区域、分区、定区、业务受理)
        --> 整个项目分为基础设置、取派、中转、路由、报表
      • 7-8天:权限控制、权限管理
        --> apache shiro
      • 9-11天:工作流开发
        --> activiti
      • 12天:总结
    • 今天内容安排:
      • 1、项目概述(背景介绍、常见软件类型、软件开发流程(瀑布模型))
      • 2、搭建开发(数据库、web项目、SVN管理项目)
      • 3、主页设计(jQuery的插件easyUI)
      • 4、UML工具使用PowerDesigner

    1、项目概述

    1.1、项目背景介绍

    • BOS --> Bussiness Operating System 业务操作系统

      • 甲方:宅急送物流公司,软件的使用方
      • 乙方:用友软件,软件的开发方
    • 本项目属于宅急送公司二期改造项目。

    • ERP--> Enterprise Resource Planning 企业资源计划,如下图所示:

    • 项目的团队人数20多个人,项目开发周期1年多(13个月),编码阶段4个月。

    1.2、常见的软件类型

    • OA:Office Automation办公自动化系统
    • CRM:Customer Relationship Management客户关系管理系统
    • ERP:Enterprise Resource Planning企业资源计划平台(物资流、人力流、财务流、信息流)
    • CMS:Content Mangement System内容管理系统

    1.3、软件开发流程

    • 本案例使用:瀑布模型,该模型适用于规模小、周期短的项目。
      • 0、可行性分析
      • 1、需求调研分析 --> 需求规格说明书
      • 2、设计阶段(概要设计、详细设计) --> 数据库设计、原型设计
      • 3、编码阶段(单元测试)
      • 4、测试阶段(系统测试、性能测试、白盒测试(需要检查代码,懂技术)、黑盒测试(不懂技术))
      • 5、上线和运维
    • 敏捷开发 --> 思想:分阶段,分模块

    1.4、开发环境

    • 如下图所示:

    1.5、技术选型

    • 如下图所示:
    • Webservice和Hession都属于远程调用技术。二者区别如下:
      • Webservice,传输的数据格式是xml格式,数据冗余比较多,网络传输比较大的话,会成为性能的瓶颈。
      • Hession,传输的数据格式是二进制格式,传输效率更高。

    2、搭建开发环境

    2.1、数据库环境

    • 第一步:创建一个数据库
      mysql -uroot -proot
    • 第二步:创建一个数据库用户
      create database bos19;
    • 第三步:为创建的用户授权
      grant all on bos19.* to heize;
    • 第四步:使用新创建的数据库用户登录MySQL系统,并查看数据库
      mysql -uheize -p1234
      show databases;

    2.2、web项目环境

    • 第一步:使用ecplise,创建一个动态web项目,将Dynamic web module version 设置为2.5,创建完成后修改jdk版本为jdk1.7。
      • 方法:选中项目右键 --> Bulid Path --> Configure Bulid Path… --> Libraries --> JRE System Library [J2SE-1.5] --> Remove,然后再 Add Library… --> JRE System Library --> Next --> Workspace default JRE (jdk1.7.0_80)
      • 由于 EAR Libraries 是一个空的库,没有什么用,所以我们把它也Remove掉。
    • 第二步:导入jar包
      • Struts 11个jar + 1个整合Springj的jar = 12个
      • Spring 10个jar + 5个依赖jar = 15 个
      • Hibernate 1个Hibernate3的jar + 6个必须jar + 1个jpa的jar + 1个slf4j-log4j12-1.7.2.jar = 9个
      • 1个数据库驱动jar
      • 共计37个jar
      • 干掉重复的低版本的jar
    • 第三步:配置web.xml(配置struts2的过滤器、配置spring的监听器、配置解决Hibernate延迟加载问题的过滤器、配置解决中文乱码的过滤器)

    示例代码如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns="http://java.sun.com/xml/ns/javaee"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
        id="WebApp_ID" version="2.5">

        <display-name>bos19</display-name>

        <!-- 配置解决中文乱码的过滤器,注意:该方式不能解决get方式提交中文乱码,除此之外,其余的都可以 -->
        <filter>
            <filter-name>characterEncodingFilter</filter-name>
            <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
            <init-param>
                <param-name>encoding</param-name>
                <param-value>UTF-8</param-value>
            </init-param>
            <!--        
            <init-param>
                <param-name>forceEncoding</param-name>
                <param-value>true</param-value>
            </init-param> 
            -->

            <!-- encoding用来设置编码格式,forceEncoding用来设置是否理会 request.getCharacterEncoding()方法,设置为true则强制覆盖之前的编码格式 -->
        </filter>
        <filter-mapping>
            <filter-name>characterEncodingFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>

        <!-- 配置解决Hibernate延迟加载问题的过滤器 -->
        <filter>
            <filter-name>openSession</filter-name>
            <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>openSession</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>

        <!-- 指定spring配置文件的位置 -->
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:applicationContext.xml</param-value>
        </context-param>

        <!-- 配置spring监听器 -->
        <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>

        <!-- 配置struts2的过滤器 -->
        <filter>
            <filter-name>struts2</filter-name>
            <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>struts2</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>

        <welcome-file-list>
            <welcome-file>index.html</welcome-file>
            <welcome-file>index.htm</welcome-file>
            <welcome-file>index.jsp</welcome-file>
            <welcome-file>default.html</welcome-file>
            <welcome-file>default.htm</welcome-file>
            <welcome-file>default.jsp</welcome-file>
        </welcome-file-list>
    </web-app>
    • 第四步:创建项目目录结构
      如下图所示:
    • 第五步:在config目录下提供struts2的配置文件struts.xml和日志配置文件log4j.properties

    示例代码如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
        "http://struts.apache.org/dtds/struts-2.3.dtd">

    <struts>
        <!-- 设置为开发者模式 -->
        <constant name="struts.devMode" value="true"/>
        <!-- 使Spring对象工厂成为自动默认值,struts2与spring整合,该句不是必须的,在整合jar中已经配置过了 ,这里只是为了强调-->
        <constant name="struts.objectFactory" value="spring"/>

        <package name="basicstruts2" extends="struts-default">
            <!-- 需要进行权限控制的页面访问,使用默认的类和默认的方法,默认的类和默认的方法可以不用写,这里写出来为了强调 -->
            <action name="page_*_*" class="com.opensymphony.xwork2.ActionSupport" method="execute">
                <result name="success" type="dispatcher">/WEB-INF/pages/{1}/{2}.jsp</result>
            </action>
        </package>
    </struts>
    • 第六步:在config目录下提供spring的配置文件applicationContext.xml

    示例代码如下:

    <?xml version="1.0" encoding="UTF-8"?>

    <!-- 添加命名空间 ,让spring扫描含有注解类 -->
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
        xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/beans 
                                  http://www.springframework.org/schema/beans/spring-beans.xsd
                                  http://www.springframework.org/schema/tx 
                                  http://www.springframework.org/schema/tx/spring-tx.xsd
                                  http://www.springframework.org/schema/aop 
                                  http://www.springframework.org/schema/aop/spring-aop.xsd
                                  http://www.springframework.org/schema/context 
                                  http://www.springframework.org/schema/context/spring-context.xsd"
    >

        <!-- 加载 JdbcInfo.properties配置文件 -->
        <context:property-placeholder location="classpath:JdbcInfo.properties" />
        <!-- 配置数据源,基本四项 -->
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <property name="driverClass" value="${jdbc.driverClass}"></property>
            <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
            <property name="user" value="${jdbc.user}"></property>
            <property name="password" value="${jdbc.password}"></property>
        </bean>

        <!-- spring框架用于整合hibernate的工厂bean -->
        <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
            <!-- 注入数据源 -->
            <property name="dataSource" ref="dataSource"></property>
            <!-- 注入hibernate相关属性 -->
            <property name="hibernateProperties">
                <props>
                    <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
                    <prop key="hibernate.show_sql">true</prop>
                    <prop key="hibernate.format_sql">true</prop>
                    <prop key="hibernate.hbm2ddl.auto">update</prop>
                </props>
            </property>
            <!-- 注入hibernate的映射文件 -->
            <property name="mappingDirectoryLocations">
                <list>
                    <value>classpath:com/itheima/bos/domain</value>
                </list>
            </property>
        </bean>

        <!-- 事务管理器 -->
        <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
            <property name="sessionFactory" ref="sessionFactory"></property>
        </bean>

        <!-- 使用注解:组件扫描 -->
        <context:component-scan base-package="com.itheima.bos"/>
        <!-- 引入注解解析器:就可以使用它们了:@Controller @Service @Repository @Resource @Autowrired -->
        <context:annotation-config/>

        <!-- 事务注解:transaction-manager属性可以省略 -->
        <tx:annotation-driven/>
    </beans>
    • 第七步:提供项目所需的资源文件,如下图所示:
      • `注意1`:如果所需的资源文件图标上有红色的叉,说明需要引入外部jar包servlet-api.jar和jsp-api.jar。
      • `注意2`:由于本系统的很多页面使用了`标签`,属于服务器内部转发,会跳转到WEB-INF目录下对应的页面,而该目录下的页面是受保护的,所以web.xml中需要配置服务器内部转发也要经过struts2过滤器处理后才能跳转,否则的话服务器会报404错误,配置如下图所示:

    2.3、使用svn管理项目代码

    • 第一步:创建一个SVN仓库,在bos目录下右键 --> TortoiseSVN --> Create repository here
    • 第二步:修改SVN的配置文件,如下图所示:
      svnserve.conf

      passwd

      authz
    • 第三步:启动SVN服务
      • 法一:我们将启动SVN服务的操作注册成操作系统的“服务”,我们的电脑开机时SVN服务器就启动了。
      • 法二:使用批处理文件。(本案例我们采用法二)
      • `注意`:我们启动的是多仓库。
      • 批处理文件创建好后,我们双击运行该文件即可启动svn服务。
    • 第四步:eclipse上安装svn插件
      • 安装教程链接:https://www.cnblogs.com/chenmingjun/p/9459401.html#_label0_10
    • 第五步:将搭建的web项目共享到SVN仓库
      • 首先新建资源库位置,如下图所示:

        其余步骤参考如下链接:
        https://www.cnblogs.com/chenmingjun/p/9513143.html#_label0
        右键项目 --> Team --> Share Project…

        点击SVN --> Next --> 创建新的资源库位置 --> Next --> svn://localhost:3690/bos/code --> Next

        再次确认下,没问题,点击Next --> 第一次使用默认注释即可 --> Finish --> Yes --> 切换到提交视图,即已经纳入到svn的版本控制了,但是还没有真正上传。
        在提交视图下,右键项目 --> 提交(C)

        稍等一会儿,代码提交至svn仓库界面如下:

        然后,我们切换至SVN资源库视图进行查看,如下图所示:

    3、主页设计 --> jQuery EasyUI 插件

    • jQuery EasyUI的目录结构,如下图所示:
    • 在jsp页面中引入jQuery EasyUI相关的资源文件

    示例代码如下:

        <link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/js/easyui/themes/default/easyui.css">
        <link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/js/easyui/themes/icon.css">
        <script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-1.8.3.js"></script>
        <script type="text/javascript" src="${pageContext.request.contextPath}/js/easyui/jquery.easyui.min.js"></script>

    3.1、layout 布局

    详解如下:

        通过 $.fn.layout.defaults 重写默认的 defaults。
        这个布局(layout)是有五个区域(北区 north、南区 south、东区 east、西区 west 和中区center)的容器。
        中间的区域面板是必需的,边缘区域面板是可选的。每个边缘区域面板可通过拖拽边框调整尺寸,也可以通过点击折叠触发器来折叠面板。
        布局(layout)可以嵌套,因此用户可建立复杂的布局。


    示例代码如下:

    <body class="easyui-layout">
        <!-- 使用div指定区域 -->
        <div title="XX管理系统" data-options="region:'north'" style="height:100px">北部区域</div>
        <div title="系统菜单" data-options="region:'west'" style="200px">西部区域</div>
        <div data-options="region:'center'">中心区域</div>
        <div data-options="region:'east'" style="200px">东部区域</div>
        <div data-options="region:'south'" style="height:50px">南部区域</div>
    </body>

    效果如下图所示:

    3.2、accordion 折叠面板

    详解如下:

        通过 $.fn.accordion.defaults 重写默认的 defaults。
        折叠面板(accordion)允许您提供多个面板(panel),同时显示一个或多个面板(panel)。
        每个面板(panel)都有展开和折叠的内建支持。点击面板(panel)头部可展开或折叠面板(panel)主体。
        面板(panel)内容可通过 ajax 指定 'href' 属性来加载。用户可定义被选中的面板(panel)。如果为指定,则默认选中第一个面板(panel)。

    示例代码如下:

    <body class="easyui-layout">
        <!-- 使用div指定区域 -->  
        <div title="XX管理系统" data-options="region:'north'" style="height:100px">北部区域</div>
        <div title="系统菜单" data-options="region:'west'" style="200px">
            <!-- 折叠面板效果 -->
            <!-- data-options="fit:true"表示自适应或者叫填充父容器 -->
            <div class="easyui-accordion" data-options="fit:true">
                <!-- 每个子div是其中的一个面板 -->
                <div title="面板一">棉衣一</div>
                <div title="面板二">test2</div>
                <div title="面板三">test3</div>
            </div>
        </div>
        <div data-options="region:'center'">中心区域</div>
        <div data-options="region:'east'" style="200px">东部区域</div>
        <div data-options="region:'south'" style="height:50px">南部区域</div>
    </body>

    效果如下图所示:

    3.3、tabs 标签页/选项卡面板

    详解如下:

        通过 $.fn.tabs.defaults 重写默认的 defaults。
        选项卡显示一组面板。它一次只显示一个选项卡面板。
        每个选项卡面板都有标题和一些迷你按钮工具,包括关闭按钮和其他自定义按钮。

    示例代码如下:

    <body class="easyui-layout">
        <!-- 使用div指定区域 -->
        <div title="XX管理系统" data-options="region:'north'" style="height:100px">北部区域</div>
        <div title="系统菜单" data-options="region:'west'" style="200px">
            <!-- 折叠面板效果 -->
            <!-- data-options="fit:true"表示自适应或者叫填充父容器 -->
            <div class="easyui-accordion" data-options="fit:true">
                <!-- 每个子div是其中的一个面板 -->
                <div title="面板一">棉衣一</div>
                <div title="面板二">test2</div>
                <div title="面板三">test3</div>
            </div>
        </div>

        <div data-options="region:'center'">
            <!-- 选项卡面板效果 -->
            <div id="tt" class="easyui-tabs" data-options="fit:true">
                <!-- 每个子div是其中的一个面板 -->
                <div data-options="closable:true,iconCls:'icon-help'" title="面板一">棉衣一</div>
                <div title="面板二">test2</div>
                <div title="面板三">test3</div>
            </div>
        </div>
        <div data-options="region:'east'" style="200px">东部区域</div>
        <div data-options="region:'south'" style="height:50px">南部区域</div>
    </body>

    效果如下图所示:

    3.4、动态添加选项卡面板

    示例代码如下:

    <body class="easyui-layout">
        <!-- 使用div指定区域 -->
        <div title="XX管理系统" data-options="region:'north'" style="height:100px">北部区域</div>
        <div title="系统菜单" data-options="region:'west'" style="200px">
            <!-- 折叠面板效果 -->
            <!-- data-options="fit:true"表示自适应或者叫填充父容器 -->
            <div class="easyui-accordion" data-options="fit:true">
                <!-- 每个子div是其中的一个面板 -->
                <div title="面板一">
                    <a class="easyui-linkbutton" onclick="doAdd();">百度</a>
                    <script type="text/javascript">
                        function doAdd() {
                            // 动态添加一个选项卡面板
                            $("#tt").tabs("add", {
                                title:'这个可是动态添加的',
                                content:'<iframe frameborder="0" width="100%" height="100%" src="page_base_staff.action"></iframe>',
                                closable:true,
                                iconCls:'icon-search'
                            });
                        }
                    
    </script>
                </div>
                <div title="面板二">test2</div>
                <div title="面板三">test3</div>
            </div>
        </div>

        <div data-options="region:'center'">
            <!-- 选项卡面板效果 -->
            <div id="tt" class="easyui-tabs" data-options="fit:true">
                <!-- 每个子div是其中的一个面板 -->
                <div data-options="closable:true,iconCls:'icon-help'" title="面板一">棉衣一</div>
                <div title="面板二">test2</div>
                <div title="面板三">test3</div>
            </div>
        </div>
        <div data-options="region:'east'" style="200px">东部区域</div>
        <div data-options="region:'south'" style="height:50px">南部区域</div>
    </body>

    效果如下图所示:

    4、ztree 树形插件 --> jQuery 插件

    • 主要用于制作系统菜单。
    • ztree的目录结构:
    • 在jsp页面中引入ztree相关的资源文件

    示例代码如下:

        <link rel="stylesheet" href="${pageContext.request.contextPath}/js/ztree/zTreeStyle.css" type="text/css">
        <script type="text/javascript" src="${pageContext.request.contextPath}/js/ztree/jquery.ztree.all-3.5.js"></script>

    4.1、使用标准json数据构造ztree

    示例代码如下:

    <div title="面板二">
        <!-- 展示树形菜单 :使用标准json数据构造-->
        <ul id="ztree1" class="ztree"></ul>
        <script type="text/javascript">
            $(function() {
                // 当页面加载完成后,动态创建ztree菜单
                // 设置ztree相关的属性,该属性中不用写数据,因为我们使用标准json数据构造
                var setting = {}; 
                // 构造json数据
                var zNodes = [ 
                    // 每个json对象对应一个节点数据
                    {name : '系统管理'}, 
                    // 每个json对象对应一个节点数据
                    {name : '用户管理'children : [{name : '用户添加'}, {name : '用户修改'}]}, 
                    // 每个json对象对应一个节点数据
                    {name : '权限管理'
                ];
                // 创建ztree
                $.fn.zTree.init($("#ztree1"), setting, zNodes);
            });
        
    </script>
    </div>

    效果如下图所示:

    4.2、使用简单json数据构造ztree(建议使用)

    由于使用标准json数据构造ztree,代码的层级结构太深,不利于阅读,所以使用简单json数据构造ztree。
    示例代码如下:

    <div title="面板三">
        <!-- 展示树形菜单 :使用简单json数据构造-->
        <ul id="ztree2" class="ztree"></ul>
        <script type="text/javascript">
            $(function() {
                // 当页面加载完成后,动态创建ztree菜单
                // 设置ztree相关的属性
                var setting2 = {
                    data : {
                        simpleData : {
                            // 启用简单json数据描述节点数据 
                            enable : true
                        }
                    }
                }; 
                // 构造json数据
                var zNodes2 = [ 
                    // 每个json对象对应一个节点数据
                    {id : '1'pId : '0'name : '系统管理'},
                    // 每个json对象对应一个节点数据
                    {id : '2'pId : '0'name : '用户管理'},
                    {id : '21'pId : '2'name : '用户添加'},
                    {id : '22'pId : '2'name : '用户修改'},
                    // 每个json对象对应一个节点数据
                    {id : '3'pId : '0'name : '权限管理'}
                ];
                // 创建ztree
                $.fn.zTree.init($("#ztree2"), setting2, zNodes2);
            });
        
    </script>
    </div>

    效果如下图所示:

    4.3、发送ajax请求获取菜单数据构造ztree

    示例代码如下:

    <div title="面板四">
        <!-- 展示树形菜单 :发送ajax请求获取菜单数据构造ztree-->
        <ul id="ztree3" class="ztree"></ul>
        <script type="text/javascript">
            $(function() {
                // 设置ztree相关的属性
                var setting3 = {
                    data : {
                        simpleData : {
                            // 启用简单json数据描述节点数据 
                            enable : true
                        }
                    }
                };
                // 发送ajax请求获取json数据构造ztree
                var url = "${pageContext.request.contextPath}/json/menu.json";
                $.post(url, {}, function(data{
                    // 创建ztree
                    $.fn.zTree.init($("#ztree3"), setting3, data);
                }, 'json');
            });
        
    </script>
    </div>

    效果如下图所示:

    4.4、为ztree节点绑定事件

    示例代码如下:

    <div title="面板五">
        <!-- 展示树形菜单 :发送ajax请求获取菜单数据构造ztree,并为ztree节点绑定事件-->
        <ul id="ztree4" class="ztree"></ul>
        <script type="text/javascript">
            $(function() {
                // 设置ztree相关的属性
                var setting4 = {
                    data : {
                        simpleData : {
                            // 启用简单json数据描述节点数据 
                            enable : true
                        }
                    },
                    // 绑定事件
                    callback: {
                        onClickfunction(event, treeId, treeNode{
                            // alert(treeNode);
                            // alert(treeNode.page);
                            var page = treeNode.page;
                            if (page != undefined) {
                                // 判断当前选型卡是否已经打开
                                var e = $("#tt").tabs("exists", treeNode.name);
                                if (e) {
                                    // 当前选型卡已经打开,就选中它
                                    $("#tt").tabs("select", treeNode.name);
                                } else {
                                    // 当前选型卡没有打开,需要动态添加一个选项卡面板
                                    $("#tt").tabs("add", {
                                        title: treeNode.name,
                                        content:'<iframe frameborder="0" width="100%" height="100%" src="' + page + '"></iframe>',
                                        closable:true,
                                        iconCls:'icon-edit'
                                    });
                                }
                            }
                        }
                    }
                };
                // 发送ajax请求获取json数据构造ztree
                var url = "${pageContext.request.contextPath}/json/menu.json";
                $.post(url, {}, function(data{
                    // 创建ztree
                    $.fn.zTree.init($("#ztree4"), setting4, data);
                }, 'json');
            });
        
    </script>
    </div>

    效果如下图所示:

    5、UML工具 --> PowerDesiger 的使用

    • PowerDesigner16.5安装教程(含下载+汉化+破解)链接地址:
      https://www.fujieace.com/software/powerdesigner.html

    示例图片:

  • 相关阅读:
    简单介绍三层架构
    Java字符串常量池是什么?为什么要有这种常量池?
    java中String、StringBuffer和StringBuilder的区别(简单介绍)
    java中equals以及==的用法(简单介绍)
    关于java中Exception异常
    职场沟通,别光靠嘴
    小目标 | DAX高级实践-Power BI与Excel联合应用
    本号讯 | 微软和百度携手推进全球自动驾驶技术; 微软发布新一代可垂直可水平滚动的Arc鼠标
    你有一枚私人同声传译员待领取
    有了这套物联网节水平台,他决定回去继续管理农场
  • 原文地址:https://www.cnblogs.com/chenmingjun/p/9732587.html
Copyright © 2011-2022 走看看