您现在的位置是: 首页  >  架构/框架  >  Spring MVC
  • SpringMVC文件下载和上传

    SpringMVC文件下载和上传

    1、文件下载文件下载的最重要的一点是设置响应头的Content-disposition为attachmen;filename=要下载的文件的名字,然后得到文件的输入流写入本地即可1.常规方法2.使用SpringMVC提供的ResponseEntity<T>类型,使用它可以很方便地定义返回的HttpHeaders和HttpStatus。下载页面测试结果2、文件上传文件上传这里使用的是commons-fileupload-1.4,他需要依赖commons-io,他们的Maven依赖如下:(1)单文件上传上传表单页面文件上传最重要的一点就是将表单的提交方法设置为post,并且将enctype的值设置为"multipart/form-data"。控制器在Controller的处理方法中,使用MultipartFile对象作为参数接收前端上传过来的文件在springmvc配置文件中注册文件上传组件使用MultipartFile对象接收前端上传过来的文件,还需要在springmvc的配置文件中进行如下配置:(2)多文件上传其实多文件上传也很简单,单文件上传是在Controller的处理方法中使用MultipartFile对象作为参数接收前端上传过来的文件,而多文件上传则使用MultipartFile对象数组来接收。页面该页面中有几个name值一样的file类型的input标签,其他跟单文件上传的页面没区别。控制器同样的,使用MultipartFile数组接收前端上传过来的多个文件,也需要在springmvc的配置文件进行配置,具体配置与上述单文件上传的springmvc.xml配置没差别。这样,就可以进行多文件上传了。多种文件上传情景综合当然,项目开发中,场景可能并不是这么简单,上述的多文件上传是一个个文件选择后一起上传(即多个name相同的input标签),那要是我项目中只要一个input标签就可以一次性多个文件呢?又或者一个页面中既要一个个选择的多文件上传,又要一次性选择的多文件上传,还要有单文件上传呢?没问题,MultipartFile[]通吃,代码也很easy,下面直接上代码。页面控制器测试结果MultipartFile[]就是如此强大,不管单个多个,逻辑处理一样,所以建议在项目开发中使用MultipartFile[]作为文件的接收参数。3、重要方法和参数1、MutipartFile类的一些常用方法:StringgetContentType()//获取文件MIME类型InputStreamgetInputStream()//获取文件流StringgetName()//获取表单中文件组件的名字StringgetOriginalFilename()//获取上传文件的原名longgetSize()//获取文件的字节大小,单位bytebooleanisEmpty()//是否为空voidtransferTo(Filedest)//保存文件到服务器指定路径2、CommonsMultipartResolver的属性解析defaultEncoding:表示用来解析request请求的默认编码格式,当没有指定的时候根据Servlet规范会使用默认值ISO-8859-1。当request自己指明了它的编码格式的时候就会忽略这里指定的defaultEncoding。uploadTempDir:设置上传文件时的临时目录,默认是Servlet容器的临时目录。maxUploadSize:设置允许上传的总的最大文件大小,以字节为单位计算。当设为-1时表示无限制,默认是-1。maxUploadSizePerFile:跟maxUploadSize差不多,不过maxUploadSizePerFile是限制每个上传文件的大小,而maxUploadSize是限制总的上传文件大小。maxInMemorySize:设置在文件上传时允许写到内存中的最大值,以字节为单位计算,默认是10240。resolveLazily:为true时,启用推迟文件解析,以便在UploadAction中捕获文件大小异常。

    LoveIT 2019-08-12
    Spring MVC
  • SpringMVC拦截器(Interceptor)详解

    SpringMVC拦截器(Interceptor)详解

    1、拦截器概述1.1什么是拦截器?       SpringMVC中的拦截器(Interceptor)类似于Servlet中的过滤器(Filter),但是比过滤器的功能更加强大,它主要用于拦截用户请求并作相应的处理。例如通过拦截器可以进行权限验证、记录请求信息的日志、判断用户是否登录等。要使用SpringMVC中的拦截器,就需要对拦截器类进行定义和配置。通常拦截器类可以通过两种方式来定义:1.通过实现HandlerInterceptor接口,或继承HandlerInterceptor接口的实现类(如HandlerInterceptorAdapter)来定义。2.通过实现WebRequestInterceptor接口,或继承WebRequestInterceptor接口的实现类来定义。2、自定义拦截器以实现HandlerInterceptor接口方式为例,自定义拦截器类的代码如下:上述代码中,自定义拦截器实现了HandlerInterceptor接口,并实现了接口中的三个方法:preHandle():在目标方法执行之前回执行,有个boolean类型的返回值,当返回true表示放行,即允许执行目标方法;当返回false,表示不放行,即不运行执行目标方法,此时会中断以后的所有过程postHandle():在目标方法执行结束后会执行,且解析视图之前执行afterCompletion():在请求到达页面,即视图渲染完成后执行开发拦截器就像开发servlet或者filter一样,都需要在配置文件进行配置,配置代码如下:上面的代码中,<mvc:interceptors>元素用于配置一组拦截器,子元素<bean>中定义的是全局拦截器,它会拦截所有的请求;而也可以使用<mvc:interceptor>元素中定义指定路径的拦截器,它会对指定路径下的请求生效。<mvc:interceptor>元素的子元素<mvc:mapping>用于配置拦截器作用的路径,该路径在其属性path中定义。如果在请求路径中包含不需要拦截的内容,还可以通过<mvc:exclude-mapping>元素进行配置。注意:<mvc:interceptor>中的子元素必须按照上述代码中的配置顺序进行编写,即<mvc:mapping><mvc:exclude-mapping><bean>,否则文件会报错。下面写一个控制器来测试一下正常情况下单个拦截器的工作流程:目标页面success.jsp测试结果2.1单个拦截器正常情况下的工作流程:拦截器preHandle方法执行,返回true继续以后的过程控制器目标方法执行拦截器postHandle方法执行页面渲染完成来到页面拦截器afterCompletion方法执行单个拦截器非正常情况下的工作流程:单个拦截器的非正常情况分为两种情况:    1、拦截器中的preHandler方法返回false;    2、虽然preHandler方法返回了true,但是其中有一个过程“炸了”,比如发生了异常没有处理接下来通过代码来测试:-第一种情况:preHandler返回false测试结果:可以看到,后面的过程直接无法执行第二种情况:preHandle方法放行了,但是有一个过程“炸了”,比如我们在控制器目标方法中制造一个异常:测试结果:可以看到,只要拦截器的prehandle方法放行了,拦截器的afterCompletion方法总会执行/font>#####2.2多个拦截器正常情况下的工作流程:实现第二个自定义拦截器:```javapackagecom.xust.iot.interceptor;importorg.springframework.web.servlet.HandlerInterceptor;importorg.springframework.web.servlet.ModelAndView;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;publicclassMySecondInterceptorimplementsHandlerInterceptor{@OverridepublicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException{System.out.println("1.执行目标方法之前......MySecondInterceptor");returntrue;}@OverridepublicvoidpostHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler,ModelAndViewmodelAndView)throwsException{System.out.println("3.执行目标方法之后......MySecondInterceptor");}@OverridepublicvoidafterCompletion(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler,Exceptionex)throwsException{System.out.println("5.来到页面之后......MySecondInterceptor");}}```配置第二个拦截器```xml可以具体配置拦截器拦截那些请求>-->```执行结果:交换拦截器在springmvc配置文件中的定义顺序:```xml可以具体配置拦截器拦截那些请求>-->```执行结果:测试结果表明:多个拦截器是有执行的先后顺序的,这个顺序就是定义的先后顺序拦截器的preHandle方法:按照定义顺序顺序执行的拦截器的postHandle方法:按照定义顺序逆序执行的拦截器的preHandle方法:按照定义顺序顺逆序执行的***多个拦截器非正常情况下的工作流程**:1、一个拦截器的preHandle方法返回false的情况:2、所有拦截器的preHandle方法都返回true,但是中间有过程发生了异常:####3、小结#####3.1单拦截器的执行顺序*正常情况下会按照:preHandle--->目标方法--->postHnadle--->页面渲染--->afterCompetion执行*当preHandle返回false,就没有以后流程的事儿了当preHandler返回了true,但是中间过程发生异常,会直接结束以后的流程但是afterCompetion总会执行3.2多个拦截器的执行顺序正常情况会按照配置中定义的顺序顺序执行所有拦截器的preHandle方法,然后执行控制器中目标方法,之后按照定义顺序的逆序执行postHandle方法,然后渲染页面,最后按照定义的顺序的逆序执行afterComprtion方法有拦截器返回false在多个拦截器中只要有一个拦截器的preHandle方法返回了false,那么以后的流程都没有了,会直接回按照这些拦截器配置的定义顺序的逆序执行afterCompetion方法

    LoveIT 2019-08-11
    Spring MVC
  • SpringMVC对Ajax异步请求的支持

    SpringMVC对Ajax异步请求的支持

    1、Ajax异步请求概念1.1AJAX:AnsycJavascriptAndXml(异步请求)       异步是指基于Ajax的应用与服务器通信的方法。对于传统的Web应用,每次用户发送请求或向服务器请求获得新数据时,浏览器都会完全丢弃当前页面,而等待重新加载的页面。在服务器完全响应之前,用户浏览器将是一片空白,用户的动作必须中断。异步是指用户发送请求后,完全无须等待,请求在后台发送,不会阻塞用户的当前活动,用户无须等待第一次请求得到完全响应,就可以立即发送第二次请求。简单的说,异步请求不会刷新当前html页面。异步指的是服务器端响应数据的获取方式。同步:异步:#####1.2异步&同步的区别1.同步请求:>请求的过程:浏览器(当前的html页面会丢弃)--->http协议--->Web服务器(tomcat)响应的过程:Web服务器(tomcat)--->http协议-->返回一个新html页面.2.异步请求:>请求的过程:浏览器(当前的html页面不会丢弃)--->Ajax引擎(http协议)--->Web服务器(tomcat)响应的过程:Web服务器(tomcat)--->准备部分数据-->Ajax引擎(http协议)-->DOM编程.总而言之,异步请求只是局部刷新页面,同步请求会全部刷新当前的页面####2、jQuery框架的异步请求和处理1.$.ajax([settings])—jQuery核心处理异步请求的方法:语法:>$.ajax([settings])最简单的情况下,$.ajax()可以不带任何参数直接使用。具体语法格式都有哪些参数的参照:https://www.w3school.com.cn/jquery/ajax_ajax.asp2.$.post()$.post()方法通过HTTPPOST请求从服务器上请求数据。语法:>$.post(url,data,function(data,status){>//status(状态码):success、error>//data:响应数据>},dataType);必需的URL参数规定您希望请求的URL。可选的data参数规定连同请求发送的数据。可选的function参数是请求成功后所执行的函数名,其中data是响应的数据,status是状态码可选的dataType参数是服务器响应返回的数据3.$.get()$.get()方法通过HTTPGET请求从服务器上请求数据。>$.get(url,data,function(data,status){>//status(状态码):success、error>//data:响应数据>},dataType);必需的URL参数规定您希望请求的URL。可选的data参数规定连同请求发送的数据。可选的function参数是请求成功后所执行的函数名,其中data是响应的数据,status是状态码可选的dataType参数是服务器响应返回的数据####3、SpringMVC支持ajax异步请求和处理返回json数据#####3.1数据绑定@RequestBody/@ResponseBody***@RequestBody**    功能:用于将HttpServletRequest的getInputStream()的内容绑定到方法入参例如:>@RequestMapping(value="/hello")>publicStringhandleRequest(@RequestBodyStringbody){>//body参数就被请求参数自动绑定>}***@ResponseBody**    功能:被ResponseBody修饰的方法的返回值会被作为响应体>@RequestMapping(value="/hello")>@ResponseBody>publicUserhandleRequest(Ueseruser){>>returnUser;//返回值会被作为响应体,而且如果返回值是对象时SpringMVC会自动转换成JSON给页面>}#####3.2使用@RequestBody/@ResponseBody来支持Ajax可以使用@RequestBody来自动获取Ajax上传的数据,同时也可以使用@ResponseBody,把要返回的对象自动拼成JSON的格式返回。当然,需要加入几个jackson的包,这里加入了:jackson-core-2.9.3.jar、jackson-annotations-2.9.3.jar、jackson-databind-2.9.3.jar,Maven依赖如下:```xmlcom.fasterxml.jackson.corejackson-databind2.9.3com.fasterxml.jackson.corejackson-core2.9.3com.fasterxml.jackson.corejackson-annotations2.9.3```Controller```java/***ResponseBody:用于将ResponseBody方法的返回值作为响应体*RequestBody:用于将HttpServletRequest的getInputStream()内容绑定到入参**@paramusers*@return*/@ResponseBody@RequestMapping(value="/getAllUserByAJAX",produces="application/json;charset=UTF-8")publicListgetAllUserByAJAX(@ModelAttribute("users")Listusers){returnusers;}/***RequestBody:将请求体的数据绑定到入参**@paramuser*@return*/@ResponseBody@RequestMapping("/testRequestBody")publicUsertestRequestBody(@RequestBodyUseruser,Modelmodel){System.out.println("请求的数据:"+user);model.addAttribute("requestInfo",user);returnuser;}/***提前把全部信息查询好放在隐含模型中*@parammodel*/@ModelAttribute("users")publicvoidgetAll(Modelmodel){IUserServiceuserService=newIUserServiceImpl();Listlists=userService.getUser(null,null,null);model.addAttribute("users",lists);}```1.通过AJAX获得服务器数据的页面:```jspajax获取全部用户信息```测试结果2.通过AJAX向服务器发JSON数据,服务器返回JSON数据```jspTitleAJAX发送JSON数据给服务器```测试结果

    LoveIT 2019-08-10
    Spring MVC
  • SpringMVC异常处理

    SpringMVC异常处理

    1、重要的接口和类1.1HandlerExceptionResolver       他是SpringMVC“九大组件”之一,SpringMVC异常处理核心接口。该接口定义了1个解析异常的方法:1.2ExceptionHandlerExceptionResolver       继承自AbstractHandlerMethodExceptionResolver,该类主要处理Controller中用@ExceptionHandler注解定义的方法。该类是<annotation-driven/>配置中定义的HandlerExceptionResolver实现类之一,大多数异常处理都是由该类操作。 在Controller中使用@ExceptionHandler处理异常异常后的页面:测试结果:       像这样在Controller中借助@ExceptionHandler这个注解定义的异常处理方法只能在定义的那个Controller中使用,当Controller类十分多的时候,那么写异常处理方法就是个体力活了,因此SpringMVC就提供了@ControllerAdvice这个注解,它只能用在类上,而这个类中的异常处理方法都是全局范围,如下定义一个类专门集中处理异常:1.3DefaultHandlerExceptionResovler       HandlerExceptionResolver接口的默认实现之一 ,基本上是SpringMVC内部使用,用来处理Spring定义的各种标准异常,将其转化为相对应的HTTPStatusCode。其处理的异常类型有:1.4ResponseStatusExceptionResovler       用来支持@ResponseStatus的使用,处理使用了ResponseStatus注解的异常,根据注解的内容,返回相应的HTTPStatusCode和异常页面给客户端。如果Web应用程序中配置了ResponseStatusExceptionResolver,那么我们就可以使用ResponseStatus注解来注解我们自己编写的异常类,并在Controller中抛出该异常类,之后ResponseStatusExceptionResolver就会自动帮我们处理剩下的工作。<annotation-driven/>配置中定义的HandlerExceptionResolver实现类之一。 自定义一个异常另一个自定义异常在Controller中主动抛出这个异常看看效果:测试结果:ExceptionHandlerExceptionResolver、DefaultHandlerExceptionResolver和ResponseStatusExceptionResolver这三个类是<mvc:annotation-driver>配置后默认的3个实现类,他们的优先级是按书写的顺序由高到底。1.5SimpleMappingExceptionResovler提供了将异常映射为视图的能力,高度可定制化。其提供的能力有:1.根据异常的类型,将异常映射到视图;2.可以为不符合处理条件没有被处理的异常,指定一个默认的错误返回;3.处理异常时,记录log信息;4.指定需要添加到Modle中的Exception属性,从而在视图中展示该属性。

    LoveIT 2019-08-09
    Spring MVC
  • SpringMVC对资源国际化的支持

    SpringMVC对资源国际化的支持

    1、资源国际化开发1.1什么是资源国际化?       软件的国际化:软件开发时,要使它能同时应对世界不同地区和国家的访问,并针对不同地区和国家的访问,提供相应的、符合来访者阅读习惯的页面或数据。国际化(internationalization)又称为i18n(读法为i18n,据说是因为internationalization(国际化)这个单词从i到n之间有18个英文字母,i18n的名字由此而来)1.2国际化的基本规则       国际化信息”也称为“本地化信息”,一般需要两个条件才可以确定一个特定类型的本地化信息,它们分别是“语言类型”和“国家/地区的类型”。如中文本地化信息既有中国大陆地区的中文,又有中国台湾、中国香港地区的中文,还有新加坡地区的中文。Java通过java.util.Locale类表示一个本地化对象,它允许通过语言参数和国家/地区参数创建一个确定的本地化对象。       语言参数使用ISO标准语言代码表示,这些代码是由ISO-639标准定义的,每一种语言由两个小写字母表示。在许多网站上都可以找到这些代码的完整列表,下面的网址是提供了标准语言代码的信息:http://www.loc.gov/standards/iso639-2/php/English_list.php。       国家/地区参数也由标准的ISO国家/地区代码表示,这些代码是由ISO-3166标准定义的,每个国家/地区由两个大写字母表示。用户可以从以下网址查看ISO-3166的标准代码:http://www.iso.ch/iso/en/prods-services/iso3166ma/02iso-3166-code-lists/list-en1.html。下面是常用的国家/地区语言参数:2、资源国际化简单示例编写国际化资源文件:国际化资源文件就是用一种key-value的形式把要显示的信息的不同语言的翻译版本写到properties资源文件中。(1)英文的资源文件(2)简体中文的资源文件注意:一般情况下我们用*._zh_CN.properties表示中文资源文件,*.properties表示默认的资源文件。在springmvc配置文件中简单的配置一下,把我们的资源文件交给SpringMVC管理编写一个用户登录表单上面的代码中用到了JSTL中的fmt标签<fmt:message>,因此需要导入对应的jar包。测试结果我的浏览器默认就是中文,因此显示的就是中文的欢迎信息:在火狐浏览器中手动更改语言为英文英文环境下就显示的是英文信息:3、资源文件的编码问题       一般我们采用properties文件来保存资源文件。properties文件是以key-value的形式来保存文件的。login_zh_CN.properties中保存的是经过utf-8编码字后的ASCII字符,Unicode字符中不允许出现中文、日文等其他字符的文字。但是Unicode编码后的文字阅读起来比较困难,在IDEA中,可以在File->Settings->Editor->FileEncodings设置中勾选Transparentnative-to-asciiconversion,如下图,设置好后点击Apply,然后回到刚才编写的中文资源文件发现中文字符全部乱码了,这时可以在编辑器中直接重新输入中文。虽然我们输入的是中文,但是IDEA已经帮我们做了中文转码。4、在程序中获取国际化信息在程序中我们可以通过ResourceBundleMessageSource来获取资源文件的信息:执行结果:可以看到在不同对语言环境下使用了不同的资源文件。5、自定义区域信息解析器3个步骤:1、写一个类实现LocaleResolver接口或他的子接口或继承他的实现类,最主要是要实现它的resolveLocale方法2、在springmvc的配置文件中注册自定义的区域信息解析器3、启动测试(1)写一个类实现LocalResolver接口(2.1)在springmvc的配置文件中注册自定义的区域信息解析器注意:解析器的id必须是localeResolver,如果写错了就没有效果了。至于为啥非要这么写请参考SpringMVC源码中的DispatcherServlet这个类。(2.2)在页面中加入可以切换语言的链接(3)测试6、SessionLocaleResolver从SpringMVC的区域信息的继承图中我么看到了几个特别的区域信息解析器:1.AcceptHeaderLocaleResolver:它是SpringMVC默认装配的区域信息解析器,他会默认从accept-language请求头信息进行解析处理,通常这个头信息包含客户端操作信息的本地标示。它不支持通过链接的方式改变locale信息。2.FixedLocaleResolver:从字面意思就可以知道,这也是一个不支持通过链接的方式改变locale信息的一个解析器,它默认会从操作系统拿locale信息。3.SessionocaleResolver:从session中拿locale信息,允许设置区域信息。4.CookieLocaleResolver:从Cookie中拿locale信息,允许设置区域信息。下面我们借助SessionLocaleResolver来实现我们上面自定义区域信息解析器的功能:测试结果:7、使用LocaleChangeInterceptor通过配置LocaleChangeInterceptor,我们可以动态改变本地语言。它会检测请求中的参数并且改变地区信息。它调用LoacalResolver.setLocal()进行配置。既然是拦截器,要使用他就需要在springmvc配置文件中配置它,配置也很简单:然后在配合SessionLocaleResovler,实现动态的改变本地信息控制器层的代码瞬间变得极其简单,就一个跳转页面对返回语句测试结果:

    LoveIT 2019-08-08
    Spring MVC
  • SpringMVC 数据绑定&数据格式化&数据校验

    SpringMVC 数据绑定&数据格式化&数据校验

    1、数据绑定流程SpringMVC将ServletRequest对象及目标方法的入参实例传给WebDataBinderFactory实例,创建出DataBinder(数据绑定的核心部件)DataBinder调用转配在SpringMVC上下文中的ConversionService组件进行数据类型转换、数据格式化。并将servlet中的请求信息填充到入参对象中调用Validator组件对已经绑定好的请求消息的入参进行数据合法性校验,并最终生成数据绑定结果BindingResult对象SpringMVC抽取BindingResult中的入参对象和检验错误对象,将他们赋给处理方法的响应入参SpringMVC通过反射机制对目标方法进行解析,将请求消息绑定到处理方法的入参中。2、数据转换2.1ConversionServiceSpringMVC上下文中内建了很多转换器,可完成大多数Java类型的转换工作。Spring3.0添加了一个通用的类型转换模块,位于org.springframework.core.convert包中ConversionService接口是类型转换的核心接口ModifierandTypeMethodandDescriptionbooleancanConvert(ClasssourceType,ClasstargetType)判断是否可以将一个java类转换为另一个java类booleancanConvert(TypeDescriptorsourceType,TypeDescriptortargetType)需转换的类将以成员变量的方式出现在宿主类中,TypeDescriptor不但描述了需转换类的信息,还描述了从宿主类的上下文信息,如成员变量上的注解,成员是否是数组、集合或Map的方式呈现等Tconvert(Objectsource,ClasstargetType)将原类型对象转换为目标类型对象.Objectconvert(Objectsource,TypeDescriptorsourceType,TypeDescriptortargetType)将对象从原类型对象转换为目标类型对象,此时往往会用到所在宿主类的上下文信息2.2自定义类型转换器       Spring在org.springframework.core.convert.converter包中定义了3种类型转换器接口,实现任意一个转换器接口都可以作为自定义转换器注册到ConversionServiceFactroyBean中:-Converter<S,T>:将S类型对象转换为T类型对象-ConverterFactory:将相同系列多个Converter封装在一起.如果希望将一种类型的对象转换为另一种类型及其子类的对象(例如将String转换为Number及Number子类(Integer、Long、Double等)对象)可使用该转换器工厂类-GenericConverter:会根据源类对象及目标类对象所在的宿主类找那个的上下文信息进行类型转换       ConverstionServiceFactoryBean的converters属性可以接受Converter、ConverterFactory、GenericConverter或ConditionalGenericConverter接口的实现类,并把这些转换器的转换逻辑统一封装到一个ConverstionService实例对象中(GenericConversionService),Spring在Bean属性配置及SpringMVC请求消息绑定时将利用这个ConversionService实例完成类型转换工作。实际应用中常用的是Converter<S,T>,下面通过他实现一个自定义的类型转换器。关键步骤:1.实现Converter接口,他有两个泛型,S:是转换前的了类型,T:是转换后的类型,实现Converter接口的conver方法,在方法中定制对S类型如何转换换成T类型的规则2.在springmvc配置文件中将自定义的Converter配置在ConversionService中3.告诉SpringMVC使用我们自定义的类型转换器假设处理方法有一个User类型的入参,我们希望将一个格式化的请求字符串直接转为User对象,该字符串格式如(小明:男:软件工程:软工3306班:1134556)-编写自定义类型转换器在SpringMVC配置文件中将自定义的Converter方在IOC容器中交给Spring管理用<mvc:annotation-drivenconversion-service=”xxx”/>覆盖默认的类型转换器控制器:测试结果3、数据格式化       Spring使用转换器进行源类型对象到目标类型对象的转换,Spring的转换不提供输入及输出信息格式化工作,像日期、时间、数字、货币等数据都具有一定格式的,在不同的本地化环境中,同一类型的数还会相应地呈现不同的显示格式。如何从格式化的数据中获取真正的数据以完成数据绑定,并将处理完成的数据输出为格式化的数据,是spring格式化框架要解决的问题,Spring引入了一个新的格式化框架,这个框架位于org.springframework.format类包中,其中最重要的一个接口FormatterSpring的org.springframework.format.datetime包中提供了一个用于时间对象格式化的DateFormatter实现类,而org.springframework.format.number包中提供了3个用于数字对象格式化的实现类。-NumberFormatter:用于数字类型对象的格式化-CurrencyFormatter:用于货币类型对象的格式化-PercentFormatter:用于百分数数字类型对象的格式化示例:有一个员工类employee.java要使注解可以发挥作用还需要在注解中配置如下信息:       对属性对象的输入/输出进行格式化,从其本质上讲依然属于“类型转换”的范畴。Spring在格式化模块中定义了一个实现ConversionService接口的FormattingConversionService实现类,该实现类扩展了GenericConversionService,因此它既具有类型转换的功能,又具有格式化的功能。    FormattingConversionService拥有FormattingConversionServiceFactroyBean工厂类,后者用于在Spring上下文中构造前者FormattingConversionServiceFactroyBean内部已经注册了:NumberFormatAnnotationFormatterFactroy:支持对数字类型的属性使用@NumberFormat注解JodaDateTimeFormatAnnotationFormatterFactroy:支持对日期类型的属性使用@DateTimeFormat注解装配了FormattingConversionServiceFactroyBean后,就可以在SpringMVC入参绑定及模型数据输出时使用注解驱动了。<mvc:annotation-driven/>默认创建的ConversionService实例即为FormattingConversionServiceFactroyBean.4、数据校验       应用程序在执行业务逻辑前,必须通过数据校验保证接收到的输入数据是正确合法的,如代表生日的日期应该是一个过去的时间、工资的数值必须是一个整数等。一般情况下,应用程序的开发时分层的,不同层的代码由不同的开发人员负责。很多时候,同样的数据验证会出现在不同的层中,这样就会导致代码冗余,违反了DRY原则。为了避免这样的情况,最好将验证逻辑和响应的域模型进行绑定,将代码验证的逻辑集中起来管理。4.1JSR-303规范       JSR-303规范是Java为Bean数据合法校验锁提供的标准框架,它已经包含在JavaEE6.0中。JSR-303通过在Bean属性上标注类似于@NotNull、@Max等标准的注解指定校验规则,并通过标准的验证接口对Bean进行验证。可以通过http://jcp.org/en/jsr/detail?id=303了解更多详细内容。JSR-303定义了一套可标注在成员变量、属性方法上的校验注解:JSR-303支持XML风格的和注解风格的验证,接下来我们首先看一下如何和Spring集成。1.导入jar包,此处使用Hibernate-validator实现(版本:hibernate-validator-6.0.17.Final-dist.zip),他的Maven依赖如下:在Spring配置中添加JSR-303验证框架支持通过ConfigurableWebBindingInitializer注册validator使用JSR-303验证框架注解为模型对象指定验证信息控制器通过在命令对象上注解@Valid来告诉SpringMVC此命令对象在绑定完毕后需要进行JSR-303验证,如果验证失败会将错误信息添加到Errors错误对象中。5.验证失败后回到填写表单的页面(/WEB-INF/jsp/pages/add.jsp)测试结果:4.2自定义国际化错误消息提示在上面的程序中有一个不好的地方,错误消息不是我们自定义的,而且都是英文的,下面我们来看看如何在通过国际化配置文件实现自定义国际化错误消息提示。使用System.out.println("错误码:"+fieldError.getCodes());可以得到错误的错误码,每种错误都定义了4中错误码,如下:他们从上到下所包含的范围由小到大,我们在写国际化配置文件的时候,每条配置的key必须是4个code中的一个code。`error_en_US.properties`error_zh_CN.properties在springmvc.xml文件中配置国际化资源:测试结果:

    LoveIT 2019-08-07
    Spring MVC
  • Spring MVC视图解析

    Spring MVC视图解析

          对于控制器的目标方法,无论其返回值是String、View、ModelMap或是ModelAndView,SpringMVC都会在内部将它们封装为一个ModelAndView对象进行返回。   SpringMVC借助视图解析器(ViewResolver)得到最终的视图对象(View),最终的视图可以是JSP也可是Excell、JFreeChart等各种表现形式的视图。1、视图(View)视图的作用是渲染模型数据,将模型里的数据以某种形式呈现给客户。为了实现视图模型和具体实现技术的解耦,Spring在org.springframework.web.servlet包中定义了一个高度抽象的View接口。视图对象由视图解析器负责实例化。由于视图是无状态的,所以他们不会有线程安全的问题。所谓视图是无状态的,是指对于每一个请求,都会创建一个View对象。 JSP是最常见的视图技术。2、视图解析器(ViewResolver)和视图(View)springMVC用于处理视图最重要的两个接口是ViewResolver和View。所以视图解析器的作用就是通过视图名(处理方法的返回值)生成View对象,所有的视图解析器都必须实现ViewResolver接口。  SpringMVC为逻辑视图名的解析提供了不同的策略,可以在SpringWEB上下文中配置一种或多种解析策略,并指定他们之间的先后顺序。每一种映射策略对应一个具体的视图解析器实现类。程序员可以选择一种视图解析器或混用多种视图解析器。可以通过order属性指定解析器的优先顺序,order越小优先级越高,SpringMVC会按视图解析器顺序的优先顺序对逻辑视图名进行解析,直到解析成功并返回视图对象,否则抛出ServletException异常。在项目中可以配置InternalResourceViewResolver作为视图解析器,在springmvc.xml中可以做如下配置:3、forward:和redirect:一般情况下,控制器方法返回字符串类型的值会被当成逻辑视图名处理,会经过视图解析器拼串,但如果返回的字符串中带forward:或redirect:前缀时,SpringMVC会对它们进行特殊处理:将forward:和redirect:当成指示符,其后的字符串作为URL来处理。示例如下:index.htmlhello.jsp,在当前项目的根路径下,和index.html同级ViewTestController.java测试结果:按F12打开开发者工具,可以看到确实两次重定向4、SpringMVC视图的解析流程(结合源码分析)源码中把任何返回返回值封装为ModelAndView的实现:这里以发出了一个GET请求为例:首先FrameworkServlet类会来处理这个GET请求doGetprocessRequestDispatcherServlet类doService方法doDispatch方法processDispatchResult方法,这个方法就是最终将数据交给页面的方法DispatcherServlet类的render方法并没有继承View接口的render,和View接口的render不是一回事,这个render仅仅是为了命名统一而起的一个名字resolveViewName方法,循环遍历你配置的视图解析器,viewResolvers是进过order排序的,这一步就是ViewResolvers是如何通过视图名产生View对象的关键InternalResourceViewResolver继承了AbstractCachingViewResolver,resolveViewName方法首先会判断有没有缓存,要是有缓存,它会先去缓存中通过viewName查找是否有View对象的存在,要是没有,它会通过viewName创建一个新的View对象,并将View对象存入缓存中,这样再次遇到同样的视图名的时候就可以直接在缓存中取出View对象了createView的实现细节:以下都是解析视图名的实现细节,感兴趣的可以看一下。父类AbstractCachingViewResolver类的createView实现细节:InternalResourceViewResolver继承了UrlBasedViewResolverUrlBasedViewResolver类中loadView方法的实现:UrlBasedViewResolver的buildView方法会获取一个View对象,这个对象会将视图以什么格式呈现给用户,例如如果是jsp显示呈现给用户的话,那这个view对象就是JstlView,默认的是JstlView。在这个方法中我们看到了getPrefix()+viewName+getSuffix()这样一段代码,这就是对视图路径的一个拼接了,getPrefix()方法获取前缀,也就是我们在配置文件中配置的<propertyname="prefix"value="/WEB-INF/PAGE/"/>的value中的值了,getSuffix()方法就是获取后缀值了,也就是我们在配置文件中配置的<propertyname="suffix"value=".jsp"/>的value中的值。这样就将将视图的物理路径找到了,并赋值到View的URL属性中去。就这样我们得到了一个View对象,这个视图的name就是逻辑视图名,因为当将View对象放在缓存的时候,我们可以通过逻辑视图名在缓存中找出View对象。我们在获取到View对象的时候,我们还要将View进行渲染,并呈现给用户。View是个接口,AbstractView实现了render方法:最后一行的renderMergedOutputModel方法由AbstractView的孙子类InternalResourceView实现InternalResourceView的renderMergedOutputModel方法帮我们获取到视图的物理路径,然后将这段路径传给RequestDispatcher对象,再调用RequestDispatcher的forward方法将页面呈现给用户,这样就走完了视图的解析了。最后一句话总结:视图解析器只是为了得到视图对象;视图对象才是真正的转发(将模型数据发在request域中数据)或重定向到页面(视图对象才是真正的渲染视图)。

    LoveIT 2019-08-06
    Spring MVC
  • Spring MVC从入门到精通—向页面带回响应数据的方法

    Spring MVC从入门到精通—向页面带回响应数据的方法

    1、SpringMVC提供了以下几种途径输出模型数据:ModelAndView:处理方法返回值类型为ModelAndView时,方法体即可通过该对象添加模型数据Map、Model以及ModelMap:入参为org.springframework.ui.Model、org.springframework.ui.ModelMap或Java.uti.Map时,处理方法返回时,Map中的数据会自动添加到模型中。@SessionAttributes:将模型中的某个属性暂存到HttpSession中,以便多个请求之间可以共享这个属性@ModelAttribute:方法入参标注该注解后,入参的对象就会放到数据模型中。当然,除了上面这些SpringMVC提供的几种方法,SpringMVC支持直接使用Servlet几个原生API来给页面传值:HttpServletRequestrequest、HttpservletResponseresponse、HttpSessionsession、InputStream/Reader对应request.getInputStream()、OutputStream/Writer对应response.getOutputStram()1.1Servlet原生API给页面传值页面测试代码:success.jsp测试结果:1.2Model、Map、ModelMap首先通过通过源码看看他们三者的关系:(1)ModelMap类(2)Model接口(3)ExtendModelMap类(4)BindingAwareModelMap类通过打开源码,我们不难总结出如下继承关系:接下来看看他们的用法:示例代码页面代码和上面样测试结果(1)页面的显示:(2)控制台打印的信息:从测试结果可以总结出:Model(SpringMVC接口)其中一个实现类是ExtendedModelMapModelMap是Map(JDK的接口)Map的一个实现类,并且ModelMap被ExtendedModelMapExtendedModelMap被BindingAwareModelMap继承Model、Map、ModelMap不论用哪个,最终工作的都是BindingAwareModelMap,而且从测试结果可以看到通过这三个设置的值,SpringMVC都把他们放在了request域中。1.3ModelAndView目标方法的返回值可以是ModelAndView类型,从名字上就可以看到,这是一个既包括模型(Model)又有视图(View)的一个类,然而事实也确实如此,他的model就可以理解为送给页面的数据,他的View可以理解为目标页面地址。但我们在他的model中放入值后,SpringMVC会把ModelAndView的model中数据放在request域对象中。示例代码测试结果:1.4使用@SessionAttributes注解       如果希望在多个请求之间共用某个模型属性数据,则可以在控制器类标注一个@SessionAttributes,SpringMVC会将模型中对应的属性暂存到HTTPSession中。@SessionAttributes除了可以通过属性名指定需要放到会话中的属性外,还可以通过模型属性的对象类型指定哪些模型属性需要放到会话中。1.@SessionAttributes(types=User.class)会将隐含模型中所有类型为User的属性添加到会话中2.@SessionAttributes(value={"user1","user2"})将名为user1和user2的模型属性添加到会话中3.@SessionAttributes(types={"User.class","Dept.class"})将模型中所有类型为User及Dept的属性添加到会话中4.@SessionAtributes(value={"user1","user2"},types={Dept.class})将名为user1和user2的模型属性添加到会话中,同时将所有类型为Dept的模型属性添加到会话中总之:当使用@SessionAttributes注解时就是告诉SpringMVC,当@SessionAttributes中的value值和BindingAwareModelMap的key一样时,那么在session也你也给我保存一份相同的值示例代码:页面代码对success.jsp中的sessionScope稍作修改:测试结果:1.5使用@ModelAttribute注解先来看看ModelAttribute的定义:通过@ModelAttribute的定义可以看到这个注解可以用在方法和参数上。在SpringMVC的Controller中使用@ModelAttribute时,应用情况包括下面几种:1、应用在方法上。2、应用在方法的参数上。3、应用在方法上,并且方法也使用了@RequestMapping示例代码:修改图书信息的页面:提交图书修改信息后的页面:如果没有使用@ModelAttribute,那么要更新数据信息,必须要全字段更新,即使你不需要更新的的字段,你也要填写,这显然不和常理,因为如果你不填写这个值,值就会为null。最主要是因为SpringMVC在封装提交的信息的时候只会new一个Book对象,里面的属性的值初始就是null。你没有填写也只会以null存到数据库。不使用@ModelAttribute进行非全字段更新测试结果:页面的显示:看看控制台的打印信息:可以看到果然不出预料的出问题了,更新信息后书名和作者的信息没了。这就相当于你更改了一下你的QQ密码,然后你的QQ号没了!这是很可怕的事情。使用@ModelAttribute解决问题:测试结果:页面展示的结果:控制台打印的信息:而且从控制台打印的信息来看,被@ModelAttribute标识的方法确实是在处理器方法之前执行了1.6@Modelattribute的原理废话不多说,直接看代码测试结果:最后总结为一张图:

    LoveIT 2019-08-04
    Spring MVC
  • Spring MVC从入门到精通—@RequestMapping注解详解

    Spring MVC从入门到精通—@RequestMapping注解详解

           在SpringMVC中@RequestMapping注解是一个十分强大的注解,SpringMVC使用@RequestMapping注解可以为控制器指定可以处理那些URL请求,在控制器的类上或类中的方法上均可以使用这个注解:在类上使用可以提供初步的映射信息。相当于一个根路径在方法上使用提供更进一步的细分映射信息。(1)这是一个只在方法上使用@RequestMapping注解的例子:(2)这是一个在类和方法同时使用@RequestMapping注解的例子:@Requestmapping的属性:属性作用value默认的属性就是value,他就是一个URL路径,可以在一个方法上或类上给多个value值method用来定义接收浏览器发来的何种请求。在Spring中,使用枚举类RequestMethod来封装了HTTP协议的所有请求方式。最基本的有GET、POST、DELETE、PUTparams表示请求参数,也就是追加在URL上的键值对,多个请求参数以&隔开headers该属性表示请求头,通过@RequestMapping中的headers属性,可以限制客户端发来的请求consumes规定请求头的Content-Typeproduces告诉浏览器返回的内容是什么,给响应头中加上Content-Type示例代码:method:限定请求方法parmars:限定参数parmars支持简单的表达式计算,例如:eg1:params={"username"},表示请求的路径中必须要有username这个关键字,如果没有就会报异常eg2:params={"!username"},表示请求的路径中不能有username这个关键字,如果有这个参数就会报异常eg2:params={"username","age=20","pwd"},表示请求的路径中必须要有username、age、pwd这三个关键字,并且age必须是20,如果没有或age的值不等就会报异常headers:限定请求头部示例一:测试结果:

    LoveIT 2019-08-03
    Spring MVC
  • Spring MVC从入门到精通—SpringMVC获取请求参数

    Spring MVC从入门到精通—SpringMVC获取请求参数

    第一种方式:方法的形参上给一个和请求参数同名的参数1.获得普通类型的参数值示例代码2.获得POJO类型的值示例代码新建Book.java以及Address.java两个POJOBook.javaAddress.java写一个简单的表单:index.html提交后的页面:book.jsp提供一个控制器:BookContorller.java测试结果:第二种方式:使用SpringMVC提供的注解1.使用@RequestParam获取参数@RequestParam的源码:示例代码:2.使用@RequestHeader获得请求的头部信息@RequestHeader和@ReuqestParma的实现方式如出一辙,使用方法也基本相同。示例代码1:使用RequestHeader注解获得浏览器的信息示例代码2:使用RequestHeader注解获取请求头部的Cookie信息3.使用@CookieValue获得请求头部的JSESSIONID示例代码:4.使用@RequestBody接收前端传给后端的JSON格式的数据       由于GET方式无请求体,所以使用@RequestBody接收数据时,前端不能使用GET方式提交数据,而是用POST方式进行提交。在后端的同一个接收方法里,@RequestBody与@RequestParam()可以同时使用,@RequestBody最多只能有一个,而@RequestParam()可以有多个。后端@RequestBody注解对应的类在将HTTP的输入流(含请求体)装配到目标类(即:@RequestBody后面的类)时,会根据json字符串中的key来匹配对应实体类的属性,如果匹配一致且json中的该key对应的值符合(或可转换为)实体类的对应属性的类型要求时,会调用实体类的setter方法将值赋给该属性。使用示例;

    LoveIT 2019-08-02
    Spring MVC
  • Spring MVC快速入门—Spring MVC体系结构及工作流程

    Spring MVC快速入门—Spring MVC体系结构及工作流程

    SpringMVC体系结构:SpringMVC是基于MVC软件架构实现的技术框架SpringMVC的执行流程具体步骤:第一步:客户端发起请求到前端控制器(DispatcherServlet)第二步:前端控制器请求HandlerMapping查找Handler(可以根据xml配置、注解进行查找)并返回一个Handler第三步:处理器映射器HandlerMapping向前端控制器返回Handler,HandlerMapping会把请求映射为HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象,多个HandlerInterceptor拦截器对象),通过这种策略模式,很容易添加新的映射策略第四步:前端控制器调用处理器适配器HandlerAdapter去执行Handler,处理器适配器HandlerAdapter将会根据适配的结果去执行Handler第五步:Handler执行完成给适配器返回ModelAndView第六步:处理器适配器向前端控制器返回ModelAndView(ModelAndView是springmvc框架的一个底层对象,包括Model和view)第七步:前端控制器请求视图解析器ViewResolver对ModelAndView进行解析(根据逻辑视图名解析成真正的视图(jsp)),通过这种策略很容易更换其他视图技术,只需要更改视图解析器即可。视图解析器最终向前端控制器返回View第八步:前端控制器进行视图渲染(视图渲染将模型数据(在ModelAndView对象中)填充到request域)第九步:前端控制器向用户响应结果第一个SpringMVC程序第一步:配置环境(新建Web工程+导包+配置Tomcat)在IDEA中新建MavenWeb工程,新建好后导包,使用SpringMVC所需要的基本的Maven依赖如下:第二步:配置DispatcherServlet通过DispatcherServlet这个名字可以大概了解到,这就是一个servlet,因此要想使一个sevlet起作用无非两种方法:一种是在servle类的头部加@WebServlet注解,二是在web.xml文件中配置<servlet>和servlet-mapping,第一中方法在这里显然不可行,人家源码肯定不能让改,那就需要在web.xml配置它,配置如下:接着在src/resources下新建springmvc.xml,配置springmvc:第三步:在webapp包下新建一个index.html以及hello.jsp,随便写点啥第四步:新建一个Controller,比如就叫HelloController测试结果:总结在做的时候的几细节1.SpringMVC下Web项目的运行流程:1.点击http://localhost/SpringMVC_01_war_exploded/后浏览器把请求给tomcat服务器2.服务器中由于配置了SpringMVC的Dispatcherservlet,他可以收到所有的请求3.Dispatcherservlet拿到请求后查看请求地址和@RequestMapping()中的那个地址(对应的方法)匹配4.前端控制器找到目标处理器和方法后,直接利用反射调用方法5.方法执行完成会有返回值(视图名),SpringMVC认为这就是方法执行完后要去的页面6.拿到方法返回值后,视图解析器拼接触页面地址7.拿到页面地址后,前段控制器就会使用转发的方式到目标页面2.关于springmvc.xml配置文件的配置:在web.xml配置前段控制器又这么一段配置,他的作用是告诉服务器去哪里加载对于前端控制器的配置文件:<init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc.xml</param-value></init-param>如果我们没有写他会发生什么呢?会发生异常:一大堆异常信息最终就是告诉中我们你没有给配置文件的路径,那我(SpringMVC)就会在/WEB-INF目录下默认加载一个文件叫app-servlet.xml的文件,然而也没有找到,从而无法完成初始化。从这里我们知道,在配置前端控制器的时候也可以不写初始化参数,但是我们必须将springmvc配置文件放在WEB-INF目录下,并且文件的必须名字是:前端控制器的<servlet-name>app</servlet-name>+-servlet.xml,这是规定,不可随便来,你想节省一些操作就得按人家的要求来。

    LoveIT 2019-08-01
    Spring MVC