zoukankan      html  css  js  c++  java
  • 20201205 Spring MVC

    Spring MVC 应用

    三层架构 和 MVC 设计模式

    img

    MVC 对应于三层架构中的 表现层

    三层架构:

    • 表现层
    • 业务层
    • 持久层

    MVC 设计模式:

    • Model(模型)
    • View(视图)
    • Controller(控制器)

    Spring MVC 介绍

    Spring MVC 本质可以认为是对 Serlvet 的封装,简化了我们 Serlvet 的开发

    Spring MVC 请求处理流程 :

    img

    开发过程:

    1. 配置 DispatcherServlet 前端控制器
    2. 开发处理具体业务逻辑的 Handler(@Controller@RequestMapping
    3. XML 配置文件配置 Controller 扫描,配置 Spring MVC 三⼤件
    4. 将 XML ⽂件路径告诉 Spring MVC (DispatcherServlet

    Spring MVC 请求处理流程 :

    img

    1. 用户发送请求至前端控制器 DispatcherServlet
    2. DispatcherServlet 收到请求调用 HandlerMapping 处理器映射器
    3. 处理器映射器根据请求 Url 找到具体的 Handler(后端控制器),生成处理器对象及处理器拦截器(如果 有则生成)⼀并返回 DispatcherServlet
    4. DispatcherServlet 调用 HandlerAdapter 处理器适配器去调⽤ Handler
    5. 处理器适配器执⾏ Handler
    6. Handler 执⾏完成给处理器适配器返回 ModelAndView
    7. 处理器适配器向前端控制器返回 ModelAndViewModelAndView 是 SpringMVC 框架的⼀个底层对象,包括 ModelView
    8. 前端控制器请求视图解析器去进行视图解析,根据逻辑视图名来解析真正的视图。
    9. 视图解析器向前端控制器返回 View
    10. 前端控制器进行视图渲染,就是将模型数据(在 ModelAndView 对象中)填充到 request 域前端控制器向用户响应结果

    Spring MVC 九⼤组件

    定义和初始化方法:org.springframework.web.servlet.DispatcherServlet#initStrategies

    • HandlerMapping(处理器映射器)
    • HandlerAdapter(处理器适配器)
    • HandlerExceptionResolver(处理器异常解析器)
    • ViewResolver(视图解析器)
    • RequestToViewNameTranslator(请求到视图名称翻译器)
    • LocaleResolver(国际化解析器)
    • ThemeResolver(主题解析器)
    • MultipartResolver(文件上传解析器)
    • FlashMapManagerFalshMap 管理器)

    默认的初始化配置定义文件:DispatcherServlet.properties

    # Default implementation classes for DispatcherServlet's strategy interfaces.
    # Used as fallback when no matching beans are found in the DispatcherServlet context.
    # Not meant to be customized by application developers.
    
    org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
    
    org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
    
    org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,
    	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
    
    org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,
    	org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,
    	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
    
    org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,
    	org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,
    	org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
    
    org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
    
    org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
    
    org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
    

    请求参数绑定

    绑定简单数据类型参数,只需要直接声明形参即可(形参参数名和传递的参数名要保持⼀致,建议使用包装类型,当形参参数名和传递参数名不⼀致时可以使用 @RequestParam 注解进行手动映射

    • 默认支持 Servlet API 作为方法参数

      • HttpServletRequestHttpServletResponseHttpSession
    • 绑定简单类型参数

      • 简单数据类型:八种基本数据类型及其包装类型
        • 参数类型推荐使用包装数据类型,因为基础数据类型不可以为 null
      • 整型: Integerint
      • 字符串: String
      • 单精度: Floatfloat
      • 双精度: Doubledouble
      • 布尔型: Booleanboolean
        • 对于布尔类型的参数, 请求的参数值为 truefalse。或者 10
    • 绑定 Pojo 类型参数

      • 要求传递的参数名必须和 Pojo 的属性名保持⼀致
    • 绑定 Pojo 包装对象参数

      /demo/handle05?user.id=1&user.username=zhangsan
      
      public class QueryVo {
          private String mail;
          private String phone;
      }
      
      @RequestMapping("/handle05")
      public ModelAndView handle05(QueryVo queryVo) {
      
      }
      
    • 绑定日期类型参数(需要配置自定义类型转换器)

    对 Restful 风格请求⽀持

    • REST(英文: Representational State Transfer,简称 REST)描述了⼀个架构样式的网络系统
    • 资源 表现层 状态转移
    • REST 并没有⼀个明确的标准,而更像是⼀种设计的风格。
    <input type="hidden" name="_method" value="put"/>
    
    @RequestMapping(value = "/handle/{id}/{name}",method = {RequestMethod.PUT})
    public ModelAndView handlePut(@PathVariable("id") Integer id,@PathVariable("name") String username) {
    }
    
    <!--配置springmvc请求⽅式转换过滤器,会检查请求参数中是否有_method参数,如果有就
    按照指定的请求⽅式进⾏转换-->
    <filter>
        <filter-name>hiddenHttpMethodFilter</filter-name>
        <filterclass>org.springframework.web.filter.HiddenHttpMethodFilter</filterclass>
    </filter>
    <filter-mapping>
        <filter-name>hiddenHttpMethodFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    

    Spring MVC ⾼级技术

    拦截器(Inteceptor)使用

    • Servlet:处理 Request 请求和 Response 响应
    • 过滤器(Filter):对 Request 请求起到过滤的作用,作用在 Servlet 之前,如果配置为 /* 可以对所有的资源访问(servlet、 js/css 静态资源等)进行过滤处理
    • 监听器(Listener):实现了 javax.servlet.ServletContextListener 接口的服务器端组件,它随 Web应用的启动而启动,只初始化⼀次,然后会⼀直运行监视,随 Web 应用的停止而销毁
      • 作用一: 做一些初始化⼯作, web 应用中 Spring 容器启动 ContextLoaderListener
      • 作用二: 监听 web 中的特定事件,比如 HttpSessionServletRequest 的创建和销毁;变量的创建、销毁和修改等。可以在某些动作前后增加处理,实现监控,比如统计在线⼈数,利用 HttpSessionLisener 等。
    • 拦截器(Interceptor):是 SpringMVC、 Struts 等表现层框架自己的,不会拦截 jsp/html/css/image 的访问等,只会拦截访问的控制器⽅法(Handler)。
    • 从配置的角度也能够总结发现: serlvet 、 filter 、 listener 是配置在 web.xml 中的,而 interceptor 是配置在表现层框架自己的配置文件中的
      • 在 Handler 业务逻辑执行之前拦截一次
      • 在 Handler 逻辑执行完毕但未跳转页面之前拦截一次
      • 在跳转页面之后拦截一次

    img

    源码参考:

    • org.springframework.web.servlet.DispatcherServlet#doDispatch
    • org.springframework.web.servlet.HandlerInterceptor

    执行过程:

    1. 程序先执行 preHandle() 方法,如果该方法的返回值为 true ,则程序会继续向下执行处理器中的方法,否则将不再向下执行。
    2. 在业务处理器(即控制器 Controller 类)处理完请求后,会执行 postHandle() 方法,然后会通过 DispatcherServlet 向客户端返回响应。
    3. DispatcherServlet 处理完请求后,才会执行 afterCompletion() 方法。

    多个拦截器的执行流程:

    img

    文件上传

    <!--⽂件上传所需jar坐标-->
    <dependency>
        <groupId>commons-fileupload</groupId>
        <artifactId>commons-fileupload</artifactId>
        <version>1.3.1</version>
    </dependency>
    
    
    
    <!--配置⽂件上传解析器, id是固定的multipartResolver-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!--设置上传⼤⼩,单位字节-->
        <property name="maxUploadSize" value="1000000000"/>
    </bean>
    
    
    
    @RequestMapping("upload")
    public String upload(MultipartFile uploadFile, HttpServletRequest request) throws IOException {
    
    }
    

    异常控制

    异常处理的三种方式,默认优先级从上到下:

    1. 在 Controller 内定义 @ExceptionHandler 注解方法,处理 Controller 内的异常

      @ExceptionHandler({ArithmeticException.class})
      @ResponseBody
      public String testEx() {
          return "testEx";
      }
      
    2. @ControllerAdvice 全局异常处理

      // 可以让我们优雅的捕获所有Controller对象handler⽅法抛出的异常
      @ControllerAdvice
      public class GlobalExceptionResolver {
      
          @ExceptionHandler(ArithmeticException.class)
          public ModelAndView handleException(ArithmeticException exception, HttpServletResponse response) {
              ModelAndView modelAndView = new ModelAndView();
              modelAndView.addObject("msg",exception.getMessage());
              modelAndView.setViewName("error");
              return modelAndView;
          }
      
      }
      
    3. 自定义 HandlerExceptionResolver

      可以通过设置 Order 来自定义在 DispatcherServlet#handlerExceptionResolvers 中的位置,默认为最后,如果设置了 order 小于 0,则最先处理

    DispatcherServlet 九大组件之一:DispatcherServlet#handlerExceptionResolvers

    获取异常处理方法:

    • org.springframework.web.servlet.DispatcherServlet#processDispatchResult
      • org.springframework.web.servlet.DispatcherServlet#processHandlerException
        • 遍历 handlerExceptionResolvers,处理异常

    初始化 handlerExceptionResolvers 的默认策略 DispatcherServlet.properties 中:

    org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,
    	org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,
    	org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
    

    解析 mvc:annotation-driven 标签时,会在容器中增加三个 HandlerExceptionResolver

    • org.springframework.web.servlet.config.MvcNamespaceHandler#init

      • org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser#parse

        • ExceptionHandlerExceptionResolver

          • order 为 0
        • ResponseStatusExceptionResolver

          • order 为 1
        • DefaultHandlerExceptionResolver

          • order 为 2

    Controller 内的 @ExceptionHandler 注解方法和 @ControllerAdvice 全局异常处理与 ExceptionHandlerExceptionResolver 相关

    • org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver#getExceptionHandlerMethod

    ExceptionHandlerExceptionResolver 关联 @ControllerAdvice 方法:

    • org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver#exceptionHandlerAdviceCache
    • org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver#initExceptionHandlerAdviceCache

    基于 Flash 属性的跨重定向请求数据传递

    return "redirect:handle01?name=" + name;
    
    
    
    /**
     * SpringMVC 重定向时参数传递的问题
     * 转发:A 找 B 借钱400,B没有钱但是悄悄的找到C借了400块钱给A
     *      url不会变,参数也不会丢失,一个请求
     * 重定向:A 找 B 借钱400,B 说我没有钱,你找别人借去,那么A 又带着400块的借钱需求找到C
     *      url会变,参数会丢失需要重新携带参数,两个请求
     */
    
    @RequestMapping("/handleRedirect")
    public String handleRedirect(String name,RedirectAttributes redirectAttributes) {
    
        //return "redirect:handle01?name=" + name;  // 拼接参数安全性、参数长度都有局限
        // addFlashAttribute方法设置了一个flash类型属性,该属性会被暂存到session中,在跳转到页面之后该属性销毁
        redirectAttributes.addFlashAttribute("name",name);
        return "redirect:handle01";
    
    }
    

    手写 MVC 框架

    Spring MVC 源码深度剖析

    核心方法:org.springframework.web.servlet.DispatcherServlet#doDispatch

    1. 调用 getHandler() 获取到能够处理当前请求的执行链 HandlerExecutionChain(Handler + 拦截器)
    2. 调用 getHandlerAdapter() 获取能够执行 Handler 的适配器
    3. 适配器调用 Handler 执行 ha.handle (总会返回一个 ModelAndView 对象)
    4. 调用 processDispatchResult() 方法完成视图渲染跳转

    SSM 整合

    整合目标:

    • 数据库连接池以及事务管理都交给 Spring 容器来完成
    • SqlSessionFactory 对象应该放到 Spring 容器中作为单例对象管理
    • Mapper 动态代理对象交给 Spring 管理,我们从 Spring 容器中直接获得 Mapper 的代理对象
    1. 目录结构

      img
    2. POM

      <dependencies>
      
              <!--spring相关 START-->
      
              <!--SpringMVC-->
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-webmvc</artifactId>
                  <version>5.1.12.RELEASE</version>
              </dependency>
      
      
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-context</artifactId>
                  <version>5.1.12.RELEASE</version>
              </dependency>
      
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-jdbc</artifactId>
                  <version>5.1.12.RELEASE</version>
              </dependency>
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-tx</artifactId>
                  <version>5.1.12.RELEASE</version>
              </dependency>
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-aop</artifactId>
                  <version>5.1.12.RELEASE</version>
              </dependency>
              <dependency>
                  <groupId>org.aspectj</groupId>
                  <artifactId>aspectjweaver</artifactId>
                  <version>1.8.9</version>
              </dependency>
              <!--spring相关 END-->
      
              <!--mybatis START-->
              <dependency>
                  <groupId>org.mybatis</groupId>
                  <artifactId>mybatis</artifactId>
                  <version>3.4.5</version>
              </dependency>
              <!--mybatis与spring的整合包-->
              <dependency>
                  <groupId>org.mybatis</groupId>
                  <artifactId>mybatis-spring</artifactId>
                  <version>2.0.3</version>
              </dependency>
              <!--mybatis END-->
      
              <!--数据库相关 START-->
              <dependency>
                  <groupId>mysql</groupId>
                  <artifactId>mysql-connector-java</artifactId>
                  <version>5.1.46</version>
              </dependency>
              <!--druid连接池-->
              <dependency>
                  <groupId>com.alibaba</groupId>
                  <artifactId>druid</artifactId>
                  <version>1.1.21</version>
              </dependency>
              <!--数据库相关 END-->
      
              <!--jsp-api&servlet-api START-->
              <dependency>
                  <groupId>javax.servlet</groupId>
                  <artifactId>jsp-api</artifactId>
                  <version>2.0</version>
                  <scope>provided</scope>
              </dependency>
              <dependency>
                  <groupId>javax.servlet</groupId>
                  <artifactId>javax.servlet-api</artifactId>
                  <version>3.1.0</version>
                  <scope>provided</scope>
              </dependency>
              <!--页面使用jstl表达式-->
              <dependency>
                  <groupId>jstl</groupId>
                  <artifactId>jstl</artifactId>
                  <version>1.2</version>
              </dependency>
              <dependency>
                  <groupId>taglibs</groupId>
                  <artifactId>standard</artifactId>
                  <version>1.1.2</version>
              </dependency>
              <!--jsp-api&servlet-api END-->
      
              <!--json数据交互所需jar START-->
              <dependency>
                  <groupId>com.fasterxml.jackson.core</groupId>
                  <artifactId>jackson-core</artifactId>
                  <version>2.9.0</version>
              </dependency>
              <dependency>
                  <groupId>com.fasterxml.jackson.core</groupId>
                  <artifactId>jackson-databind</artifactId>
                  <version>2.9.0</version>
              </dependency>
              <dependency>
                  <groupId>com.fasterxml.jackson.core</groupId>
                  <artifactId>jackson-annotations</artifactId>
                  <version>2.9.0</version>
              </dependency>
              <!--json数据交互所需jar END-->
      
              <!--test START-->
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-test</artifactId>
                  <version>5.1.12.RELEASE</version>
              </dependency>
              <!--junit-->
              <dependency>
                  <groupId>junit</groupId>
                  <artifactId>junit</artifactId>
                  <version>4.12</version>
                  <scope>test</scope>
              </dependency>
              <!--test END-->
          </dependencies>
      
    3. web.xml

      <!DOCTYPE web-app PUBLIC
              "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
              "http://java.sun.com/dtd/web-app_2_3.dtd" >
      
      <web-app>
          <display-name>Archetype Created Web Application</display-name>
      
      
          <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>
      
      
          <!--springmvc启动-->
          <servlet>
              <servlet-name>springmvc</servlet-name>
              <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
              <init-param>
                  <param-name>contextConfigLocation</param-name>
                  <param-value>classpath*:springmvc.xml</param-value>
              </init-param>
              <load-on-startup>1</load-on-startup>
          </servlet>
      
      
          <servlet-mapping>
              <servlet-name>springmvc</servlet-name>
              <url-pattern>/</url-pattern>
          </servlet-mapping>
      </web-app>
      
    4. applicationContext-dao.xml

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:context="http://www.springframework.org/schema/context"
             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.xsd
             http://www.springframework.org/schema/context
             http://www.springframework.org/schema/context/spring-context.xsd">
      
          <!--数据库连接池以及事务管理都交给Spring容器来完成-->
      
          <!--引入外部资源文件-->
          <context:property-placeholder location="classpath:jdbc.properties"/>
      
          <!--第三方jar中的bean定义在xml中-->
          <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
              <property name="driverClassName" value="${jdbc.driver}"/>
              <property name="url" value="${jdbc.url}"/>
              <property name="username" value="${jdbc.username}"/>
              <property name="password" value="${jdbc.password}"/>
          </bean>
      
      
          <!--
              SqlSessionFactory对象应该放到Spring容器中作为单例对象管理
              原来mybaits中sqlSessionFactory的构建是需要素材的:SqlMapConfig.xml中的内容
          -->
          <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
              <!--别名映射扫描-->
              <property name="typeAliasesPackage" value="com.lagou.edu.pojo"/>
              <!--数据源dataSource-->
              <property name="dataSource" ref="dataSource"/>
          </bean>
      
      
          <!--Mapper动态代理对象交给Spring管理,我们从Spring容器中直接获得Mapper的代理对象-->
          <!--扫描mapper接口,生成代理对象,生成的代理对象会存储在ioc容器中-->
          <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
              <!--mapper接口包路径配置-->
              <property name="basePackage" value="com.lagou.edu.mapper"/>
              <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
          </bean>
      
      </beans>
      
    5. applicationContext-service.xml

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:context="http://www.springframework.org/schema/context"
             xmlns:tx="http://www.springframework.org/schema/tx"
             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.xsd
             http://www.springframework.org/schema/context
             http://www.springframework.org/schema/context/spring-context.xsd
             http://www.springframework.org/schema/tx
             http://www.springframework.org/schema/tx/spring-tx.xsd
      ">
      
          <!--包扫描 Service-->
          <context:component-scan base-package="com.lagou.edu.service"/>
      
          <!--事务管理-->
          <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
              <property name="dataSource" ref="dataSource"/>
          </bean>
      
          <!--事务管理注解驱动-->
          <tx:annotation-driven transaction-manager="transactionManager"/>
      
      </beans>
      
    6. springmvc.xml

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns:context="http://www.springframework.org/schema/context"
             xmlns:mvc="http://www.springframework.org/schema/mvc"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns="http://www.springframework.org/schema/beans"
             xsi:schemaLocation="http://www.springframework.org/schema/beans
             http://www.springframework.org/schema/beans/spring-beans.xsd
             http://www.springframework.org/schema/context
             http://www.springframework.org/schema/context/spring-context.xsd
             http://www.springframework.org/schema/mvc
             http://www.springframework.org/schema/mvc/spring-mvc.xsd
      ">
      
          <!--包扫描 Controller-->
          <context:component-scan base-package="com.lagou.edu.controller"/>
      
          <!--配置springmvc注解驱动,自动注册合适的组件 handlerMapping 和 handlerAdapter -->
          <mvc:annotation-driven/>
      
      </beans>
      
    7. jdbc.properties

      jdbc.driver=com.mysql.jdbc.Driver
      jdbc.url=jdbc:mysql://localhost:3306/bank
      jdbc.username=root
      jdbc.password=123456
      

    乱码问题解决

    • Post 请求乱码, web.xml 中加入过滤器

      <!-- 解决post乱码问题 -->
      <filter>
          <filter-name>encoding</filter-name>
          <filter-class>
              org.springframework.web.filter.CharacterEncodingFilter
          </filter-class>
          <!-- 设置编码参是UTF8 -->
          <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>
      </filter>
      <filter-mapping>
          <filter-name>encoding</filter-name>
          <url-pattern>/*</url-pattern>
      </filter-mapping>
      
    • Get 请求乱码(Get 请求乱码需要修改 tomcat 下 server.xml 的配置)

      <Connector URIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
      

    参考资料

  • 相关阅读:
    进阶篇:3.2.5)DFM钣金-常见装配和成形结构
    基础篇:3.4)3d模型绘制的好坏会影响产品合格率(注意点)
    进阶篇:2.1)DFMA实施障碍和关键
    [洛谷P2224][题解][HNOI2001]产品加工
    [洛谷P1262][题解]间谍网络
    [洛谷P3919][题解]可持久化数组&&主席树讲解
    [洛谷P5677][题解][GZOI2017]配对统计
    [洛谷P1040][题解]加分二叉树
    [校内赛3-1][题解]folder
    [校内赛3-3][题解]block
  • 原文地址:https://www.cnblogs.com/huangwenjie/p/14090296.html
Copyright © 2011-2022 走看看