zoukankan      html  css  js  c++  java
  • SpingMVC流程图

    Struts的请求流程

     

    springmvc的流程

    0.struts2       MVC框架  Controller
      Hibernate     持久化框架   Model
      spring        项目管理框架   为javaEE开发提供更好的解决方案
    ======================================================================================
    1.spring:工厂,容器
            :创建项目中的所有模块(组件),并持有管理所有的组件.
            :spring的所有功能实现,都架设在工厂(容器)的支持下.
    ======================================================================================
    2.spring工厂搭建:
      2.1 导包:
      2.2 配置文件:告知spring需要生产的组件.
           *位置:任意
           *名称:任意   applicationContext.xml    beans.xml
            <beans xmlns="http://www.springframework.org/schema/beans"
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                   xsi:schemaLocation="http://www.springframework.org/schema/beans
                                       http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
                
                <!-- 告知spring生产如下的组件 -->
                <bean id="ud47" class="com.c47.dao.UserDAOImpl"></bean>
                <bean id="us47" class="com.c47.serivce.UserServiceImpl"></bean>
            </beans>
      2.3 api:启动工厂:
            ApplicationContext
            ClassPathXmlApplicationContext
            //启动工厂:指定配置文件位置
            ApplicationContext context=new ClassPathXmlApplicationContext("com/c47/config/applicationContext.xml");
            //从工厂中获取bean
            UserDAO ud=(UserDAO)context.getBean("ud47");
            UserService us=(UserService)context.getBean("us47");
    =====================================================================================
    3.IOC Inverse Of Controll  控制反转
      :将属性的赋值权有静态代码中 反转 到配置文件中
      :将具有依赖关系的双方的耦合打散.提高项目的可维护性.
      :在配置文件中为属性赋值:DI  Dependency Injection  依赖注入
    =====================================================================================
    4.set注入:通过set方法,将属性值存入.
        <!-- jdk8中基本类型+String -->
        <property name="id" value="1"></property>
        <property name="name" value="c47"></property>
        <property name="gender" value="true"></property>
        <!-- List/数组 -->
        <property name="list47">
            <list>
                <value>1</value>
                <value>c47</value>
                <value>true</value>
                <ref bean="us47"/>
            </list>
        </property>
        <!-- Map -->
        <property name="map47">
            <map>
                <entry key="name" value="lichangpu"></entry>
                <entry key="age" value="18"></entry>
                <entry key="gender" value="true"></entry>
                <entry key="us47" value-ref="us47"></entry>
            </map>
        </property>
        <!-- properties -->
        <property name="props">
            <props>
                <prop key="url">jdbc:oracle:xxx</prop>
                <prop key="username">hr</prop>
            </props>
        </property>
    =====================================================================================
    5.构造注入:通过构造方法,为属性赋值
        <!-- 第一个参数,类型为Integer -->
        <constructor-arg index="0" type="java.lang.Integer" value="47"></constructor-arg>
        <constructor-arg index="1" type="java.lang.String" value="c47"></constructor-arg>
        <constructor-arg index="2" type="java.lang.Boolean" value="true"></constructor-arg>
        弊端:不够灵活
            :用于构造不提供空参构造的组件.
    =====================================================================================
    6.自动注入
        <!--
            autowire:自动装载
            byType:将工厂中与目标组件的属性同类型的bean,赋值给对应属性
            byName:将工厂中与目标组件的属性同名的bean,赋值给对应属性
         -->
        <bean id="ioc49" class="com.c47.IOC.test.TestIOC3" autowire="byName"></bean>
    =====================================================================================
    7.spring对于bean的生产原理:
        反射+空参构造:
        String path="com.c47.dao.UserDAOImpl";
        Class claz=Class.forName(path);
        Object obj=claz.newInstance();//调用空参构造
        例外:当使用了构造注入时,就不会选取空参构造,而是调用配置中指定的构造方法.
    =====================================================================================
    8.bean的生命周期:
      *bean的构建时刻:spring工厂启动时,所有的单例的bean随之创建
      *bean的销毁时刻:spring工厂关闭时,所有bean随之销毁.
      *细节:bean的生命历程(了解)
        构造-->set-->init-->destroy
    =====================================================================================
    9.bean的创建模式
      *singleton:单例    全局唯一  (默认)
      *prototype:非单例  全局不唯一
      <bean id="c47" class="xx"/> 单例
      <bean id="userAction47" class="xxxx" scope="singleton"> 单例
      <bean id="userAction47" class="xxxx" scope="prototype"> 非单例
      *单例:无论使用(getBean()/用于注入)多少次,都只有一个对象
      *非单例:每使用一次,都要创建一个新的对象.
      *细节:
           在工厂启动时,非单例的bean不会随之创建.而是在被使用时才创建.
    =====================================================================================
    1.复杂对象:创建过程复杂.不能直接new.
              :FactoryBean==构建复杂对象
    =====================================================================================
    2.FactoryBean 工厂bean使用流程:
      2.1 定制FactoryBean
            implements FactoryBean<SessionFactory>{
                /**
                 * 主体逻辑:定制复杂对象的创建流程
                 */
                public SessionFactory getObject() throws Exception {
                    ....
                }
                /**
                 * 返回复杂对象的类对象
                 */
                public Class getObjectType() {
                    return SessionFactory.class;
                }
                /**
                 * 定制复杂对象的创建模式:
                 * return true;单例
                 * return false;非单例
                 */
                public boolean isSingleton() {
                    return true;
                }
            }
      2.2 配置
            <!-- 声明工厂Bean -->
            <bean id="sessionFactory47" class="com.c47.factory_bean.MySessionFactory"></bean>
      2.3 使用:
            *当从工厂中获取bean时,如果此bean是FactoryBean,则返回给用户的并不是bean本身
             的对象.而是去回调此bean中的getObject(),返回此bean中getObject()方法的返回值.
    ====================================================================================
    3.spring 初步的整合hibernate
      *将sessionfactory纳入工厂
      *将DAO,Service 纳入工厂
      *并通过IOC满足DAO和Service的依赖
    ====================================================================================
    4.类型转换器:注入过程,如果双方的类型不匹配,则需要类型转换.
                :String-->数字,布尔 自动完成
        4.1 定制转换器类:
            extends PropertyEditorSupport{
                /**
                 * <bean>
                 *       <property name="birth" value="2015-12-11">
                 * </bean>
                 * 转换器的主体逻辑:完成数据格式转换
                 * param:text  要转换的值(2015-12-11)
                 * 此方法,会在spring需要类型转换时被spring回调
                 * setAsText("2015-12-11");
                 * getValue();
                 */
                @Override
                public void setAsText(String text) throws IllegalArgumentException {
                    SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd");
                    try {
                        Date date=format.parse(text);
                        //将转换好的数据,交还spring
                        //将转换好的数据,存入父类的成员变量中,spring会回调父类的getValue(),将值取走.
                        this.setValue(date);
                    } catch (ParseException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
        4.2 配置:
               *声明类型转换器:
                <bean id="dateEditor47" class="com.c47.property_editor.MyPropertyEditor"></bean>
               *注册:
                <!-- 告知spring
                     CustomEditorConfigurer:统一管理所有转换器的入口
                 -->
                <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
                    <!-- 注册自定义的类型转换器
                         告知spring此转换器可以完成string到Date的转换
                     -->
                    <property name="customEditors">
                        <map>
                            <entry key="java.util.Date" value-ref="dateEditor47"></entry>
                        </map>
                    </property>
                </bean>
               *使用:
                <!-- 转换器测试 -->
                <bean id="user47" class="com.c47.entity.User">
                    <property name="birth" value="2015-12-11 11:51:47"></property>
                </bean>
        *细节:如果是日期数据的注入,可以不定制转换器,spring默认的日期格式:
             :yyyy/MM/dd HH:mm:ss
    ====================================================================================
    *补充:spring对于hiberante更新的支持:
        //User{id,name,age,Set<order> orders}
        //user{id,name,age,null}
        //user2{id,name,age,orders}
        public void updateUser(User user) {
            Session session=factory.getCurrentSession();
            User user2=(User)session.get(User.class, user.getId());
            //将user的属性值,赋值给user2中的同名属性.
            //技巧:在set方法中添加判断,过滤null
            BeanUtils.copyProperties(user, user2);
            session.update(user2);
        }

    0.业务层:冗余:在业务中有大量的重复的逻辑散布在大量的业务方法,导致极大的冗余.
                 :对于项目的开发,和后期的维护,都是极大的隐患.
            :耦合:在业务中有两类逻辑[核心业务],[额外功能],耦合在一起,不利于项目的维护.
      public interface UserService{
        public void delete(Integer id);
        public void update(User user);
      }
      public class UserServiceImpl implements UserService{
        public void delete(Integer id){
            //核心业务处理:删除  UserDAO.delete();
        }
        public void update(User user){
            //核心业务处理:更新  UserDAO.update();
        }
      }

      //性能
      //事务
     
      静态代理类:组成:[target:核心业务]+[额外功能]
                :原则:代理(proxy)和目标(target)要有同样的方法实现(同样的接口实现)
          public class UserServiceProxy implements UserService{
            //原始的业务类
            private UserService us=new UserServiceImpl();
            public void delete(Integer id){
                 //性能
                 //事务
                 us.delete(id);
                 //事务
            }
            public void update(User user){
                 //性能
                 //事务
                 us.update(id);
            }
          }
          new UserServiceProxy().update(user);
          new UserServiceProxy().delete(1);
      动态代理类搭建:
         1.准备原材料:target中的核心业务
                     :额外功能
         2.通过aop:编织,将原材料,动态的加载,称为一个代理类
         3.获取动态生成的代理类,完成相关业务.
    ======================================================================================
    1.AOP :解决业务层中的问题
          :面向切面编程  代理模式   代理类
          :代理:target+Advice
          :切入点:切入了额外功能的 业务方法.
          :切面:切入点+额外功能
      OOP :面向对象编程  类 对象 接口  继承  封装  多态
    =====================================================================================
    2.动态代理搭建:*导入第三方的jar
      2.1 准备原材料
          *target
          *额外功能(Advice:建议)
                 MethodBeforeAdvice       前置额外功能
             AfterReturningAdvice     后置额外功能
             MethodInterceptor        环绕额外功能
             ThrowsAdvice             异常时的额外功能(了解)
            implements MethodBeforeAdvice{
                /**
                 * 主体逻辑:
                 *   params:
                 *      m:目标的方法对象
                 *      params:目标方法的参数表,如果方法是空参,则params的长度为0.
                 *      target:代理的目标
                 */    
                public void before(Method m, Object[] params, Object target)
                        throws Throwable {
                    //定制在目标的方法之前,执行的逻辑
                    System.out.println("before: method:"+m.getName()+" params'length:"+params.length+" target:"+target);
                }
            }
      2.2 动态的编织代理类
          *声明原材料:target和advice
          *Weave:编织
            <!-- target -->
            <bean id="userService47" class="com.c47.serivce.UserServiceImpl"></bean>
            <!-- Advice -->
            <bean id="before47" class="com.c47.advice.MyBefore"></bean>
            <!-- 编织:基于aop schema完成编织 -->
            <aop:config>
                <!-- 1.目标,及其中需要附加额外功能的方法.
                     2.在目标中加入哪些额外功能
                  -->
                <!--
                    pointcut:切入点=目标中 附加了额外功能的方法
                    execution()表达式:描述切入点
                           返回值   包  类  方法名  参数表
                    * com.c47.service4.UserServiceImpl.*(..)
                    * com.c47.service4.UserServiceImpl.deleteUser(..)
                 -->
                <aop:pointcut id="pc47" expression="execution(* com.c47.service4.UserServiceImpl.*(..))"/>
                <!-- 在位置[pc47]上,附加额外功能[before47]  -->
                <aop:advisor advice-ref="before47" pointcut-ref="pc47"/>
            </aop:config>
      2.3 从工厂中获取动态代理对象:通过目标类的beanID即可,用接口类型引用接收.
    ===================================================================================  
    3.额外功能:
      3.1 后置额外功能:AfterReturningAdvice
            implements AfterReturningAdvice{
                /**
                 * 主体逻辑:
                 *   params:
                 *       ret:目标方法的返回值,如果方法是void,则ret为null
                 *       m:目标方法对象
                 *       paras:方法参数表
                 *       target:目标对象
                 */
                public void afterReturning(Object ret, Method m, Object[] params,
                        Object target) throws Throwable {
                    System.out.println("after ret:"+ret+" method:"+m.getName()+" params'length:"+params.length+" target:"+target);
                }
            }
      3.2 环绕额外功能:
            implements MethodInterceptor{
                /**
                 * 主体逻辑
                 *   param:
                 *      mi:
                 */
                public Object invoke(MethodInvocation mi) throws Throwable {
                    System.out.println("tx begin~~~");
                    //调用目标的方法.
                    Object ret=mi.proceed();
                    System.out.println("tx commit~~~");
                    //接收目标方法的返回值,并向上返回给用户.
                    //注意:在环绕额外功能中,目标方法的返回值,务必要向上返回.
                    return ret;
                }
            }
      3.3 异常时的额外功能:目标抛出异常时触发.(了解)
            implements ThrowsAdvice{
                /**
                 * 主体逻辑:目标抛出异常时,执行
                 * @param ex :抛出的异常对象
                 */
                public void afterThrowing(Exception ex){
                    System.out.println("my throws :"+ex.getMessage());
                }
            }
    ====================================================================================
    4.execution表达式:描述切入点
      组成:返回值   包    类    方法名   参数表
      1>* com.c47.serivce.UserServiceImpl.deleteUser(..)
        返回值:任意
        包:com.c47.service
        类:UserServiceImpl
        方法:deleteUser
        参数表:任意
      2>* com.c47.serivce.UserServiceImpl.*(..)
        返回值:任意
        包:com.c47.service
        类:UserServiceImpl
        方法:任意
        参数表:任意
      3>* com.c47.serivce.*.*(..)
        返回值:任意
        包:com.c47.service
        类:任意
        方法:任意
        参数表:任意
      4>* *(..)
        返回值:任意
        包:任意
        类:任意
        方法:任意
        参数表:任意
      5>* login(..)
        返回值:任意
        包:任意
        类:任意
        方法:login
        参数表:任意
      6>技巧:* com.c47.serivce.UserServiceImpl.*User(..)
            返回值:任意
            包:com.c47.service
            类:UserServiceImpl
            方法:以User结尾的方法(便于批量的切入)
            参数表:任意
        建议:表达式,定义尽量精确.避免不必要的切入.
    ===================================================================================
    *基于AOP,抽取事务管理:
      1>DAO,Service,SessionFactory,DataSource 纳入工厂
      2>IOC满足依赖
      3>Service不再依赖SessionFactory
      4>定制环绕额外功能:事务管理
      5>IOC满足事务管理器的依赖
      6>AOP将事务管理器切入需要事务的业务方法中.

    1.原理:*动态代理类如何创建的.
              1>jdk代理  :通过和目标实现同一套接口,保证功能统一
              2>cglib代理:通过继承目标,保证功能统一.
              spring会动态的选择,如果目标有接口实现,则使用jdk代理,
              反之,则使用cglib.
           *为什么通过目标的BeanID===>Proxy
              1>BeanPostProcessor作用,再次加工.
    ======================================================================================
    2.动态代理类如何创建(jdk代理):
            //1.目标 target
            final UserService us=new UserServiceImpl();
            //2.额外功能
            InvocationHandler ih=new InvocationHandler(){
                /**
                 * method:方法对象
                 * args:参数列表
                 */
                public Object invoke(Object proxy, Method method, Object[] args)
                        throws Throwable {
                    System.out.println("before~~~");
                    //调用目标(us)的方法
                    Object ret=method.invoke(us, args);
                    System.out.println("after~~~");
                    return ret;
                }
            };
            //3.编织  *类加载器   *目标的所有实现的接口   *额外功能
            UserService usProxy=(UserService)Proxy.newProxyInstance(TestAOPYL.class.getClassLoader()
                                                                   ,us.getClass().getInterfaces()
                                                                   ,ih);
    ====================================================================================
    3.为什么通过目标的BeanID===>Proxy
      *BeanPostProcessor:后处理bean-->对工厂创建好的bean,进行再次的加工.
          被代理的Bean 生产过程:
          构造-->set-->
                    postProcessBeforeInitialization-->
                    init-->
                    postProcessAfterInitialization-->
                    用户
                    
      *定制后处理bean:
                implements BeanPostProcessor{
                    /**
                     * 在init之后执行
                     * param:bean=postProcessBeforeInitialization加工后的对象
                     */
                    public Object postProcessAfterInitialization(final Object bean, String arg1)
                            throws BeansException {
                        
                    }
                    /**
                     * 在init之前执行
                     * param:bean=工厂供创建的目标的bean的对象
                     */
                    public Object postProcessBeforeInitialization(Object bean, String arg1)
                            throws BeansException {
                        //加工
                        return bean;
                    }
                }
       *<!-- 声明后处理bean
             则在获取当前配置中的任何一个bean时,后处理bean,就会进行再加工
         -->
        <bean class="com.c47.postprocessor.MyPostProcessor"></bean>
    ===================================================================================
    4.spring事务管理:
      4.1 将 HibernateTransactionManager 纳入工厂,并IOC满足依赖:SessionFactory
            <!-- 并不是一个完整的事务管理器,其中,管理了事务控制的核心的逻辑
                         需要对其进一步的包装
            -->
            <bean id="tx47" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
                <property name="sessionFactory" ref="sessionFactory47"></property>
            </bean>
      4.2 进一步包装,获取真正的事务管理器
            <!-- 基于schema tx 包装真正的事务管理器
                 事务属性(attributes):
                    *隔离级别:1>读未提交   事务之间可以读取到彼此未提交的数据,会导致[脏读],并发性极好.
                                    [脏读]:一个事务中读取到了其他事务中未提交的数据
                           2>读提交    事务之间只可以读取到彼此已提交的数据,可防止[脏读].但不能防止[不可重复读],并发性较好
                                    [不可重复读]:一个事务中,多次读取统一条数据,结果不一致
                           3>可重复读     一个事务内,多次读取统一条数据,结果一致.可防止[脏读,不可重复读],但不能防止[幻影读],并发性较差
                                    [幻影读]:一个事务中,多次读取统一张表,数据行数不一致.
                           4>序列化读  多个事务是串行发生.可以防止一切不合法的读取,并发性极差.
                          oracle:1.读提交(默认)  2.序列化读
                    *传播性: REQUIRED:如果当前没有事务环境,开启事务;如果已有事务环境,则融入事务.
                           SUPPORTS:如果当前没有事务环境,则在非事务环境下执行;如果已有事务环境,则融入事务.
                    *读写性:read-only="true" 只读事务,事务中只能读.
                          read-only="false" 读写时序,事务中可读 可写.
                    *回滚时刻:rollback-for="java.lang.Exception" 在出现所有异常时,要回滚.
                                               细节:如果出现了RuntimeException,则会自动回滚.
                                                         但是如果出现了Exception,默认不会回滚,依然提交事务.
                事务特性:ACID
                        原子性
                        一致性
                        持久性
                        隔离性
            
            -->
            <tx:advice transaction-manager="tx47" id="txManager">
                <tx:attributes>
                    <tx:method name="queryUserByID" propagation="SUPPORTS"/>
                    <!-- <tx:method name="*User"/> -->
                    <!-- 其余方法 -->
                    <tx:method name="*" isolation="READ_COMMITTED" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception"/>
                </tx:attributes>
            </tx:advice>
            *事务管理器,定制完毕,AOP切入业务层中即可
    ===================================================================================
    5.spring对于DAO操作支持:进一步简化DAO操作
      HibernateTemplate:模板类,作用在DAO,将session封装到底层,构建了封装后的方法,以完成并
                       :简化DAO操作.
                       :集成session几乎所有的方法:get(),save(),delete(),update()
                       :如何执行HQL:template.find("HQL",Object... param);
                       :execute();//通用方法.
                            //execute方法会回调HibernateCallback中的doInHibernate
                            //且doInHibernate方法的返回值,就是execute方法的返回值.
                            template.execute(new HibernateCallback<List<User>>(){
                                    //param:session 即当前线程中使用的session
                                    public List<User> doInHibernate(Session session)
                                            throws HibernateException, SQLException {
                                        String hql="from User u order by u.id";
                                        Query query=session.createQuery(hql);
                                        query.setMaxResults(5);
                                        query.setFirstResult((pageNum-1)*5);
                                        return query.list();
                                    }
                                }
                            );
                       :其中将事务的自动提交置为true.   connection.setAutoCommit(true);
                         template.save(xx);
                         template.delete(xx);
                         利于测试DAO.
    ===================================================================================

    *spring   struts2   hibernate
     spring   struts2   mybatis
     基于注解的ssh
     *OpenSessionInViewFilter

    1.spring+struts整合
      1>搭建struts2
      2>将Action纳入工厂(注意:prototype)
      3>IOC满足Action依赖
      4>导入插件包:struts2-spring-plugin.jar
                  :在struts.xml配置Action时,<action  class="Action_BeanID" ....
                  :保证前端控制器从工厂中获取需要的Action实例
      5>启动工厂:定制监听器=org.springframework.web.context.ContextLoaderListener
                           =在项目启动时,启动工厂
                :定制context-param=contextConfigLocation
                                  =指示spring配置文件位置
    ======================================================================================
    2.spring+mybatis整合:
      1>构建连接池
      2>通过SqlSessionFactoryBean构建SqlSessionFactory
        *依赖点:
            *数据源
            *别名设置(可选)
            *映射文件位置
      3>通过MapperScannerConfigurer构建DAO接口的实现类
        *依赖点:
            *SqlSessionFactory
            *DAO接口所在位置
        *构建出的DAO接口实现类,会纳入工厂,且ID为对应接口名的首字母小写
      4>将构建好的DAO注入给Service
      5>搭建DataSourceTransactionManager(注入数据源)
        并通过<tx:advice 进一步包装出mybatis的事务管理器,切入service方法中
      6>整合struts2....
    =====================================================================================
    3.基于注解SSH整合:
      1>//将当前类纳入工厂,bean的ID默认为类名的首字母小写:userDAOImpl
        //也可以明确指定bean的ID
        @Component("userDAO") 作用在类上
      2> //指示当前bean是非单例/单例(默认)的.
         @Scope(value="prototype/singleton")  作用在类上
      3>//基于类型自动注入
        @Autowired   作用在属性
        //基于名称自动注入
        @Resource(name="userService")  作用在属性
      4>//作用在类上:缺省的为类中的所有方法指定事务属性.
        //作用在方法上:为方法单独的指定事务属性
        @Transactional(isolation=Isolation.READ_COMMITTED,propagation=Propagation.REQUIRED,readOnly=false,rollbackFor=Exception.class)
      *告知spring注解位置:
            <context:component-scan base-package="com.c47"></context:component-scan>
      *告知spring,事务注解切入的是什么事务:
            <bean id="tx47" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
            <tx:annotation-driven transaction-manager="tx47"/>
    =====================================================================================
    4.OpenSessionInViewFilter:
      :被此过滤器过滤的请求,Session有此过滤器管理:session在事务结束后依然是开启的,直到
       视图渲染完毕后,将session关闭,以解决延迟加载异常.
          <!-- 配置OpenSessionInViewFilter
                          注意:要在前端控制器之前定义
                          此过滤器依赖SessionFactory,且默认向工厂所要id为:"sessionFactory"的bean
                          如果工厂中的SessionFactory的beanID不是"sessionFactory",通过init-param指定
          -->
          <filter>
            <filter-name>osiv47</filter-name>
            <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
            <init-param>
                <param-name>sessionFactoryBeanName</param-name>
                <param-value>sessionFactory47</param-value>
            </init-param>
          </filter>
          <filter-mapping>
            <filter-name>osiv47</filter-name>
            <!-- 需要在页面中使用延迟属性的请求 -->
            <url-pattern>/ssh/user_queryOneUser</url-pattern>
            <url-pattern>/user/a</url-pattern>
            <url-pattern>/user/b</url-pattern>
            <url-pattern>/user/c</url-pattern>
            <url-pattern>/user/d</url-pattern>
            <url-pattern>/a</url-pattern>
            <url-pattern>/b</url-pattern>
          </filter-mapping>
    ====================================================================================

  • 相关阅读:
    Oracle数据库的左连接和右连接(+)
    Web文件上传模块 Plupload
    增加反向链接的35个技巧
    google map api 与jquery结合使用(1)控件,监听器[转帖]
    教你在windows 7/xp 下安装使用mencoder
    Oracle 全文索引
    提高关键词排名的28个SEO技巧
    二叉树遍历及C语言实现
    小额担保业务管理系统详细设计介绍
    C#与数据结构二叉树的遍历
  • 原文地址:https://www.cnblogs.com/gyadmin/p/8458741.html
Copyright © 2011-2022 走看看