文稿说明s培训springmvc source minibook_第1页
文稿说明s培训springmvc source minibook_第2页
文稿说明s培训springmvc source minibook_第3页
文稿说明s培训springmvc source minibook_第4页
文稿说明s培训springmvc source minibook_第5页
已阅读5页,还剩116页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、springmvc-source-minibookTable of ContentsIntroduction0SpringMVC入门1分发器DispatcherServlet分析2SpringMVC请求是如何找到正确的Controller3SpringMVC中Controller的方法中参数的工作原理4SpringMVC关于json、xml自动转换的原理5SpringMVC类型转换、数据绑定6SpringMVC器7SpringMVC视图机制8SpringMVC异常处理机制9Spring相关的知识10Spring中Ordered接口简介10.12springmvc-source-minibook

2、SpringMVC源码分析迷你书仓库阅读一本分析SpringMVC部分源码的mini书,基本上是从之前的博客中拷贝过来的,博客地址:这个mini书比较适合想深入学习SpringMVC的读者。这本书的文章都是基于Spring4.0.2版本的。文章阅读顺序如下:1.SpringMVC入门SpringMVC的入门文章, 对于某些没接触过SpringMVC的同学来说,可以阅读以下,了解这个框架的结构以及使用,以入门的同学可以选择不看2.分发器DispatcherServlet分析SpringMVCServlet -> DispatcherServlet的分析,解释了DispatcherServl

3、et的父类FrameworkServlet以及FrameworkServlet的父类HttpServletBean的作用3.SpringMVC请求是如何找到正确的Controller想知道http请求是如何找到对应Controller中的方法的吗,这个过程当中到底发生了什么,? 本篇将为你一一解答。4.SpringMVC中Controller的方法中参数的工作原理本文分析Controller中方法的参数是如何被注入进来的5.SpringMVC关于json、xml自动转换的原理通过json、xml的自动转换巩固第四篇文章的知识,自动转换由RequestResponseBodyMethodProc

4、essor处理,该类实现了HandlerMethodArgumentResolver和HandlerMethodReturnValueHandler接口。6.SpringMVC类型转换、数据绑定介绍了属性编辑器的概念以及Spring对属性编辑器的支持,本文知识消化之后可以回过头看第4篇中FormObjArgumentResolver的实现。7.SpringMVC器Introduction3springmvc-source-minibook解释了SpringMVC器的设计原理。8.SpringMVC视图机制分析了SpringMVC的视图机制,主要也就是讲解View和ViewResolver这两个

5、接口的作用。9.SpringMVC异常处理机制解释了SpringMVC异常机制的设计原理。SpringMVC是Spring大框架中的一个子框架,所以内部肯定用到了Spring框架的一些依赖,所以本书也会将一些Spring框架的内容,目前只写了1篇文章。1. Spring中Ordered接口简介文中难免会有错误,欢迎读者指出。Introduction4springmvc-source-minibook介绍SpringMVC是一款Web MVC框架。 它跟Struts框架类似,是目前主流的Web MVC框架之一。本章通过实例来介绍SpringMVC的入门知识。实例本章所写的实例是一个员工的CRUD

6、 demo。 用idea编写,基于maven, Web框架使用SpringMVC,视图采取Freemarker技术,数据库使用MySQL,用Hibernate4数据。项目文件目录如下:SpringMVC入门5springmvc-source-minibook首先在web.xml中配置servlet:SpringMVC入门6springmvc-source-minibook注意有个初始参数 contextConfigLocation, 顾名思义 上下文配置文件路径。,这个servlet对应的url-pattern最好写成 "/", 不要写成 "/*"。 至

7、于为还有另外一个什么需要写成 "/" , 具体请参考tomcat-urlPattern.html#springmvc在dispatcher-servlet.xml中主要是配置springmvc的一些Controller的初始化,静态文件的策略,视图的配置等。然后开始编写Controller类(类似Struts2中的Action)首先来看一个主页的Controller:这里有2个注解: Controller和RequestMappingController注解就是表明这是一个Controller,且会被spring容器进行初始化。dispatcher-servlet.xml中

8、的扫描包配置语句:SpringMVC入门7<context:component-scan base-package="org.format.demo.controller" />Controller RequestMapping("/")public class IndexController RequestMappingpublic MAndView index() MAndView view = new MAndView("index"); view.addObject("welcome", &qu

9、ot;hello");return view;<servlet><servlet-name>dispatcher</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springCon

10、fig/dispatcher-servlet.xml</param-value></init-param><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>dispatcher</servlet-name><url-pattern>/</url-pattern></servlet-mapping>springmvc-source-minibook这条语句是扫描o

11、rg.format.demo.controller下被Controller(还有其他的如 Component,Service, Repository)注解的那些类,并进行实例化。RequestMapping 顾名思义,就是请求。我们看到RequestMapping("/")中的"/"的意义就是contextPath后面的路径;也就是后面的路径。 (这里不一定都要以"/"开头,比如 "/employee", 我们可以写成 "employee" )MAndView对象就是一个带模型的视图对象。 我们

12、看到IndexController返回了1个index名称的MAndView对象。addObject对象就类似HttpServletRequest的setAttribute对象,也就是视图里面丢数据。 我们看到丢了一个key为welcome的对象。最后的视图代码:我们看到用了el表达式得到了丢入的数据welcome,也就是hello。 因此,最终生成的页面及地址如下:最后SpringMVC会通过配置文件中的视图对象拼接成最终的视图地址。SpringMVC入门8<!DOCTYPE html><html><head lang="en"><

13、;meta charset="UTF-8"><title></title></head><body><h2>Welcome to user SpringMVC</h2><h3>your welcome param: $welcome</h3></body></html>springmvc-source-minibook图中viewName也就是返回的M为 /WEB-INF/view/index.ftl。AndView中的viewName 即index

14、。 因此,最终的视图路径下面在来看一个员工操作的Controller代码:SpringMVC入门9springmvc-source-minibookControllerRequestMapping(value = "/employee") public class EmployeeController Autowiredprivate IEmployeeService employeeService;Autowiredprivate IDeptService deptService;RequestMappingpublic MAndView index() MAndView

15、 view = new MAndView("employee/list");List<Employee> employees = employeeService.list(); view.addObject("list", employees);return view;RequestMapping(method = RequestMethod.POST, value = "/delete/employeeId") ResponseBodypublic String delete(PathVariable Integer e

16、mployeeId) employeeService.delete(employeeId);return "success"RequestMapping(method = RequestMethod.GET, value = "/add")public MAndView add(MAndView view) view.setViewName("employee/form"); view.addObject("depts", deptService.listAll();return view;RequestMappi

17、ng(method = RequestMethod.GET, value = "/detail/employeeId")public MAndView detail(PathVariable Integer employeeId, MAndViewview)view.setViewName("employee/form");view.addObject("employee", employeeService.getById(employeeId); view.addObject("depts", deptServi

18、ce.listAll();return view;RequestMapping(method = RequestMethod.POST, value = "/update") public String add(Employee employee) if(employee.getDept().getId() = null) employee.setDept(null);employeeService.saveOrUpdate(employee); return "redirect:/employee/"SpringMVC入门10springmvc-sou

19、rce-minibook这里多了几个新的内容:1.RequestMapping注解的作用位置RequestMapping可以作用在类名上,也可以作用在方法上。 如果都有, 产生作用的路径是类名上的路径+方法上的路径。 比如EmployeeController的add方法,最终起作用的路径是2.RequestMapping注解的method参数method参数表示的HTTP请求的方式。常见的有GET,PUT,POST,DELETE等。若请求的方法与编写的方法不一致,会出现HTTP 405错误。3.PathVariable注解这是一种基于RESTFUL的注解。我们看到detail方法的Reques

20、tMapping的value值/detail/employeeId,参数中加入了一个PathVariable employeeId。 这样起作用的路径就根据employee的Id,即每个员工都有的一个URI路径。 符合RESTFUL架构。4.Controller的方法参数Controller的方法非常灵活。 比如Employee有id,name,age等属性。 只要我们在前台传入name为id,name,age这3个参数,并且接受的方法有一个Employee对象参数, SpringMVC会自动把3个注入到这个对象中。 还有其他一些Integer,Long参数等, SpringMVC会默认帮我们

21、自动转化。 同时参数也可以丢入一些HttpServletRequest, HttpServletResponse, HttpServletSession对象,SpringMVC会自动帮我们注入。 这点非常方便。5.不带参数基于方法的RequestMapping会被当然基于类的RequestMapping所作用的地址的默认进入的方法add方法。 get请求SpringMVC入门11springmvc-source-minibookdetail方法。 RESTFUL风格delete方法。RESTFUL风格总结SpringMVC是一个Web MVC框架。 它的特点是轻便,与Spring无缝整合,上手

22、简单。它的易用性、可扩展性、安全性均非常理想。参考资料SpringMVC入门12springmvc-source-minibookSpringMVC入门13springmvc-source-minibookDispatcherServlet初始化过程在分析DispatcherServlet之前,我们先看下DispatcherServlet的继承关系。HttpSerlvetBean继承自HttpServlet。HttpServletBean覆写了init方法,对初始化过程做了一些处理。 我们来看下init方法到底做了什么:比如上面这段配置,传递了contextConfigLocation参数,之

23、后构造BeanWrapper,这里使用BeanWrapper,有2个理由:分发器DispatcherServlet分析14<servlet><servlet-name>dispatcher</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><load-on-startup>1</load-on-startup><init-param><param-name&

24、gt;contextConfigLocation</param-name><param-value>classpath:springConfig/dispatcher-servlet.xml</param-value></init-param></servlet><servlet-mapping><servlet-name>dispatcher</servlet-name><url-pattern>/</url-pattern></servlet-mapping>

25、springmvc-source-minibook1. contextConfigLocation属性在FrameworkServlet中定义,HttpServletBean中未定义2. 利用Spring的注入特性,只需要调用setPropertyValues方法就可将contextConfigLocation属性设置到对应实例中,也就是以依赖注入的方式初始化属性。然后设置DispatcherServlet中的contextConfigLocation属性(FrameworkServlet中定义)为web.xml中的contextConfigLocation参数,该参数用于构造SpringMV

26、C容器上下文。下面看下FrameworkServlet这个类,FrameworkServlet继承自HttpServletBean。首先来看下该类覆写的initServletBean方法:接下来看下initWebApplicationContext方法的具体实现逻辑:分发器DispatcherServlet分析15springmvc-source-minibook这里的根上下文是web.xml中配置的ContextLoaderListenercontextConfigLocation路径生成的上下文。器中根据比如这段配置文件中根据classpath:springConfig/applicati

27、onContext.xml下的xml文件生成的根上下文。最后看下DispatcherServlet。DispatcherServlet覆写了FrameworkServlet中的onRefresh方法:很明显,initStrategies方法内部会初始化各个策略接口的实现类。比如异常处理初始化initHandlerExceptionResolvers方法:SpringMVC异常处理机制详解视图处理初始化initViewResolvers方法:SpringMVC视图机制详解请求处理初始化initHandlerMappings方法:详解SpringMVC请求的时候是如何找到正确的Controller

28、总结一下各个Servlet的作用:1.HttpServletBean分发器DispatcherServlet分析16<context-param><param-name>contextConfigLocation</param-name><param-value>classpath:springConfig/applicationContext.xml</param-value></context-param><listener><listener-class>org.springframework

29、.web.context.ContextLoaderListener</listener-class></listener>springmvc-source-minibook主要做一些初始化的工作,将web.xml中配置的参数设置到Servlet中。比如servlet的子init-param中配置的参数。2.FrameworkServlet将Servlet与Spring容器上下文关联。其实也就是初始化FrameworkServlet的属性webApplicationContext,这个属性代表SpringMVC上下文,它有个父类上下文,既web.xml中配置的Conte

30、xtLoaderListener器初始化的容器上下文。3.DispatcherServlet初始化各个功能的实现类。比如异常处理、视图处理、请求处理等。DispatcherServlet处理请求过程在分析DispatcherServlet处理请求过程之前,我们回顾一下Servlet对于请求的处理。HttpServlet提供了service方法用于处理请求,service使用了模板设计模式,在内部对于httpget方调用doGet方法,httppost方法调用doPost方法.进入processRequest方法看下:分发器DispatcherServlet分析17springmvc-sourc

31、e-minibook的器类型为ApplicationListener接口类型。其中继续看DispatcherServlet覆写的doService方法:分发器DispatcherServlet分析18springmvc-source-minibook最终就是doDispatch方法。doDispatch方能简单描述一下:首先根据请求的路径找到HandlerMethod(带有Method反射属性,也就是对应Controller中的方法),然后匹配路径对应的器,有了HandlerMethod和器构造个HandlerExecutionChain对象。HandlerExecutionChain对象的获

32、取是通过HandlerMapping接口提供的方法中得到。有了HandlerExecutionChain之后,通过HandlerAdapter对象进行处理得到MAndView对象,HandlerMethod内部handle的时候,使用各种HandlerMethodArgumentResolver实现类处理HandlerMethod的参数,使用各种HandlerMethodReturnValueHandler实现类处理返回值。 最终返回值被处理成M对象,这期间发生的异常会被HandlerExceptionResolver接口实现类进行处理。AndView总结本章分析了SpringMVCServl

33、et -> DispatcherServlet的作用,其中分析了父类HttpServletBean以及FrameworkServlet的作用。SpringMVC的设计与Struts2完全不同,Struts2采取的是一种完全和Web容器制,而SpringMVC就是基于最基本的request和response进行设计。和解耦的机参考资料分发器DispatcherServlet分析19springmvc-source-minibook分发器DispatcherServlet分析20springmvc-source-minibook前言我们使用浏览器通过地址进行,SpringMVC是如何得知用户

34、到底是哪个Controller中的方法,这期间到底。本章将分析SpringMVC是如何处理请求与Controller之间的关系的,让读者知道这个过程中到底事情。源码分析在分析源码之前,我们先了解一下几个东西。1.这个过程中重要的接口和类。HandlerMethod类:Spring3.1版本之后引入的。 是一个封装了方法参数、方法注解,方法返回值等众多元素的类。它的子类InvocableHandlerMethod有两个重要的属性WebDataBinderFactory和HandlerMethodArgumentResolverComposite,很明显是对请求进行处理的。InvocableHan

35、dlerMethod的子类ServletInvocableHandlerMethod有个重要的属性HandlerMethodReturnValueHandlerComposite,很明显是对响应进行处理的。ServletInvocableHandlerMethod这个类在HandlerAdapter对每个请求处理过程中,都会实例化一个出来(上面提到的属性由HandlerAdapter进行设置),分别对请求和返回进行处理。(RequestMappingHandlerAdapter源码,实例化ServletInvocableHandlerMethod的时候分别set了上面提到的重要属性)Sprin

36、gMVC请求是如何找到正确的Controller21springmvc-source-minibookMethodParameter类:HandlerMethod类中的parameters属性类型,是一个MethodParameter数组。MethodParameter是一个封装了方法参数具体信息的工具类,包括参数的的索引位置,类型,注解,参数名等信息。HandlerMethod在实例化的时候,构造函数中会初始化这个数组,这时只初始化了部分数据, 在HandlerAdapter对请求处理过程中会完善其他属性,之后交予合适的HandlerMethodArgumentResolver接口处理。以类

37、DeptController为例:(刚初始化时的数据)(HandlerAdapter处理后的数据)SpringMVC请求是如何找到正确的Controller22Controller RequestMapping(value = "/dept") public class DeptController Autowiredprivate IDeptService deptService;RequestMapping("/update") ResponseBodypublic String update(Dept dept) deptService.saveO

38、rUpdate(dept); return "success"springmvc-source-minibookReqondition接口:Spring3.1版本之后引入的。 是SpringMVC的基础中的请求条件,可以进行combine,compareTo,getMatchingCondition操作。这个接口是中getMatchingCondition方法关乎是否能找到合适的。匹配的关键接口,其RequestMappingInfo类:Spring3.1版本之后引入的。 是一个封装了各种请求的类。条件并实现了Reqondition接口有各种Reqondition实现类属性

39、,patternsCondition,methodsCondition,paramsCondition,headersCondition,consumesCondition以及producesCondition,这个请求条件看属性名也了解,分别代表http请求的路径模式、方法、参数、头部等信息。RequestMappingHandlerMapping类:处理请求与HandlerMethod关系的一个类。SpringMVC请求是如何找到正确的Controller23springmvc-source-minibook2.Web服务器启动的时候,SpringMVC到底做了什么。先看AbstractH

40、andlerMethodMapping的initHandlerMethods方法中。我们进入createRequestMappingInfo方法看下是如何构造RequestMappingInfo对象的。PatternsReqondition构造函数:SpringMVC请求是如何找到正确的Controller24springmvc-source-minibook类对应的RequestMappingInfo存在的话,跟方法对应的RequestMappingInfo进行combine操作。然后使用符合条件的method来各种HandlerMethod。下面我们来看下各种Reqondition接口的实

41、现类的combine操作。PatternsReqondition:SpringMVC请求是如何找到正确的Controller25springmvc-source-minibookRequestMethodsReqondition:方法的请求条件,用个set直接add即可。其他相关的Reqonditon实现类读者可自行查看源码。最终,RequestMappingHandlerMapping中两个比较重要的属性T为RequestMappingInfo。构造完成。SpringMVC请求是如何找到正确的Controller26private final Map<T, HandlerMethod&

42、gt; handlerMethods = new LinkedHashMap<T, HandlerMethod>(private final MultiValueMap<String, T> urlMap = new LinkedMultiValueMap<String, T>();springmvc-source-minibook我们知道,SpringMVC的分发器DispatcherServlet会根据浏览器的请求地址获得HandlerExecutionChain。这个过程我们看是如何实现的。首先看HandlerMethod的获得(直接看关键代码了):这

43、里的比较器是使用RequestMappingInfo的compareTo方法(Reqondition接口定义的)。然后构造HandlerExecutionChain加上器SpringMVC请求是如何找到正确的Controller27springmvc-source-minibook实例写了这么多,来点例子让我们验证一下吧。由于这里的每个pattern都带了*因此,都的。加入到urlMap中,但是handlerMethods还是有SpringMVC请求是如何找到正确的Controller28ControllerRequestMapping(value = "/wildcard"

44、;) public class TestWildcardController RequestMapping("/test/*") ResponseBodypublic String test1(MAndView view) view.setViewName("/test/test");view.addObject("attr", "TestWildcardController -> /test/*"); return view;RequestMapping("/test/*") Respo

45、nseBodypublic String test2(MAndView view) view.setViewName("/test/test");view.addObject("attr", "TestWildcardController -> /test*"); return view;RequestMapping("test?") ResponseBodypublic String test3(MAndView view) view.setViewName("/test/test");

46、view.addObject("attr", "TestWildcardController -> test?"); return view;RequestMapping("test/*") ResponseBodypublic String test4(MAndView view) view.setViewName("/test/test");view.addObject("attr", "TestWildcardController -> test/*");

47、return view;springmvc-source-minibook当我们:的时候。会先根据 "/wildcard/test1"找urlMap对应的RequestMappingInfo集合,找不到的话取handlerMethods集合中所有的key集合(也就是RequestMappingInfo集合)。然后进行匹配,匹配根据Reqondition的getMatchingCondition方法。最终匹配到2个RequestMappingInfo:然后会使用比较器进行排序。之前也分析过,比较器是有优先级的。我们看到,RequestMappingInfo除了pattern,

48、其他属性都是一样的。我们看下PatternsReqondition比较的逻辑:SpringMVC请求是如何找到正确的Controller29springmvc-source-minibook因此,/test*的通配符比/test?的多,因此,最终选择了/test?直接比较优先于通配符。SpringMVC请求是如何找到正确的Controller30springmvc-source-minibook这里例子,其他reqondition都一样,只有RequestMethodCondition不一样。看出,方法多的优先级越多。至于其他的Reqondition,大家自行查看源码吧。文件SpringMVC

49、请求是如何找到正确的Controller31ControllerRequestMapping(value = "/priority") public class TestPriorityController RequestMapping(method = RequestMethod.GET) ResponseBodypublic String test1(MAndView view) view.setViewName("/test/test");view.addObject("attr", "其他condition相同,带有

50、method属性的优先级高");return view;RequestMapping() ResponseBodypublic String test2(MAndView view) view.setViewName("/test/test");view.addObject("attr", "其他condition相同,不带method属性的优先级高");return view;springmvc-source-minibook以上分析均是基于Controller方法的(RequestMappingHandlerMappin

51、g)。SpringMVC中还有静态文件的,SimpleUrlHandlerMapping。DispatcherServlet找对应的HandlerExecutionChain的时候会遍历属性handlerMappings,这个一个实现了HandlerMapping接口的集合。由于我们在*-dispatcher.xml中加入了以下配置:Spring配置文件会使用ResourcesBeanDefinitionParser进行的时候,会实例化出SimpleUrlHandlerMapping。其中的HandlerMethod为ResourceHttpRequestHandler。SpringMVC请求

52、是如何找到正确的Controller32<mvc:resources location="/static/" mapping="/static/*"/>springmvc-source-minibook地址:地址匹配到/static/*。最终SimpleUrlHandlerMapping找到对应的Handler -> ResourceHttpRequestHandler。ResourceHttpRequestHandler进行handleRequest的时候,直接输出文件的文本内容。总结大致上整理了一下SpringMVC对请求的处理,包

53、括其中比较关键的类和接口,希望对读者有帮助。也让读者对SpringMVC有了更深入的认识,也为之后分析数据绑定,HandlerAdapter等打下基础。器、参考资料SpringMVC请求是如何找到正确的Controller33springmvc-source-minibook前言SpringMVC中Controller的方法参数可以是Integer,Double,自定义对象,ServletRequest,ServletResponse,MAndView等等,非常灵活。本章将分析SpringMVC是如何对这些参数进行处理的,使读者能够处理自定义的一些参数。现象本章使用的demo基于maven。我

54、们先来看一看对应的现象。首先这是一个Controller,有4个方法。他们对应的参数分别是带有RequestBody的自定义对象、自定义对象、带有RequestParam的自定义对象、日期对象。接下来我们一个一个方法进行看对应的现象是如何的。SpringMVC中Controller的方法中参数的工作原理34Controller RequestMapping(value = "/test") public class TestController RequestMapping("/testRb") ResponseBodypublic Employee t

55、estRb(RequestBody Employee e) return e;RequestMapping("/testCustomObj") ResponseBodypublic Employee testCustomObj(Employee e) return e;RequestMapping("/testCustomObjWithRp") ResponseBodypublic Employee testCustomObjWithRp(RequestParam Employee e) return e;RequestMapping("/te

56、stDate") ResponseBodypublic Date testDate(Date date) return date;springmvc-source-minibook首先第一个testRb:第二个testCustomObj:第三个testCustomObjWithRp:第四个testDate:SpringMVC中Controller的方法中参数的工作原理35springmvc-source-minibook为何返回的Employee对象会被自动为xml,请看另一篇章节:戳我为何Employee参数会被,带有RequestParam的Employee参数错?被,甚至报为何

57、日期类型不能被?SpringMVC到底是如何处理这些方法的参数的?RequestBody、RequestParam这两个注解有什么区别?带着这几个问题。我们开始进行分析。源码分析本章所分析的源码是Spring版本4.0.2在分析源码之前,首先让我们来看下SpringMVC中两个重要的接口。两个接口分别对应请求方法参数的处理、响应返回值的处理,分别是HandlerMethodArgumentResolver和HandlerMethodReturnValueHandler,这两个接口都是Spring3.1版本之后加入的。SpringMVC中Controller的方法中参数的工作原理36springmvc-source-minibookSpringMVC处理请求大致是这样的:首先被DispatcherServlet截获,Dispat

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论