zoukankan      html  css  js  c++  java
  • SSM整合开发

    Spring + Spring MVC + Mybatis 整合

    实现SSM的登录、注册功能。

    首先对SSM框架有一个整体意识

    建立目录结构:

    controller service mapper 三者关系:

    调用:controller --> service --> mapper

    返回:mapper --> service  --> controller 

    controller:作为请求转发,调用service接口处理逻辑,页面所有路径的访问方法:控制层的命名空间+@RequestMapping的value
    service:接口,处理业务逻辑(impl里面实现,调用mapper操作数据库)
    mapper:操作数据库的接口

    第一,导入springspring mvcmybatis所需要的包

    第二,配置applicationContext.xml

     1 <!-- 配置包扫描 -->
     2     <context:component-scan base-package="com.krry"></context:component-scan>
     3         
     4     <!-- 导入外部资源文件 -->
     5     <!-- <context:property-placeholder location="classpath:jdbc.properties" />  -->
     6     <bean class="com.krry.core.des.EncryptPropertyPlaceholderConfigurer"
     7         p:location="classpath:db/jdbc.properties" p:fileEncoding="utf-8" />
     8         
     9     <!-- proxool连接池 -->
    10     <bean id="dataSource" class="org.logicalcobwebs.proxool.ProxoolDataSource">
    11         <!-- 驱动的名字,mysql -->
    12         <property name="driver" value="${db.driver}"></property>
    13         <!--proxool 的 url连接串,这个必须确定用户名和密码 -->
    14         <property name="driverUrl" value="${db.url}"></property>
    15         <!-- 用户名(proxool没有使用,但是不能没有) -->
    16         <property name="user" value="${db.username}"></property>
    17         <!-- 密码(proxool没有使用,但是不能没有) -->
    18         <property name="password" value="${db.password}"></property>
    19         <!-- proxool自动侦察各个连接状态的时间间隔(毫秒),侦察到空闲的连接就马上回收,超时的销毁 现在设置为4秒) -->
    20         <property name="houseKeepingSleepTime" value="3000"></property><!-- 自动检查连接是否断掉开关 -->
    21         <property name="testBeforeUse" value="true"></property>
    22         <!--  如果发现了空闲的数据库连接.house keeper 将会用这个语句来测试.这个语句最好非常快的被执行.如果没有定义,测试过程将会被忽略 -->
    23         <property name="houseKeepingTestSql" value="SELECT count(1) from dual"></property>
    24         <!--  如果housekeeper 检测到某个线程的活动时间大于这个数值.它将会杀掉这个线程.所以确认一下你的服务器的带宽.然后定一个合适的值.默认是5分钟. 现在设置 10 秒--> 
    25         <property name="maximumActiveTime" value="10000"></property>
    26         <!-- 最少保持的空闲连接数 (现在设置20个) -->
    27         <property name="prototypeCount" value="20"></property>
    28         <!-- 最大连接数 (现在设置100个) -->
    29         <property name="maximumConnectionCount" value="200"></property>
    30         <!-- 最小连接数 (现在设置50个) -->
    31         <property name="minimumConnectionCount" value="50"></property>
    32         <!-- 如果为true,那么每个被执行的SQL语句将会在执行期被log记录(DEBUG LEVEL).你也可以注册一个ConnectionListener (参看ProxoolFacade)得到这些信息. -->
    33         <property name="trace" value="false"></property>
    34         <property name="verbose" value="true"></property>
    35     </bean>
    36     
    37     <!-- 注册事务管理器 -->
    38     <bean id="txMgr"
    39         class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    40         <property name="dataSource" ref="dataSource"></property>
    41     </bean>
    42 
    43     <!-- 开启事务注解驱动 -->
    44     <tx:annotation-driven transaction-manager="txMgr" />
    45     
    46     <!-- 配置mybatis的sqlSessionFactory -->
    47     <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    48         <property name="dataSource" ref="dataSource"></property>
    49         <property name="configLocation" value="classpath:mybatis-config.xml"></property>
    50     </bean>
    51     
    52     <!-- 配置可以整体扫描Mapper的一个扫描器 -->
    53     <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    54         <!--如果有多个报路径,用逗号分开即可  -->
    55         <property name="basePackage" value="com.krry.mapper"></property>
    56         <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
    57     </bean>

    第三,配置springmvc.xml

      1 <?xml version="1.0" encoding="UTF-8" ?>
      2 <beans xmlns="http://www.springframework.org/schema/beans"
      3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
      4     xmlns:p="http://www.springframework.org/schema/p"
      5     xmlns:context="http://www.springframework.org/schema/context"
      6     xmlns:util="http://www.springframework.org/schema/util" 
      7     xmlns:mvc="http://www.springframework.org/schema/mvc"
      8     xsi:schemaLocation="http://www.springframework.org/schema/beans
      9        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
     10        http://www.springframework.org/schema/context 
     11        http://www.springframework.org/schema/context/spring-context-3.0.xsd
     12        http://www.springframework.org/schema/util 
     13        http://www.springframework.org/schema/util/spring-util-3.0.xsd 
     14        http://www.springframework.org/schema/mvc 
     15        http://www.springframework.org/schema/mvc/spring-mvc.xsd
     16       ">
     17    
     18          <!-- 开启注解模式驱动 -->    
     19         <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" /> 
     20         <!-- 开启mvc的注解模式 user 还会注册一个ConversionService 子类FormattingConversionServiceFactoryBean-->
     21          <mvc:annotation-driven>
     22             <mvc:message-converters register-defaults="true">
     23                 <bean class="com.krry.core.UTF8StringHttpMessageConverter">
     24                     <property name="supportedMediaTypes">
     25                         <list>  
     26                             <value>text/plain;charset=UTF-8</value>  
     27                             <value>text/html;charset=UTF-8</value>  
     28                         </list>  
     29                     </property>
     30                 </bean> 
     31                 <bean class="org.springframework.http.converter.BufferedImageHttpMessageConverter"/>
     32                 <bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/> 
     33                 <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
     34                     <property name="prefixJson" value="false" />
     35                     <property name="objectMapper">
     36                          <bean class="com.fasterxml.jackson.databind.ObjectMapper">
     37                                <!-- 处理responseBody 里面日期类型 --> 
     38                                <property name="dateFormat">  
     39                                    <bean class="java.text.SimpleDateFormat">  
     40                                        <constructor-arg type="java.lang.String" value="yyyy-MM-dd HH:mm:ss" />  
     41                                    </bean>  
     42                                </property> 
     43                                <!-- 为null字段时不显示 -->
     44                                <property name="serializationInclusion">
     45                                    <value type="com.fasterxml.jackson.annotation.JsonInclude.Include">NON_NULL</value>
     46                                </property> 
     47                            </bean>  
     48                     </property>
     49                      <property name="supportedMediaTypes">  
     50                         <list>  
     51                             <value>application/json;charset=UTF-8</value>  
     52                             <value>application/x-www-form-urlencoded;charset=UTF-8</value>  
     53                         </list>  
     54                     </property>
     55                 </bean>
     56                 </mvc:message-converters> 
     57         </mvc:annotation-driven>
     58         
     59          <!-- 扫包 -->
     60          <context:component-scan base-package="com.krry.controller"></context:component-scan>
     61          
     62          <!--对静态资源文件的访问  必须要设置,因为在springmvc的配置中配置了/匹配所有请求,
     63         此工程所有的请求(.do ,addUser,js/image/css)都会被springmvc解析,
     64         必须对所有的静态资源文件进行过滤放行 -->
     65       <!-- 静态资源过滤  下面二选一-->
     66       <!--<mvc:default-servlet-handler/> -->
     67       <mvc:resources mapping="/resourse/**" location="/resourse/" />
     68       
     69       <!-- 拦截器定义 -->
     70       <mvc:interceptors>    
     71           <mvc:interceptor>
     72              <!-- 个人中心也需要登陆  以admin开头的配置都会进行拦截-->
     73                <mvc:mapping path="/admin/**"></mvc:mapping> 
     74                    <!-- 这个是设置不会进入拦截器的路径 -->
     75                    <mvc:exclude-mapping path="/resourse/**"/>
     76             <!-- 拦截器进入的类,返回false表示不会进入输入的路径 -->
     77             <bean class="com.krry.core.filter.LoginInterceptor" />       
     78           </mvc:interceptor>
     79       </mvc:interceptors>
     80        
     81            <!-- 配置文件解析器 -->
     82         <bean id="multipartResolver"
     83             class="org.springframework.web.multipart.commons.CommonsMultipartResolver"
     84             p:defaultEncoding="utf-8">
     85             <property name="uploadTempDir" value="/temp"></property>
     86             <property name="maxUploadSize">
     87                 <value>209715200</value><!-- 200MB -->
     88             </property>
     89             <property name="maxInMemorySize">
     90                 <value>4096</value><!-- 4KB大小读写 -->
     91             </property>
     92         </bean>
     93            
     94    
     95        <!-- 视图渲染 jsp/freemaker/velocity-->
     96        <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
     97                <!-- 制定页面存放的路径 -->
     98                <property name="prefix" value="/WEB-INF/pages/"></property>
     99                <!-- 文件的后缀 -->
    100                <property name="suffix" value=".jsp"></property>
    101        </bean> 
    102     
    103 </beans>

    第四,配置mybatis-config.xml

     1 <configuration> 
     2     <settings>  
     3          <!-- 全局映射器启用缓存 -->  
     4         <setting name="cacheEnabled" value="true" />  
     5          <!-- 查询时,关闭关联对象即时加载以提高性能 -->  
     6         <setting name="lazyLoadingEnabled" value="true" />  
     7         <!-- 设置关联对象加载的形态,此处为按需加载字段(加载字段由SQL指定),不会加载关联表的所有字段,以提高性能 -->  
     8         <setting name="aggressiveLazyLoading" value="false" />  
     9         <!-- 对于未知的SQL查询,允许返回不同的结果集以达到通用的效果 -->  
    10         <setting name="multipleResultSetsEnabled" value="true" />  
    11         <!-- 允许使用列标签代替列名 -->  
    12         <setting name="useColumnLabel" value="true" />  
    13         <!-- 允许使用自定义的主键值(比如由程序生成的UUID 32位编码作为键值),数据表的PK生成策略将被覆盖 -->  
    14         <setting name="useGeneratedKeys" value="true" />  
    15          <!-- 给予被嵌套的resultMap以字段-属性的映射支持 -->  
    16         <setting name="autoMappingBehavior" value="FULL" />  
    17         <!-- 对于批量更新操作缓存SQL以提高性能  -->  
    18         <setting name="defaultExecutorType" value="BATCH" />  
    19          <!-- 数据库超过25000秒仍未响应则超时 -->  
    20         <setting name="defaultStatementTimeout" value="25" />  
    21          <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
    22     </settings>  
    23     
    24     <typeAliases>
    25         <!--自定义user对象的别名  -->
    26         <!-- <typeAlias type="com.krry.mybatis.sysmanage.entity.User" alias="user"/> -->
    27         <!-- 批量定义别名 -->
    28         <package name="com.krry.entity" />
    29     </typeAliases>
    30 
    31     <!-- 配置pageHelper分页插件 -->
    32     <plugins>
    33         <plugin interceptor="com.github.pagehelper.PageHelper">
    34             <!-- 设置数据库类型 Oracle,Mysql,MariaDB,SQLite,Hsqldb,PostgreSQL六种数据库 -->
    35             <property name="dialect" value="mysql" />
    36             <!--当设置为true的时候,如果pagesize设置为0 就不执行分页,返回全部结果 -->
    37             <property name="pageSizeZero" value="true" />
    38             <!--合理化查询 比如如果pageNum<1会查询第一页;如果pageNum>pages会查询最后一页(设置为false返回空) -->
    39             <property name="reasonable" value="false" />
    40             <!-- 支持通过Mapper接口参数来传递分页参数 -->
    41             <property name="supportMethodsArguments" value="false" />
    42             <!-- 总是返回PageInfo类型,check检查返回类型是否为PageInfo,none返回Page -->
    43             <property name="returnPageInfo" value="none" />
    44         </plugin>
    45     </plugins>
    46     
    47     
    48 </configuration>

    在mybatis相应的xml文件配置mybatis的sql文件和mapper转换器(也就是说的mapper下面的接口) 注入到sqlSessionFactory (放入到内存中)

    1.  mapper的xml中,这里的命名空间可以随便定义(必须唯一),但是为了方便,定义成mapper包下的类的目录,调用mapper下面类的接口方法的时候,调用的路径是:mapper包下的类的目录+方法名,即是与这个命名空间+id一样,自动用了这个sql语句(id对应这个类的接口里面的方法)这里面必定有executeQuery方法,会执行这条sql语句。

    2.  如果自己自定义名命名空间,调用下面的sql语句的方法为:在mapper里的方法执行以下语句:
    SqlSession session = sessionFactory.openSession();
    List<User> users = session.selectList("命名空间+id");   //根据实际结果集类型和sql语句类型,写这条代码就可以获取结果集

    推荐使用第一种命名方式。

     mybatis执行流程:

    第五,配置web.xml

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
     3   
     4   <display-name>krry_SSM</display-name>
     5   
     6   <welcome-file-list>
     7     <welcome-file>index</welcome-file>
     8   </welcome-file-list>
     9   
    10   <!-- 加载Spring IOC容器 -->
    11   <context-param>
    12     <param-name>contextConfigLocation</param-name>
    13     <param-value>classpath:spring/applicationContext*.xml</param-value>
    14   </context-param>
    15   
    16   <!-- spring上下文监听器 -->
    17   <listener>
    18     <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    19   </listener>
    20   
    21   <!-- Introspector缓存清除监听器 -->
    22   <listener>
    23     <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
    24   </listener>
    25   
    26   <filter>
    27     <filter-name>encoding</filter-name>
    28     <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    29     <init-param>
    30       <param-name>encoding</param-name>
    31       <param-value>UTF-8</param-value>
    32     </init-param>
    33   </filter>
    34   
    35   <filter-mapping>
    36     <filter-name>encoding</filter-name>
    37     <url-pattern>/*</url-pattern>
    38   </filter-mapping>
    39   
    40   <!-- 配置DispatcherServlet -->
    41   <servlet>
    42     <servlet-name>krry_SSM</servlet-name>
    43     <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    44     <!-- 配置springMVC的配置文件 -->
    45     <!-- 如果不配置下面选项,系统默认加载classpath下面名为[servlet-name]-servlet.xml的文件 springmvc01-servlet.xml -->
    46     <init-param>
    47       <param-name>contextConfigLocation</param-name>
    48       <param-value>classpath:spring/springmvc.xml</param-value>
    49     </init-param>
    50   </servlet>
    51   
    52   <servlet-mapping>  
    53       <servlet-name>krry_SSM</servlet-name>  
    54       <url-pattern>/index</url-pattern>  
    55   </servlet-mapping>  
    56   
    57   <!-- 可以配*.do, *.action(了解) / (重点): 所有的请求都会被spring mvc解析,但必须对静态资源文件进行过滤放行,建议大家使用这种方式 
    58         /* : 不建议大家使用  -->
    59   <servlet-mapping>
    60     <servlet-name>krry_SSM</servlet-name>
    61     <url-pattern>/</url-pattern>
    62   </servlet-mapping>
    63  
    64 </web-app>

    这里注意一点欢迎页面,welcome-file-list一般情况下只能使用静态网页,如果非要把他配置成SpringMVC的控制器(通过controller进入欢迎页)URL就会报错404,

    解决方法:

    在web.xml上首先设置

    1   <welcome-file-list>
    2     <welcome-file>index</welcome-file>
    3   </welcome-file-list>

    再增加一个/index 的映射

    1   <servlet-mapping>  
    2       <servlet-name>krry_SSM</servlet-name>  
    3       <url-pattern>/index</url-pattern>  
    4   </servlet-mapping>  

    最后在controller层添加一个首页控制器得到index的请求

    1 @RequestMapping("/index")

    controller层:

      1 package com.krry.controller.login;
      2 
      3 import java.sql.Date;
      4 import java.sql.Timestamp;
      5 import java.text.SimpleDateFormat;
      6 import java.util.UUID;
      7 
      8 import javax.servlet.http.HttpServletRequest;
      9 
     10 import org.springframework.beans.factory.annotation.Autowired;
     11 import org.springframework.stereotype.Controller;
     12 import org.springframework.web.bind.annotation.RequestMapping;
     13 import org.springframework.web.bind.annotation.RequestMethod;
     14 
     15 import com.krry.entity.User;
     16 import com.krry.service.IUserService;
     17 import com.krry.util.TmStringUtils;
     18 
     19 /**
     20  * Controller层,作为请求转发
     21  * 页面所有路径的访问方法:控制层的命名空间+@RequestMapping的value
     22  * 如这里的/login/index.krry(后缀在xml文件配置)
     23  * */
     24 @Controller  //表示是多例模式,每个用户返回的web层是不一样的
     25 @RequestMapping("/login")
     26 public class LoginController {
     27 
     28     @Autowired
     29     private IUserService userService;
     30     
     31     /**
     32      * 若在下面的@RequestMapping前面加上@ResponseBody,
     33      * 若方法是String类型则直接返回的是字符串,不会跳转到该字符串的路径jsp文件
     34      * 
     35      * 所以要想跳转到某一jsp页面,不能加上@ResponseBody
     36      * 这个@ResponseBody适合ajax返回的数据
     37      * 
     38      */
     39     
     40     /**
     41      * 在控制层不加@ResponseBody的情况下,return值默认是转发到某路径,不会显示转发路径,显示的是未转发前的路径
     42      * 若要重定向,加上redirect:这里默认是当前命名空间的转发,要跳转到另一个control层,需要返回上一级../
     43      * 
     44         这里使用重定向,返回命名空间的上一级,重定向到命名空间为Krry下的index 
     45         return "redirect:../index";
     46         
     47         注意:
     48         转发不会显示转发路径,显示的是未转发前的路径
     49      *  重定向显示的是跳转之后的路径
     50      */
     51     
     52     /**
     53      * 进入登录界面
     54      * @return
     55      */
     56     @RequestMapping("/index")
     57     public String index(){
     58 //        ModelAndView modelAndView = new ModelAndView();
     59 //        modelAndView.setViewName("index/login"); //跳到此页面
     60 //        return modelAndView;
     61         return "index/login";   //默认是转发,不会显示转发路径
     62     }
     63     
     64     /**
     65      * 点击登录
     66      * com.krry.controller.login 
     67      * 方法名:login
     68      * @author krry 
     69      * @param request
     70      * @return String
     71      * @exception 
     72      * @since  1.0.0
     73      */
     74     @RequestMapping(method=RequestMethod.POST,value="/logined")
     75     public String login(HttpServletRequest request){
     76         //获取用户和密码
     77         String username = request.getParameter("username");
     78         String password = request.getParameter("password");
     79         
     80         //如果邮箱和密码为null,那么就返回已null标识
     81         if(TmStringUtils.isEmpty(username) )return "index/allError";
     82         if(TmStringUtils.isEmpty(password))return "index/allError";
     83         
     84         //密码进行加密处理
     85         password = TmStringUtils.md5Base64(password);
     86         
     87         //根据邮箱或昵称查询,用户是否存在
     88         User user = userService.getLogin(username);
     89         
     90         //如果存在
     91         if(user!=null){
     92             
     93             User userpas = userService.getpass(username, password);
     94             if(userpas!=null){
     95                 //如果密码正确
     96                 //将用户信息放入到会话中...
     97                 request.getSession().setAttribute("user", user);
     98                 
     99                 //这里使用重定向,返回命名空间的上一级,重定向到命名空间为Krry下的index.krry
    100                 return "redirect:../index";
    101             }else{
    102                 //如果密码错误
    103                 System.out.println("密码错误");
    104                 return "index/error";
    105             }
    106         }else{
    107             //如果不存在,代码邮箱和密码输入有误
    108             System.out.println("用户不存在");
    109             return "index/error";
    110         }
    111     }
    112     
    113     /**
    114      * 退出登录控制层
    115      * com.krry.controller.login 
    116      * 方法名:logout
    117      * @author krry 
    118      * @param request
    119      * @return String
    120      * @exception 
    121      * @since  1.0.0
    122      */
    123     @RequestMapping(method=RequestMethod.GET,value="/logout")
    124     public String logout(HttpServletRequest request){
    125         request.getSession().invalidate(); //清空session值
    126         return "index/index";
    127     }
    128     
    129     /**
    130      * 打开注册界面层
    131      * @return
    132      */
    133     @RequestMapping("/rege")
    134     public String rege(){
    135 //        ModelAndView modelAndView = new ModelAndView();
    136 //        modelAndView.setViewName("index/login"); //跳到此页面
    137 //        return modelAndView;
    138         return "index/resgi";
    139     }
    140     
    141     /**
    142      * 注册控制层
    143      * com.krry.controller.login 
    144      * 方法名:resig
    145      * @author krry 
    146      * @param request
    147      * @return String
    148      * @exception 
    149      * @since  1.0.0
    150      */
    151     @RequestMapping(method=RequestMethod.POST,value="/resig")
    152     public String resig(HttpServletRequest request){
    153         //获取用户和密码
    154         String name = request.getParameter("username");
    155         String email = request.getParameter("email");
    156         String password = request.getParameter("password");
    157 
    158         //如果邮箱和密码为null,那么就返回已null标识
    159         if(TmStringUtils.isEmpty(name) )return "index/allError";
    160         if(TmStringUtils.isEmpty(email))return "index/allError";
    161         if(TmStringUtils.isEmail(password))return "index/allError";
    162         
    163         //密码进行加密处理
    164         password = TmStringUtils.md5Base64(password);
    165         //根据昵称查询,用户是否存在
    166         User user1 = userService.getothernameres(name);
    167         //根据账号查询,用户是否存在
    168         User user2 = userService.getemailres(email);
    169         
    170         //若存在
    171         if(user1 != null){ //昵称重复
    172             return "index/allError";
    173         }
    174         if(user2 != null){ //email重复
    175             return "index/allError";
    176         }
    177 
    178         Date time = new Date(System.currentTimeMillis());
    179         
    180         String id = UUID.randomUUID().toString();
    181         //执行到这里,说明可以注册
    182         User newUser = new User(id, name, password, email,time);
    183         //调用注册方法
    184         userService.saveUser(newUser);
    185         
    186         //将信息设置session作用域
    187         request.getSession().setAttribute("user", newUser);
    188 
    189         /**
    190          * 这里使用重定向,返回命名空间的上一级,重定向到index
    191          */
    192         return "redirect:../index";
    193     }
    194     
    195 }

     重要的点,以上的说到了,还有一些前端页面、数据库操作就不在这展示了

    以上ssm整合的链接展示:https://www.ainyi.com/krry_SSM

    JavaWeb容器初始化过程

  • 相关阅读:
    基于Android的学生电子假条管理平台(笔记18)
    基于Android的学生电子假条管理平台(笔记17)
    请假制度管理与责任规避(笔记16)
    高校学生考勤管理系统功能设计(笔记15)
    浅析普通高校考勤请假制度的困境及其解决方法(笔记14)
    浅析普通高校考勤请假制度的困境及其解决方法(笔记13)
    高职大学生非正常请假现象透视(笔记12)
    学校应该完善与落实学生考勤制度——两张与众不同的请假条的故事(笔记11)
    《基于ASP.NET技术的小区物业管理系统设计与实现》论文笔记(二十)
    《基于JSP小区物业信息管理系统的设计与实现》论文笔记(十九)
  • 原文地址:https://www.cnblogs.com/ainyi/p/8527984.html
Copyright © 2011-2022 走看看