Spring4官方文档学习WebMVC框架施比受有福

SpringWebMVC框架是围绕DispatcherServlet设计的,所谓DispatcherServlet就是将请求分发到handler,需要有配置好的handler映射、视图解析、本地化、时区、theme解决方案、还有上传文件的支持。默认的handler是基于@Controller和@RequestMapping注解。自Spring3.0起,@Controller注解还能用于RESTful,需要配合@PathVariable以及其他特性。

SpringWebMVC和Spring的设计准则是“对扩展开放,对修改关闭”--可以扩展,不能修改。

SpringWebMVC中核心类的一些方法被标记为final。开发者不能覆盖这些方法以提供自己的行为。这不是任性,而是遵从设计准则。

在SpringMVC中,你不能为final方法添加advice。

在SpringWebMVC中,你可以使用任何对象作为命令对象或者form-backing对象;你不需要实现框架的特定接口或者基类。Spring的数据绑定是高度弹性的:例如,它将类型错误匹配视为校验错误,而非系统错误,从而可被应用evaluate。

Spring的viewresolution是非常弹性的。Controller负责准备一个modelMap,其中带有数据,还负责挑选一个viewname--也可以直接写到响应流而完成一个请求。viewnameresolution是高度可定制的,使用文件扩展名或者Acceptheadercontenttypenegotiation,通过beannames、properties文件、或者,甚至一个自定义的ViewResolver实现。model(MVC中的M)是一个Map接口,允许view技术的完全抽象。你可以直接集成基于模板的rendering技术,例如JSP、Velocity和Freemarker、或者直接生成XML、JSON、Atom、以及很多其他内容类型。modelMap会被简单的变成合适的格式,如JSP请求属性、如Velocity模板模型。

1.1、SpringWebMVC的特性

SpringWebFlow

目标是成为管理web应用页面流程的最佳解决方案。

SWF集成了现有的框架,如SpringMVC和JSF,在Servlet和Portlet环境中。如果你有一个业务process(或多个)想从conversationalmodel中受益(与纯requestmodel相比),那么SWF就是这种解决方案。

SWF允许你捕获logicalpageflows,将其作为self-containedmodules,可以在不同环境下复用,因此,这是构建web应用模块的理想方式,能够引导用户--使用驱动业务processes的controllednavigations。

Spring的web模块包含许多独特的web支持特性:

1.2、其他MVC实现的可插拔性

对于某些项目来说,非Spring的MVC实现更适合。很多团队希望借用已有的投资(囧,真抽象),例如,使用JSF。

如果你不想使用SpringWebMVC,而想使用Spring提供的其他解决方案,你可以将你选择的webMVC框架集成到Spring中,这很简单。通过Spring的ContextLoaderListener启动Spring的rootapplicationcontext,可以在任意actionobject中通过它的ServletContext属性来获取它--也可以使用Spring的相应帮助方法来获取。

2、DispatcherServlet

像很多其他webMVC框架一样,SpringMVC框架也是请求驱动的,围绕一个中心Servlet来设计,该中心Servlet可以分发请求到Controllers,并提供其他功能。然而Spring的DispatcherServlet做的更多。它被彻底地与SpringIoC容器集成到了一起,所以,你可以使用Spring的所有特性。

SpringMVCDispatcherServlet处理请求的工作流程如下图所示。聪明的读者会认出DispatcherServlet是FrontController设计模式的一种实现。

DispatcherServlet是一个具体的Servlet(继承自HttpServlet基类),所以你需要使用一个URLmapping来映射请求--就是你想让DispatcherServlet处理的请求。这是一个标准JavaEEServlet配置,在Servlet3.0+环境下可以这样注册该Servlet:

publicclassMyWebApplicationInitializerimplementsWebApplicationInitializer{//这个接口,或者其抽象实现类@OverridepublicvoidonStartup(ServletContextcontainer){ServletRegistration.Dynamicregistration=container.addServlet("example",newDispatcherServlet());registration.setLoadOnStartup(1);registration.addMapping("/example/*");}}上面的例子中,所有以/example开头的请求都会由名字为example的DispatcherServlet实例来处理。

WebApplicationInitializer是SpringMVC提供的接口,可以确保基于代码的配置被探测到、且被自动用于初始化Servlet3容器。该接口的一个abstract基类是AbstractAnnotationConfigDispatcherServletInitializer,该abstract基类注册DispatcherServlet更简便,只需要指定映射、列出配置类即可--这是设置SpringMVC项目的一种推荐的方式(javaconfig)。

或者,传统模式,web.xml中的设置方式:

exampleorg.springframework.web.servlet.DispatcherServlet1example/example/*

在前面曾讲过,在Spring中,ApplicationContext实例可以被scoped(就是有scope)。

在DispatcherServlet初始化过程中,SpringMVC会在web应用的/WEB-INF文件夹下查找名字为[servlet-name]-servlet.xml的文件,创建其中定义的bean,并会重写在全局scope中已经定义的任何beans的定义。

看一下下面的DispatcherServlet配置:

根据上面的Servlet配置,还需要一个文件:/WEB-INF/golfing-servlet.xml。该文件会包含所有的SpringMVC特定的组件(beans)。当然,你可以更改该路径,通过特定的Servlet初始化参数(详见下面)。

对于单DispatcherServlet情景来说,也可以只有一个rootcontext。

这可以通过设置一个空的contextConfigLocationservletinit参数来配置,如下:

WebApplicationContext是简单的ApplicationContext的一个扩展,针对web应用拥有一些额外的特性。

它不同于normalApplicationContext的地方是它能够resolvethemes,它还知道关联哪个Servlet(通过到ServletContext的连接)。

WebApplicationContext被束缚在ServletContext中,通过使用RequestContextUtils类的静态方法,你可以随时查找WebApplicationContext。

注意,我们可以使用基于Java的配置达到同样的目的:

2.1、在WebApplicationContext中的特殊的beantypes

SpringDispatcherServlet使用特殊的beans来处理请求并渲染视图。这些beans是SpringMVC的一部分。你可以选择使用哪个--只需要在WebApplicationContext中简单的配置一些即可。

SpringMVC维护了一个默认beans列表以供使用,下一部分会讲。

现在先来看看DispatcherServlet依赖的特殊的beantypes:

2.2、默认的DispatcherServlet配置

上面有提到,对每个特殊的bean,DispatcherServlet默认都维护了一个实现列表以供使用。这个信息保存在DispatcherServlet.properties中,在org.springframework.web.servlet包下。

所有的特殊的beans都有其合理的默认(bean还是设置?)。或早或晚,你总会需要定制这些beans提供的一个或多个properties。例如,配置InternalResourceViewResolver的prefixproperty。

这里最需要理解的概念就是:一旦你在你的WebApplicationContext中配置了一个特殊的bean,如InternalResourceViewResolver,你就完全重写了某个类型的默认的实现列表。例如,如果你配置了InternalResourceViewResolver,那默认的ViewResolver实现列表会被忽略!

2.3、DispatcherServlet处理顺序

当你setup了一个DispatcherServlet,然后一个由其负责的request进来了,这时该DispatcherServlet会以如下流程开始处理请求:

SpringDispatcherServlet也支持返回last-modification-date(最后修改日期),如同ServletAPI中指定的一样。决定特定request的lastmodificationdate的处理是简单粗暴的:DispatcherServlet会查找合适的handlermapping,并测试找到的handler是否实现了LastModified接口。如果实现了,longgetLastModified(request)方法的值会被返回。

DispatcherServlet初始化参数

3.、实现Controller

Controller将用户的input解释并转成一个model,该model可以通过view描述给用户。

Spring2.5为MVCControllers引入了基于注解的编程模型,使用诸如@RequestMapping、@RequestParam、@ModelAttribute之类的注解。在ServletMVC和PortletMVC中都可用。

@Controller//一个注解即可ControllerpublicclassHelloWorldController{@RequestMapping("/helloWorld")//publicStringhelloWorld(Modelmodel){model.addAttribute("message","HelloWorld!");return"helloWorld";}}3.1、使用@Controller定义一个Controller

@Controller注解用于标记一个class拥有controller的角色。

注意,这种注解Controller需要开启自动探测才能使用。如下:

3.2、使用@RequestMapping映射requests

使用@RequestMapping注解将URLs如/app映射到一个类或者特定的handler方法。示例:

@Controller@RequestMapping("/appointments")publicclassAppointmentsController{privatefinalAppointmentBookappointmentBook;@AutowiredpublicAppointmentsController(AppointmentBookappointmentBook){this.appointmentBook=appointmentBook;}@RequestMapping(method=RequestMethod.GET)publicMapget(){returnappointmentBook.getAppointmentsForToday();}@RequestMapping(path="/{day}",method=RequestMethod.GET)publicMapgetForDay(@PathVariable@DateTimeFormat(iso=ISO.DATE)Dateday,Modelmodel){returnappointmentBook.getAppointmentsForDay(day);}@RequestMapping(path="/new",method=RequestMethod.GET)publicAppointmentFormgetNewForm(){returnnewAppointmentForm();}@RequestMapping(method=RequestMethod.POST)publicStringadd(@ValidAppointmentFormappointment,BindingResultresult){if(result.hasErrors()){return"appointments/new";}appointmentBook.addAppointment(appointment);return"redirect:/appointments";}}class级别上的@RequestMapping不是强制的。

@ControllerpublicclassClinicController{privatefinalClinicclinic;@AutowiredpublicClinicController(Clinicclinic){this.clinic=clinic;}@RequestMapping("/")publicvoidwelcomeHandler(){}@RequestMapping("/vets")publicModelMapvetsHandler(){returnnewModelMap(this.clinic.getVets());}}@RequestMapping变体

Spring4.3引入了以下@RequestMapping注解的变体,方法级别的。

@GetMapping

@PostMapping

@PutMapping

@DeleteMapping

@PatchMapping

@Controller@RequestMapping("/appointments")publicclassAppointmentsController{privatefinalAppointmentBookappointmentBook;@AutowiredpublicAppointmentsController(AppointmentBookappointmentBook){this.appointmentBook=appointmentBook;}@GetMappingpublicMapget(){returnappointmentBook.getAppointmentsForToday();}@GetMapping("/{day}")publicMapgetForDay(@PathVariable@DateTimeFormat(iso=ISO.DATE)Dateday,Modelmodel){returnappointmentBook.getAppointmentsForDay(day);}@GetMapping("/new")publicAppointmentFormgetNewForm(){returnnewAppointmentForm();}@PostMappingpublicStringadd(@ValidAppointmentFormappointment,BindingResultresult){if(result.hasErrors()){return"appointments/new";}appointmentBook.addAppointment(appointment);return"redirect:/appointments";}}@Controller和AOP代理

一些情况下,一个controller可能需要在运行时被AOP代理装饰。一个例子是在controller上使用@Transactional。这时,对这些controllers,我们建议使用基于类的代理。这也是controller的默认选项。

然而,如果一个controller必须实现一个非SpringContext回调的接口(如InitializingBean、*Aware等等)的话,你可能需要显式的配置基于类的代理。例如,将改成

对SpringMVC3.1中@RequestMappingmethods的新的支持类(解析类?)

Spring3.1引入了针对RequestMappingmethods的一组新的支持类,叫做:RequestMappingHandlerMapping、RequestMappingHandlerAdapter。推荐使用它们,甚至需要利用SpringMVC3.1及以后的一些新特性。这些新的支持类默认就由MVC命名空间和MVCJavaconfig启用,其他情况必须显式的配置。本部分会描述一下新旧支持类之间的一些重要区别。

Spring3.1之前,type和method-levelrequestmappings是在两个独立的阶段中检查的--controller先被DefaultAnnotationHandlerMapping选中,具体的方法调用则由AnnotationMethodHandlerAdapter负责。

Spring3.1中新的支持类,只需要使用RequestMappingHandlerMapping。不妨将controller的那些方法看作一个集合,其内容是带有映射的各种端点。

这使得一些新的可能成为现实。ForonceaHandlerInterceptororaHandlerExceptionResolvercannowexpecttheObject-basedhandlertobeaHandlerMethod,whichallowsthemtoexaminetheexactmethod,itsparametersandassociatedannotations.TheprocessingforaURLnolongerneedstobesplitacrossdifferentcontrollers.

下面这几件事情已经不再有效:

上面的特性仍由现有的支持类支持。然而,如果想使用Spring3.1的新特性,你需要使用新的支持类!

URITemplatePatterns

URITemplate是一个类似URI的字符串,包含一个或多个变量名字。当你使用值将其中的变量全部替换之后,该模板会变成一个URI。

在SpringMVC中,你可以在方法的一个参数上使用@PathVariable注解,就可以将实参绑定到URI模板变量的值。

@GetMapping("/owners/{ownerId}")publicStringfindOwner(@PathVariableStringownerId,Modelmodel){Ownerowner=ownerService.findOwner(ownerId);model.addAttribute("owner",owner);return"displayOwner";}注意,如果方法的参数名与URI模板变量的名字不符,那需要显式的指定;否则可以省略。如下:

@GetMapping("/owners/{ownerId}/pets/{petId}")publicStringfindPet(@PathVariableStringownerId,@PathVariableStringpetId,Modelmodel){Ownerowner=ownerService.findOwner(ownerId);Petpet=owner.getPet(petId);model.addAttribute("pet",pet);return"displayPet";}当在Map实参上使用@PathVariable时,map会被所有的URI模板变量填满。

URI模板可以从type和method级别的@RequestMapping注解中组装。

带正则表达式的URITemplatePatterns

有时候你需要更精确的定义URI模板变量。考虑下URL"/spring-web/spring-web-3.0.5.jar",你怎么将其拆分成多个部分?

@RequestMapping支持在URI模板变量中使用正则表达式。语法是:{varName:regex}。如下:

@RequestMapping("/spring-web/{symbolicName:[a-z-]+}-{version:\\d\\.\\d\\.\\d}{extension:\\.[a-z]+}")publicvoidhandle(@PathVariableStringversion,@PathVariableStringextension){//...}PathPatterns

除了URI模板,@RequestMapping注解和其所有变体还支持ant-style的pathpatterns,如/mypath/*.do。

PathPatternComparison

当一个URL匹配多个patterns时,会使用一种排序来查找最佳匹配。

带有更少URI变量和通配符的pattern,被认为更匹配。例如,/hotels/{hotel}/*比/hotels/{hotel}/**更合适,因为其他一样,通配符更少。

如果变量数量一样,更长的被认为更匹配。例如,/foo/bar*比/foo/*更匹配。

当两个patterns拥有相同数量的变量和长度时,通配符少的更匹配。例如,/hotels/{hotel}比/hotels/*更匹配。

另外,还有两个特殊规则:

带有占位符的pathpatterns

@RequestMapping注解的patterns还支持${...}占位符。

后缀pattern匹配

默认,SpringMVC会执行“.*”的匹配,所以,当一个controller的被映射到/person的时候,实际上是隐式的被映射到/person.*。这样可以使用URL轻松的请求不同的资源表现,如/person.pdf,/person.xml。

后缀pattern匹配可以被关闭,或者被限制在一组为了内容协商目的而注册的路径扩展名中。非常建议使用最普通的请求映射来最小化请求的模糊性,因为有时候“.”不一定代表扩展名,例如/person/{id},有可能是/person/joe@xx.com。

后缀pattern匹配和RFD

Reflectedfiledownload(RFD)攻击,最早由Trustwave在2014年指出。这种攻击类似XSS,都依赖可以反射到响应的输入。然而,不是将js插入到HTML中,RFD攻击依赖于浏览器的下载,并依赖于浏览器将响应视为一个可执行脚本(双击能运行的那种)。

在SpringMVC中,@ResponseBody和@ResponseEntity方法同样具备风险,因为它们可以渲染不同内容类型--客户端可能通过URL路径扩展名来请求的类型。需要注意,无论是单独的禁用后缀pattern匹配还是单独的禁用用于内容协商目的的路径扩展名,都不能有效的组织RFD攻击。

为了有效的防护RFD,Spring在渲染响应体之前添加了一个header(Content-Disposition:inline;filename=f.txt)以建议一个固定和安全的下载文件名。这只有在URL路径包含的扩展名既不在白名单中,也不是因内容协商目的而显式注册的文件扩展名时才有效。然而,这样做也有其副作用,有时候可能会直接显示在浏览器中!

默认,很多常用的路径扩展名已经在白名单中。此外,RESTAPI的调用通常不是用作在浏览器中使用的URL。尽管如此,使用自定义HttpMessageConverter实现的应用,可以显式的注册用于内容协商目的的文件扩展名,针对这些扩展名Content-Dispositionheader(Content-Disposition:inline;filename=f.txt)不会被添加。

MatrixVariables

matrixvariables可能出现在任意pathsegment中,每个matrixvariable都由分号隔离。例如:"/cars;color=red;year=2012"。多个value的时候,可以使用逗号拼接,如"color=red,green,blue",也可以重复name,如"color=red;color=green;color=blue"。

如果希望一个URL包含matrixvariables,请求映射pattern必须使用URI模板来代表它们。

下面是提取matrixvariable”q”的例子:

//GET/pets/42;q=11;r=22@GetMapping("/pets/{petId}")publicvoidfindPet(@PathVariableStringpetId,@MatrixVariableintq){//petId==42//q==11}因为所有的pathsegments都可能含有matrixvariables,某些情况下你需要更精确的信息来确定需要的变量:

//GET/owners/42;q=11/pets/21;q=22@GetMapping("/owners/{ownerId}/pets/{petId}")publicvoidfindPet(@MatrixVariable(name="q",pathVar="ownerId")intq1,@MatrixVariable(name="q",pathVar="petId")intq2){//q1==11//q2==22}一个matrixvariable可以被定义为可选项,可以拥有一个指定的默认值;

//GET/owners/42;q=11;r=12/pets/21;q=22;s=23@GetMapping("/owners/{ownerId}/pets/{petId}")publicvoidfindPet(@MatrixVariableMultiValueMapmatrixVars,@MatrixVariable(pathVar="petId"")MultiValueMappetMatrixVars){//matrixVars:["q":[11,22],"r":12,"s":23]//petMatrixVars:["q":11,"s":23]}注意:为了启用matrixvariables,你必须设置RequestMappingHandlerMapping的removeSemicolonContentproperty为false。其默认是true。

TheMVCJavaconfigandtheMVCnamespacebothprovideoptionsforenablingtheuseofmatrixvariables.

IntheMVCnamespace,theelementhasanenable-matrix-variablesattributethatshouldbesettotrue.Bydefaultitissettofalse.

通过指定一个consumablemediatypes列表来窄化映射。只有requestheader中的Content-Type符合指定的媒体类型时,请求才匹配。例如:

@PostMapping(path="/pets",consumes="application/json")publicvoidaddPet(@RequestBodyPetpet,Modelmodel){//implementationomitted}注意,consumablemediatype表达式可以使用“!”来否定匹配的媒体类型,如使用“!text/plain”来匹配除了text/plain之外的Content-Type。建议使用MediaType中的常量,如APPLICATION_JSON_VALUE、APPLICATION_JSON_UTF8_VALUE。

注意,虽然consumes条件支持type和method级别,但是,不同于其他条件,method级别的会覆盖type级别的类型!!!

ProducibleMediaTypes

还可以通过指定一个produciblemediatypes列表来窄化请求。仅当requestheader的Accept匹配时,该request才会匹配。此外,使用produces条件会确保实际的内容类型。如下:

@GetMapping(path="/pets/{petId}",produces=MediaType.APPLICATION_JSON_UTF8_VALUE)@ResponseBodypublicPetgetPet(@PathVariableStringpetId,Modelmodel){//implementationomitted}注意produces条件指定的媒体类型,也可以选择性的指定一个字符集。例如,在上面的代码片段中,我们指定了与MappingJackson2HttpMessageConverter中默认配置的媒体类型一致的媒体类型。--是否可以认为,一种字符集就是一种媒体类型?

同consumes类似,produces也可以使用“!”。同样建议使用MediaType中的常量。

同consumes类似,方法级别的produces会覆盖类级别的媒体类型!!!

请求参数和请求头的值RequestParameter、RequestHeadervalues

可以通过请求参数条件来窄化请求的匹配,如:"myParam","!myParam",or"myParam=myValue"。前两个用于测试请求参数中是否出现该参数,第三个则需要请求参数有一个特定的值。例子:

@Controller@RequestMapping("/owners/{ownerId}")publicclassRelativePathUriTemplateController{@GetMapping(path="/pets",headers="myHeader=myValue")publicvoidfindPet(@PathVariableStringownerId,@PathVariableStringpetId,Modelmodel){//implementationomitted}}虽然你可以使用通配符来匹配Content-Type和Acceptheadervalues(如headers="content-type=text/*",可以匹配"text/plain"和"text/html"),但建议使用consumes和produces。这也是它们的设计目的。

HTTPHEAD和HTTPOPTIONS

@RequestMapping方法映射到“GET”,同时也会隐式的映射到“HEAD”!

@RequestMapping方法内建支持HTTPOPTIONS。略。

3.3、定义@RequestMappinghandlermethods

@RequestMappinghandlermethods可以有非常灵活的签名。除了BindingResult参数之外的参数可以按任意顺序排放。

Spring3.1为@RequestMappingmethods引入了一组新的支持类,分别是:RequestMappingHandlerMappingandRequestMappingHandlerAdapter。建议使用它们,而且,应该使用Spring3.1及以后的新特性。这些新的支持类默认由MVC命名空间启用,如果是Javaconfig,必须显式的配置--否则无法使用。

支持的方法参数类型

session的访问可能不是线程安全的,特别是在一个Servlet环境中。如果需要多个请求并发访问一个session时,可以考虑将RequestMappingHandlerAdapter的synchronizeOnSession设置为true。

Errors和BindingResult参数,必须跟在modelobject后面,因为可能有多个modelobject,Spring会为每个modelobject创建一个单独的BindingResult,所以,下面的例子不会执行:

@PostMappingpublicStringprocessSubmit(@ModelAttribute("pet")Petpet,BindingResultresult,Modelmodel){...}支持JDK1.8的java.util.Optional作为方法参数类型,与带有requiredattribute的注解一起使用(如@RequestParam、@RequestHeader等等)。这些情况下,java.util.Optional相当于required=false。

支持的方法返回类型

使用@RequestParameter将请求参数绑定到方法参数

@Controller@RequestMapping("/pets")@SessionAttributes("pet")publicclassEditPetForm{//...@GetMappingpublicStringsetupForm(@RequestParam("petId")intpetId,ModelMapmodel){Petpet=this.clinic.loadPet(petId);model.addAttribute("pet",pet);return"petForm";}//...}默认,@RequestParam的requiredattribute是true,可以设置为false。@RequestParam(name="id",required=false)

如果目标方法参数的类型不是String,会自动使用类型转换。

当在Map或MultiValueMap实参上使用@RequestParam注解时,会被填入所有的requestparameters。

使用RequestBody注解来映射requestbody

方法参数的@RequestBody注解,标识了方法参数应该绑成HTTPrequestbody的值。例如:

@PutMapping("/something")publicvoidhandle(@RequestBodyStringbody,Writerwriter)throwsIOException{writer.write(body);}可以通过使用一个HttpMessageConverter将requestbody转成methodargument。HttpMessageConverter负责将HTTPrequestmsg转成一个对象以及将对象转成HTTPresponsebody。RequestMappingHandlerAdapter支持@RequestBody的默认HttpMessageConverters:

注意,如果使用MVC命名空间或者使用MVCJavaconfig,默认会注册更多的messageconverters。

@RequestBody注解的方法参数还可以使用@Valid注解,Spring会使用配置好的Validator实例来校验该参数。当使用MVC命名空间或MVCJavaconfig时,一个JSR-303validator会被自定的配置--假如classpath中有一个JSR-303实现。

使用@ResponseBody注解来映射responsebody

@ResponseBody注解类似于@RequestBody。该注解放在方法上指示返回类型会被写入HTTPresponsebody(没有被放入Model,或被解释成viewname)。例如:

@GetMapping("/something")@ResponseBodypublicStringhelloWorld(){return"HelloWorld";}上面的例子,会将字符串写入HTTPresponsestream。

如同@RequestBody,Spring会将返回的对象转换成一个responsebody--使用一个HttpMessageConverter。

使用@RestController注解创建一个RESTController

使用@RestController代替@ResponseBody与@Controller。它虽然是由后两者组合而成,但在将来会被赋予更多语义。

使用HttpEntity

HttpEntity类似于@RequestBody和@ResponseBody。除了能获取request和responsebody之外,HttpEntity(以及其response子类:ResponseEntity)还允许获取request和responseheaders,如下:

TheaboveexamplegetsthevalueoftheMyRequestHeaderrequestheader,andreadsthebodyasabytearray.ItaddstheMyResponseHeadertotheresponse,writesHelloWorldtotheresponsestream,andsetstheresponsestatuscodeto201(Created).

在方法上使用@ModelAttribute

该注解可以用在方法或方法参数上。本部分讲解用在方法上的作用,下一部分会讲解用在方法参数上的作用。

在方法上使用该注解,意味着该方法的一个目的是增加一个或多个modelattribute。该方法支持的参数类型与@RequestMappingmethods一样,但不能直接映射到请求。相反,同一个Controller中的@ModelAttributemethods会在@RequestMappingmethods之前被调用!!!例子:

//添加一个attribute//该方法的返回值会被添加到modelaccount中//你可以定义该model的名字,例如@ModelAttribute("myAccount")@ModelAttributepublicAccountaddAccount(@RequestParamStringnumber){returnaccountManager.findAccount(number);}//添加多个attributes@ModelAttributepublicvoidpopulateModel(@RequestParamStringnumber,Modelmodel){model.addAttribute(accountManager.findAccount(number));//addmore...}@ModelAttributemethods被用于将常用的attributes填入model。

注意两种形式的@ModelAttributemethods。第一个,是隐式的将返回值添加为attribute。第二个,接收一个Model,然后在其中增加任意数量的modelattributes。

一个Controller可以拥有任意数量的@ModelAttributemethods。所有这些方法都会在同一个Controller中的@RequestMappingmethods之前被调用!

@ModelAttributemethods也可以被定义在@ControllerAdviceclass内,这样的methods会被用于所有Controllers。--就是在所有Controller的所有@RequestMappingmethods之前被调用!

如果没有显式指定一个modelattributename,会发生什么?这种情况下,会基于其类型赋予一个默认的名字。例如,如果方法返回了Account类型,那默认的name就是account。

在方法参数上使用@ModelAttribute

@PutMapping("/accounts/{account}")publicStringsave(@ModelAttribute("account")Accountaccount){//...}上面的例子,modelattribute的name与URI模板变量的名字一致。如果你注册了一个Converter,那么上面的例子就可以不必使用一个@ModelAttributemethod。

数据绑定的一个结果是,可能存在errors,例如缺失必须的字段或者类型转换错误。为了检查该类错误,需要在@ModelAttributeargument之后紧跟着添加一个BindingResultargument。

@PostMapping("/owners/{ownerId}/pets/{petId}/edit")publicStringprocessSubmit(@ModelAttribute("pet")Petpet,BindingResultresult){if(result.hasErrors()){return"petForm";}//...}使用BindingResult,你可以检查是否有errors,可以使用Spring的formtag来在同一个form中显示错误。

注意,某些情况下,不使用数据绑定而获取model中的一个attribute很有用。这些情况下,你可以在Controller中注入Model,或者在注解上使用bindingflag,如下:

@ModelAttributepublicAccountFormsetUpForm(){returnnewAccountForm();}@ModelAttributepublicAccountfindAccount(@PathVariableStringaccountId){returnaccountRepository.findOne(accountId);}@PostMapping("update")publicStringupdate(@ValidAccountUpdateFormform,BindingResultresult,@ModelAttribute(binding=false)Accountaccount){//...}InadditiontodatabindingyoucanalsoinvokevalidationusingyourowncustomvalidatorpassingthesameBindingResultthatwasusedtorecorddatabindingerrors.Thatallowsfordatabindingandvalidationerrorstobeaccumulatedinoneplaceandsubsequentlyreportedbacktotheuser:

@PostMapping("/owners/{ownerId}/pets/{petId}/edit")publicStringprocessSubmit(@ModelAttribute("pet")Petpet,BindingResultresult){newPetValidator().validate(pet,result);if(result.hasErrors()){return"petForm";}//...}--就是根据BindingResult的结果进行自己的操作。

或者,可以使用JSR-303@Valid注解来自动调用校验:

@PostMapping("/owners/{ownerId}/pets/{petId}/edit")publicStringprocessSubmit(@Valid@ModelAttribute("pet")Petpet,BindingResultresult){if(result.hasErrors()){return"petForm";}//...}使用@SessionAttributes在requests之间的HTTPsession中存储modelattributes

使用@RequestAttribute来获取requestattributes

类似于@SessionAttribute,@RequestAttribute也可以用于获取pre-existingrequestattributes--由filter或interceptor创建的。

由于HttpPutFormContentFilter会consume请求体,所以,不应为那些依赖针对application/x-www-form-urlencoded的转换器的PUT或PATCHURLs配置该filter。这包括@RequestBodyMultiValueMap和HttpEntity>。

使用@CookieValue注解来映射cookievalues

该注解允许一个方法参数绑定一个HTTPcookie的值。

JSESSIONID=415A4AC178C59DACE0B2C9CA727CDD84下面的代码演示了如何获取JSESSIONIDcookie:

@RequestMapping("/displayHeaderInfo.do")publicvoiddisplayHeaderInfo(@CookieValue("JSESSIONID")Stringcookie){//...}如果目标方法参数的类型不是String,会自动应用类型转换。

该注解,也被在Servlet和Portlet环境下的annotatedhandlermethods支持。

使用@RequestHeader注解来映射requestheaderattributes

这是一个样例requestheader:

Hostlocalhost:8080Accepttext/html,application/xhtml+xml,application/xml;q=0.9Accept-Languagefr,en-gb;q=0.7,en;q=0.3Accept-Encodinggzip,deflateAccept-CharsetISO-8859-1,utf-8;q=0.7,*;q=0.7Keep-Alive300下面的代码演示了如何获取Accept-Encoding和Keep-Aliveheaders的值:

@RequestMapping("/displayHeaderInfo.do")publicvoiddisplayHeaderInfo(@RequestHeader("Accept-Encoding")Stringencoding,@RequestHeader("Keep-Alive")longkeepAlive){//...}如果目标方法参数的类型不是String,会自动应用类型转换。

当@RequestHeader注解用于一个Map、MultiValueMap,或HttpHeadersargument时,该map会被填入所有的headervalues。

内建的支持允许转换一个逗号间隔的字符串,将其转成一个字符串或其他类型的数组/集合。例如,@RequestHeader(“Accept”)注解的方法参数,可能是String类型,也可能是String[]或List类型。

methodparameters和typeconversion

从request中提取出来的基于字符串的值,包括requestparameters、pathvariables、requestheaders、还有cookievalues,可能需要被转成它们要绑定的methodparameter或field的类型。如果目标类型不是String,Spring会自动转成合适的类型。支持所有简单类型,如int、long、Date等等。甚至,你可以使用一个WebDataBinder来定制转换过程,或者通过在FormattingConversionService中注册Formatters。

定制WebDataBinder初始化

使用@InitBinder定制数据绑定

在controller方法上使用@InitBinder,允许你在controller内部配置web数据绑定。@InitBinder代表方法初始化了WebDataBinder--会被用于填充被注解的handler方法的command和formobjectarguments。

下面的案例演示了使用@InitBinder来配置针对所有java.util.Dateformproperties的一个CustomDateEditor。

@ControllerpublicclassMyFormController{@InitBinderprotectedvoidinitBinder(WebDataBinderbinder){SimpleDateFormatdateFormat=newSimpleDateFormat("yyyy-MM-dd");dateFormat.setLenient(false);binder.registerCustomEditor(Date.class,newCustomDateEditor(dateFormat,false));}//...}或者,自Spring4.2起,可以考虑使用addCustomFormatter来指定Formatter实现,取代PropertyEditor实例。

如果你在一个sharedFormattingConversionService中有基于Formatter的设置,这会非常有用,只需要同样的做法来复用特定controller针对bindingrules的调节。

@ControllerpublicclassMyFormController{@InitBinderprotectedvoidinitBinder(WebDataBinderbinder){binder.addCustomFormatter(newDateFormatter("yyyy-MM-dd"));}//...}配置一个定制的WebBindingInitializer

为了将数据绑定初始化外部化,你可以提供一个定制的WebBindingInitializer实现,然后通过提供一个定制的AnnotationMethodHandlerAdapter的beanconfiguration来启用它。

下面的例子示意了使用了org.springframework.samples.petclinic.web.ClinicBindingInitializer的配置,该配置配置了几个PetCliniccontrollers需要的PropertyEditors。

advisingcontrollerswith@ControllerAdviceand@RestControllerAdvice

@ControllerAdvice注解,是一个componentannotation,允许实现类能够在classpath扫描中被自动探测到。当使用MVCnamespace或MVCJavaconfig时,自动启用。

@RestControllerAdvice,等同于@ExceptionHandler+@ResponseBodymethods。

@ControllerAdvice和@RestControllerAdvice都可以指定作用的controllers:

//TargetallControllersannotatedwith@RestController@ControllerAdvice(annotations=RestController.class)publicclassAnnotationAdvice{}//TargetallControllerswithinspecificpackages@ControllerAdvice("org.example.controllers")publicclassBasePackageAdvice{}//TargetallControllersassignabletospecificclasses@ControllerAdvice(assignableTypes={ControllerInterface.class,AbstractController.class})publicclassAssignableTypesAdvice{}详见@ControllerAdvice文档。

JacksonSerializationViewSupport

在一个@Responsecontrollermethod上,或者在那些返回ResponseEntity的controllermethods上,简单的添加@JsonView注解,并指定需要使用的viewclass或Interface即可。如下:

@RestControllerpublicclassUserController{@GetMapping("/user")@JsonView(User.WithoutPasswordView.class)publicUsergetUser(){returnnewUser("eric","7!jd#h23");}}publicclassUser{publicinterfaceWithoutPasswordView{};publicinterfaceWithPasswordViewextendsWithoutPasswordView{};privateStringusername;privateStringpassword;publicUser(){}publicUser(Stringusername,Stringpassword){this.username=username;this.password=password;}@JsonView(WithoutPasswordView.class)publicStringgetUsername(){returnthis.username;}@JsonView(WithPasswordView.class)publicStringgetPassword(){returnthis.password;}}注意,尽管@JsonView允许指定多个class,但在controllermethod上使用时只能指定一个class!可以考虑使用复合接口,如果你需要启用多个views。

对于那些依赖viewresolution的controllers,简单的将序列化viewclass添加到model即可:

@ControllerpublicclassUserControllerextendsAbstractController{@GetMapping("/user")publicStringgetUser(Modelmodel){model.addAttribute("user",newUser("eric","7!jd#h23"));model.addAttribute(JsonView.class.getName(),User.WithoutPasswordView.class);return"userView";}}

JacksonJSONP支持

@ControllerAdvicepublicclassJsonpAdviceextendsAbstractJsonpResponseBodyAdvice{publicJsonpAdvice(){super("callback");}}对于依赖viewresolution的controllers,JSONP自动被启用,默认的queryparametername是jsonp或callback。可以通过其jsonpParameterNamesproperty来定制。

3.4、异步请求的处理

Spring3.2引入了基于Servlet3的异步请求处理。不是一直以来的让controllermethod返回一个值,而是,让controllermethod返回一个java.util.concurrent.Callable,然后从SpringMVC管理的线程中produce返回值。同时,mainServletcontainerthread会被退出和释放,以处理其他请求。SpringMVC在一个独立的线程调用Callable--通过TaskExecutor,当Callable返回时,请求会被分派回Servletcontainer,从而恢复处理。例子:

另一个选择是,controllermethod返回DeferredResult。这种情况下,也可能是任意线程produce的返回值,就是说,非SpringMVC管理的线程!例如,结果可能是响应某个外部事件,如一个JMSmessage、一个scheduledtask等等,而produce的结果。下面是一个例子:

Withtheaboveinmind,thefollowingisthesequenceofeventsforasyncrequestprocessingwithaCallable:

ThesequenceforDeferredResultisverysimilarexceptit’suptotheapplicationtoproducetheasynchronousresultfromanythread:

asyncrequests的Exception处理

如果,一个由controllermethod返回的Callable在执行时抛出了一个Exception,会发生什么?简短的答案是与一个controllermethod抛出一个异常时相同。会经历常规的异常处理机制。长的解释是,当Callable抛出一个Exception时,SpringMVC会将该Exception分派到Servletcontainer,将其作为结果以及恢复requestprocessing的引导,此时requestprocessing会处理Exception,而非controllermethodreturnvalue。当使用DeferredResult时,你还可以选择是否调用setResult或者setErrorResult--传入Exception实例。

拦截asyncrequests

一个HandlerInterceptor也可以实现AsyncHandlerInterceptor,以实现afterConcurrentHandlingStartedcallback,当asynchronousprocessing开始时,会调用afterConcurrentHandlingStarted,而非postHandle和afterComplete。

一个HandlerInterceptor也可以注册一个CallableProcessingInterceptor或一个DeferredResultProcessingInterceptor,以更深度地集成asynchronousrequest的lifecycle,例如,handle一个timeoutevent。详见AsyncHandlerInterceptorjavadoc。

DeferredResult类型,也提供了诸如onTimeout(Runnable)、onCompletion(Runnable)之类的方法。详见javadoc。

当使用一个Callable时,你可以将其wrap进一个WebAsyncTask的实例,该实例也可以提供timeout和completion的方法注册。

HTTPStreaming

如果你想要在一个HTTPresponse上push多个事件会怎样?这就是与”LongPolling”有关的技术,也就是HTTPStreaming。SpringMVC通过ResponseBodyEmitter返回值类型使其成为可能,该返回值类型可悲用于发送多个对象(而非使用@ResponseBody只发送一个--这种更常见),每个被发送的对象都通过一个HttpMessageConverter被写入到response。

例子:

@RequestMapping("/events")publicResponseBodyEmitterhandle(){ResponseBodyEmitteremitter=newResponseBodyEmitter();//Savetheemittersomewhere..returnemitter;}//Insomeotherthreademitter.send("Helloonce");//andagainlateronemitter.send("Helloagain");//anddoneatsomepointemitter.complete();注意,ResponseBodyEmitter也可被用做ResponseEntity的body,以便定制response的status和headers。

HTTPStreamingWithServer-SentEvents

HTTPStreamingDirectlyToTheOutputStream

@RequestMapping("/download")publicStreamingResponseBodyhandle(){returnnewStreamingResponseBody(){@OverridepublicvoidwriteTo(OutputStreamoutputStream)throwsIOException{//write...}};}

ConfiguringAsynchronousRequestProcessing

3.5、测试controllers

4、Handlermappings

在之前的Spring版本中,用户必须要在web应用上下文中定义一个或者多个HandlerMappingbeans以将incomingwebrequests映射到合适的handlers。随着annotatedcontrollers的引入,现在一般可以不必那样做了,因为RequestMappingHandlerMapping会自动在所有@Controllerbeans中查找@RequestMapping注解。然而,务必记住,所有的继承自AbstractHandlerMapping的HandlerMapping类,都有以下properties--你可以用来定制它们的行为:

interceptors,使用的拦截器列表。

defaultHandler,默认使用的handler--当handlermapping没有一个匹配的handler时。

order,基于该property的值(Ordered接口),Spring将所有可用的handlermappings进行排序,并应用第一匹配的handler。

alwaysUseFullPath,如果设为true,Spring会在当前Servletcontext中使用全路径来查找合适的handler。如果false(默认就是),会使用当前Servletmapping内的路径。例如,如果一个Servlet被映射到/testing/*,当设为true时,使用/testing/viewPage.html,否则,/viewPage.html。

urlDecode,默认true,自Spring2.5起。如果你倾向于对比encodedpaths,需要设为false。然而,HttpServletRequest总是以decoded形式暴露Servletpath。注意,当与encodedpath对比时,Servletpath不会匹配。

配置拦截器的例子:

4.1使用HandlerInterceptor拦截requests

spring的handlermapping机制包括handlerinterceptors,当你想要针对特定的requests应用特定的功能时,非常有用。

位于handlermapping内的interceptors,必须实现org.springframework.web.servlet.HandlerInterceptor(或者其实现/子类)。

该接口定义有三个方法preHandle(..)postHandle(..)afterHandle(..)。见这里。(为知笔记的连接,不知道行不行,以后再说)

preHandle(..)方法会返回一个boolean值,如果false,会破坏执行链的处理过程(不再往下执行)。如果false,DispatcherServlet会认定该拦截器自身来处理请求(例如,渲染视图等),所以不会继续执行其他的拦截器和实际的handler。

拦截器可以在所有继承自AbstractHandlerMapping的类中设置,使用其interceptors属性!如下:

注意:当使用RequestMappingHandlerMapping时,实际的handler是HandlerMethod的一个实例,该HandlerMethod会识别要被调用的特定的controllermethod。

我的补充:handlermapping这个过程,是将request与handler之间映射起来的过程。Spring提供的实现类,能用的也就这几个:

---还有一个RequestMappingHandlerAdapter,不要混淆了。

如你所见,Spring的适配器类HandlerInterceptorAdapter,让继承HandlerInterceptor更加简单。

THE END
1.RFD15P06中文资料数据手册规格书INTERSILRFD15P06 TO-251AA G RFD15P06SM RFP15P06 TO-252AA TO-220AB F15P06 RFP15P06 S NOTE: When ordering, use the entire part number. Add the suffix 9A to obtain the TO-252AA variant in the tape and reel, i.e., RFD15P06SM9A. Packaging JEDEC TO-220AB JEDEC TO-251https://www.icpdf.com/INTERSIL_datasheet/RFD15P06_pdf_462927/
2.德国巴斯夫PA66全型号性能介绍(德国巴斯夫集团授权总经销)视频聚酰胺塑胶原料供应商,尼龙66原料供应商,德国巴斯夫PA66代理商,巴斯夫PA66总代理,德国巴斯夫PA66经销商 所在地 上海市奉贤区南桥镇八字桥路1919号2幢12层 联系电话 021-80468006 手机 13120932899 中国总代理商 宋磊 请说明来自顺企网,优惠更多 请卖家联系我 产品详细介绍 德国巴斯夫PA66全型号性能介绍(德国巴斯夫集团https://xiangsu.11467.com/info/25944879.htm
3.IFM易福门安全技术,上海IFM传感器E20003 REFLECTOR TS-22 E20004 REFLECTOR TS-40 E20005 REFLECTOR TS-80 E20051 FT-00-P-A-M6 E20052 FT-00-P-A-E3 E20053 FT-00-P-V-E1 E20054 FT-00-P-A-R4 E20055 FT-00-A-A-M6 E20056 FT-00-A-A-E3 E20057 FT-00-A-V-E1 https://xpamwhjxs.cn.goepe.com/apollo/prodetail-7137396.html
4.穿搭公式#男女同款宝藏夹克分享 #晒晒酷飒宝藏绒感外套 #日常穿搭o?o?t?d #女大学生OOTD THE NORTH FACE PURPLE LABEL FW22 纯色翻领灯芯绒夹克 男款 黑色 想要 发布于1天前 陕西省 相关推荐 App内查看更多 一双mid黑曜石,比北卡蓝黑曜石还要贵,服了服了,怕了怕了 Thhhhhh68 44 暗色调系 28 无敌https://m.dewu.com/note/trend/details?id=257381111
5.WTSCAP(闻亭实业)公司介绍上海闻亭实业有限公司( Shanghai WTSCAP Co,Ltd)是国内超级电容器和锂电池的专业生产企业,主要从事超级电容器和锂电池的开发、生产与销售。 公司引进了全自动卷绕机、全自动套管机、激光点焊机等专业自动化生产设备及全自动电容分选机、超级电容测试仪等专业的测试设备。超级电容器和锂电池产品已形成百余种规格型号的https://www.hqchip.com/gongsi/55146.html
6.kfd2sr2ex1w安全栅kfd2sr2kfd2-sr2-ex1w安全栅价格信息不够给力?没有找到优质kfd2-sr2-ex1w安全栅批发/采购信息?马上发布询价单 阿里巴巴为您找到200条kfd2-sr2-ex1w安全栅产品的详细参数,实时报价,价格行情,优质批发/供应等信息。 移动版:kfd2-sr2-ex1w安全栅 发布询价单 让千万商家找到您https://www.1688.com/chanpin/-6B6664322D7372322D65783177B0B2C8ABD5A4.html
7.蓝天上干燥的落叶松照片正版商用图片22rfd0摄图新视界提供蓝天上干燥的落叶松图片下载,另有建筑学,秋天,美丽的,美女,蓝色,商业,城市,城市景观,颜色,建设,公司,区,市中心,落下,森林图片搜索供您浏览下载,每张图片均有版权可放心商用,您正在浏览的图片为22rfd0https://xsj.699pic.com/tupian/22rfd0.html
8.xxxrfd的微博8 2 ?35 2022-11-15 22:54 来自微博视频号 ?收藏 转发 评论 ?赞 c +关注 xxxrfd 2022-11-15 16:36 来自iPhone 13 Pro 转发微博 @模型网 #站长的n比例铁道模型坑# 今日的三分钟小火车时间TOMIX 的JR 185-0系特急电车 (舞女号) L模型网的微博视频 小窗口 https://weibo.com/5487514791
9.saltdihydrateUNII5RFD27DQ22L英文别名Tyrosine disodium dihydrate | 122666-87-9 | L-Tyrosine disodium salt dihydrate | UNII-5RFD27DQ22 | L-Tyrosine, disodium salt, dihydrate | 5RFD27DQ22 | L-Tyrosine, sodium salt, hydrate (1:2:2) | disodium;(2S)-2-amino-3-(4-oxidophenyl)propanoate;dihydrate | MFCD03840558 | https://www.aladdin-e.com/zh_cn/l302659.html
10.志高RFD35F1WXC参数志高RFD35F1WXC参数配置详细参数型号(别称) RFD35F1W-XC 空调类型 中央空调 适用面积 15-22㎡ 技术参数 产品功率 大1.5P 冷暖类型 冷暖型 是否变频 变频 制冷量 3500W 制冷功率 1340W 制热量 5000W 制热功率 3850W 循环风量 650m3/h 室内机噪音 24-34dB 室外机噪音 50dB 能效等级 3级 电源性能 220V/50Hz 其http://product.pconline.com.cn/air_condition/chigo/1341865_detail.html
11.RFDelectronicGmbHSRZ32.0Nr.8536.4900「阀门」hydac HDA3844-A-400-000 压力变送器RFD electronic GmbH SRZ 3-2.0 Nr.8536.4900 自动控制器Hawe P22-1 阀门我们是一家德国公司,主要业务是做欧洲和美国原装进口仪器仪表,机电工控类产品, 如果还有什么需求,都可以联系我问问看。只要有品牌和型号就可以.有问题咱们电话保持联系 北京康拉德科技有限公司 品牌负责人:https://m.makepolo.com/product/100567596383.html
12.日本B&PLUS传感器全系列RFD0801PU05,RXD1202PURFD12/RPT18-PU1.0,RFD30/RPT18-PU0.5;RGPE-3005-MKJ01 RGPE-3005-MKJ01-PU02,RGPE-3005P-TYT16,RGPE-3005P-TYT22, RGPE-9012-V2430N-PU-02,RGPE-9012-V2430N-PU-03,RGPE-9012-V2430N-PU-04, RGPE-9012-V2430N-PU-05,RGPE-9012-V2430N-PU-10,RGPE-9012-V2430P-PU-02, RGPE-9012https://yahanjidian.cn.china.cn/supply/5020189484.html
13.商用落地柜机空调立柜中央空调5匹冷暖变频380伏RFD苏宁易购为您提供美的(Midea)美的空调挂机KFR-35GW/BP2DN8Y-AG400(B3) 中央空调和美的Midea 商用落地柜机空调立柜中央空调5匹冷暖变频380伏RFD-120LW/BSDN8Y-PA401(B3)A参数对比,让您了解美的(Midea)美的空调挂机KFR-35GW/BP2DN8Y-AG400(B3) 中央空调和美的Midea https://m.suning.com/prdCom/0000000000-11026704541_0070128691-12343110977_0-0_0-0.html
14.RFD币最新价格RFD币今日行情RFD币最新消息2023-05-22 分时 7日 14日 30日 半年 一年 上架交易所&行情数据 #排名交易所名称交易对平台价格¥24H成交额¥24H成交量占比 1 BTCEX RFD/USDT0.000051143.34万272.94亿14.5% 2 币市 RFD/USDT0.000041107.44万261.21亿10.87% 3 D网 RFD/USDT0.00004479.82万180.29亿8.08% https://www.120btc.com/coin/28549.html
15.GitHubpublishRFD 18 Support for using labels to select networks and packages predraftRFD 19 Interface Drift In Workflow Modules draftRFD 20 Manta Slop-Aware Zone Scheduling draftRFD 21 Metadata Scrubber For Triton draftRFD 22 Improved user experience after a request has failed https://github.com/TritonDataCenter/rfd
16.「译」力的生成率(RFD)RFD的改善可能是肌肉肌腱刚性增加的结果(22,23),由于肌纤维类型或面积的改变(从I型到IIA型)而增强的肌力产生(24,25),以及在SSC早期(< 100ms)神经驱动增加的结果(26,27)。相反,RFD似乎受到肌纤维类型变化(从IIX型到IIA型),以及肌束长度增加(导致肌肉刚性降低)(29)的负面影响(28)。为什么力https://baijiahao.baidu.com/s?id=1689791686690536601&wfr=spider&for=pc
17.RFDweb(RedflagDeals)相似应用下载2016/08/19 20:22 分类 新闻阅读 搞笑 要求 Android 3.0.0 以上 相关专题 最新专题 web邮件下载 web服务器下载下载 web浏览器下载 web应用app下载 安卓web服务器app下载 web教程app下载 web浏览器和ie浏览器app下载 下载豌豆荚客户端 (领礼包看攻略) 下载 相关推荐: RFD web (RedflagDeals)最新https://m.wandoujia.com/apps/7096966
18.RFD币价值如何?RFD币值得长期投资吗?RFD币是一个相对较新的加密货币,它采用去中心化的区块链技术,旨在为用户提供去中心化的金融服务。然而,像所有其他加密货币一样,RFD币的价值是由市场需求和供应决定的。本文将探讨RFD币的价值以及是否值得进行长期投 。 币界网报道: RFD币价值如何? RFD币是一个相对较新的加密货币,它采用去中心化的区块链技术,旨https://www.528btc.com/bk/1692584540120535.html
19.dprrfduppowerautoa22-Ounces (Pack of 6) 22盎司 (盒6)[translate] aI think too 我也是认为[translate] aPlease do not suspect that I to your lov 不要怀疑I对您的lov[translate] atry every means to keep fit if you want to live a happy life in this beautiful world 如果您在这个美丽的世界,想要居住愉快的生http://eyu.zaixian-fanyi.com/fan_yi_12678408
20.RFDesignRFD900xModemGetYoursToday!Get the RFDesign RFD 900x Modem shipped fast from the best source for all your FPV gear, RMRC! Free shipping for qualified orders using the shipping deal.https://www.readymaderc.com/products/details/rfdesign-rfd-900x-modem
21.RFD900数传电台·PX4UserGuideRFD900长距离数传 jDrones和RFDesign推出了一款兼容 SiK 的长距离数传电台。 这个电台配合普通天线可以提供最少5公里的稳定链接。 jDrones生产了RFDesign的调制解调器(添加电源管理、滤波器和其他电子器件,连接普遍的飞控,并且单独验证的天线)。 第一个这种设计的调制解调器是RFD900,RFD900和jDrones之后的都升级到新http://docs.px4.io/v1.11/zh/telemetry/rfd900_telemetry.html
22.ZebraRFD40UHFRFID背夹更快速更智能面向未来RFD40 UHF RFID背夹 优异的连接,为您的员工赋能 RFD40 UHF RFID背夹能够快速连接受支持的具备 Zebra eConnex?技术的设备,包括TC21/26、EC50/55以及未来的型号,助力您的员工轻松实现RFID读写识别。 *TC系列及其他适配型号包括:TC21/26/21-HC/26-HC,TC22/27,TC51/52/52x/52ax/56/57/57x,TC53/58;以http://www.ivysun.net/arc-new/9440.html
23.RFDAAA@视觉小说FAQ的内容indienova独立游戏22信息162成员 加入小组 全部成员开发游戏(3) 编程零基础视觉小说创作话题讨论 以论坛讨论形式查看 RFDAAA@视觉小说 FAQ 的内容(查看所有内容) 废都物语网络仙侠版寻求美术接包 RFDAAA2020-06-05 H5手机页游开发团队,擅长做网络游戏,已有初步demo,寻求对废都物语有所了解的美术人员接包。 https://indienova.com/groups/76/u/rfdaaa
24.rfdrfd 切换时间排序 精选 热门会员 换一换 ATL实验室 127人关注 · 48篇文章 流苏_ 161人关注 · 542篇文章 dewei吴彦祖 43人关注 · 18篇文章 CDra90n 51人关注 · 43篇文章 锐捷天幕安全实验室 42人关注 · 22篇文章 精选专辑 换一换 渗透测试与安全 640人收藏 · 16篇文章 GhostWolf团队原创https://www.freebuf.com/tag/rfd
25.ZebraRFD40UHFRFID背夹的特性RFD40 UHF RFID背夹能够快速连接受支持的具备 Zebra eConnex技术的设备,包括TC21/26、EC50/55以及未来的型号,助力您的员工轻松实现RFID读写识别。 适配型号* *TC系列及其他适配型号包括:TC21/26/21-HC/26-HC,TC22/27,TC51/52/52x/52ax/56/57/57x,TC53/58;以及HC20/50。 https://www.elecfans.com/d/5788098.html
26.美的RFD72QW/BDN8Y美的(Midea)中央空调 3匹天花机 嵌入式吸顶机 冷暖一级能效 RFD-72QW/BDN8Y-D(B1)A 一价无忧(包5米铜管) 京东价 ¥降价通知 累计评价 0 促销 展开促销 配送至 --请选择-- 支持 选择匹数 2匹 三级能效 23-34㎡ 2匹 三级能效 变频 23-34㎡ https://item.jd.com/100089324772.html
27.RFD(反射型文件下载)漏洞原理及实战案例全汇总RFD,即Reflected File Download反射型文件下载漏洞,是一个2014年来自BlackHat的漏洞。这个漏洞在原理上类似XSS,在危害上类似DDE:攻击者可以通过一个URL地址使用户下载一个恶意文件,从而危害用户的终端PC。 这个漏洞很罕见,大多数公司会认为它是一个需要结合社工的低危漏洞,但微软,雅虎,eBay,PayPal和其他许多公司认为这https://cloud.tencent.com/developer/article/1516361
28.SpringBoot多版本更新,紧急修复RFD安全漏洞此版本包括 22 个错误修复,文档改进和依赖项升级。 https://github.com/spring-projects/spring-boot/releases/tag/v2.1.17.RELEASE 往期推荐 Java 15 转正了,国内几大互联网公司均有贡献,其中腾讯最为突出! 赠书:一本书带你吃透Nginx应用与运维 超全的 Linux Shell 文本处理工具集锦,快收藏 https://blog.51cto.com/u_14299052/2935627
29.RFD900x远距离无线电调制解调器图纸下载电子电工图纸RFD900x远距离无线电调制解调器,参数为:范围:902 - 928兆赫(美国)/ 915 - 928兆赫(澳大利亚)输出功率:1w(+30 dBm),在1dB步长控制(±1dB @ = 20dbm典型)空气数据传输率:4, 8, 16,19, 24, 32,48, 64, 96,128, 192和250 kbithttps://www.mfcad.com/tuzhi/solidworks/1298/343553.html