国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Spring之旅第十站:MVC配置、上傳文件、異常處理、跨重定向請(qǐng)求、為控制器添加通知

leanote / 1950人閱讀

摘要:依賴于對(duì)請(qǐng)求的支持。使用解析兼容的沒(méi)有構(gòu)造器參數(shù),也沒(méi)有要設(shè)置的參數(shù),這樣,在應(yīng)用上下文中,將其聲明為就會(huì)非常簡(jiǎn)單。默認(rèn)是沒(méi)有限制的整個(gè)請(qǐng)求的容量。

Spring MVC 高級(jí)的技術(shù)

本章內(nèi)容:

Spring MVC配置的替代方案

處理文件上傳

在控制器中處理異常

使用flash屬性

稍等還沒(méi)結(jié)束

說(shuō)明

如果你有幸能看到。后面的章節(jié)暫時(shí)不更新了,改變學(xué)習(xí)方式了。重要理解思想,這本書寫的太好了。記得要看作者的代碼,書上只是闡述了知識(shí)點(diǎn)。還有以后會(huì)把重點(diǎn)放在GitHub上,閱讀別人的代碼,自己理解的同時(shí)在模仿出來(lái),分享給大家。你們的點(diǎn)贊就是對(duì)我的支持,謝謝大家了。

1、本文參考了《Spring 實(shí)戰(zhàn)》重點(diǎn)內(nèi)容,參考了作者GitHub上的代碼,推薦使用chrome上的GitHub插件Insight.io,FireFox也有。

2、本文只為記錄作為以后參考,要想真正領(lǐng)悟Spring的強(qiáng)大,請(qǐng)看原書。跟著作者套路來(lái),先別瞎搗騰!!!

3、在一次佩服老外,國(guó)外翻譯過(guò)來(lái)的書,在GiuHub上大都有實(shí)例。看書的時(shí)候,跟著敲一遍,效果很好。

4、代碼和筆記在這里GitHub,對(duì)你有幫助的話,歡迎點(diǎn)贊。

5、每個(gè)人的學(xué)習(xí)方式不一樣,找到合適自己的就行。2018,加油。

6、Java 8 In Action 的作者M(jìn)ario Fusco、Spring In Action 、Spring Boot In Action的作者Craig Walls

7、知其然,也要知其所以然。有些是在Atom上手敲的,有拼寫錯(cuò)誤,還請(qǐng)見(jiàn)諒。

8、從Spring Web Flow 開(kāi)始,我要加快速度了,邏輯可能不完整,一切以原書為準(zhǔn),自己只是記錄。加深印象。

談一些個(gè)人感受

1、趕快學(xué)習(xí)Spring吧,Spring MVC 、Spring Boot 、微服務(wù)。

2、重點(diǎn)中的重點(diǎn),學(xué)習(xí)JDK 8 Lambda,Stream,Spring 5 最低要求JDK1.8.

3、還有Netty、放棄SH吧,不然你會(huì)落伍的。

4、多看一些國(guó)外翻譯過(guò)來(lái)的書,例如 Xxx In Action 系列。權(quán)威指南系列。用Kindle~

5、寫代碼之前先寫測(cè)試,這就是老外不同之處。學(xué)到了很多技巧。

6、再一次佩服老外對(duì)細(xì)節(jié)的處理。值得我們每一個(gè)人學(xué)習(xí)

在很多方面,Spirng MVC(整個(gè)Spirng也是如此),也有還沒(méi)結(jié)束這樣的感覺(jué)。

在第五章,我們學(xué)習(xí)了Sprng MVC的基礎(chǔ)知識(shí),以及如何編寫控制器來(lái)處理各種請(qǐng)求,基于這些知識(shí)。我們?cè)诘诹聦W(xué)習(xí)了如何創(chuàng)建JSP和Thymeleaf視圖,這些視圖會(huì)將模型數(shù)據(jù)展示給用戶。你可能認(rèn)為我們已經(jīng)掌握了Spring MVC的全部知識(shí),但是,稍等!還沒(méi)結(jié)束。

在本章中,我們將會(huì)看到如何編寫控制器處理文件上傳,如何處理控制器所拋出的異常,以及如何在模型中傳遞數(shù)據(jù),使其能夠在重定向(redirect)之后依然存活。

但,首先我要兌現(xiàn)一個(gè)承諾。在第5章中,我們快速展現(xiàn)了如何通過(guò)AbstractAnnotationConfigDispatcherServletInitializer搭建Spring MVC,當(dāng)時(shí),我們承諾會(huì)為讀者展現(xiàn)其他的配置方案。所以,在介紹文件上傳和異常處理之前,我們花時(shí)間探討一下如何使用其他方式來(lái)搭建DispatcherServletContextLoaderListener

7.1 Spring MVC 配置的替代方案

盡管對(duì)很多Spring應(yīng)用來(lái)說(shuō),這是一種安全的假設(shè),但是并不一定能滿足我們的要求。除了DispatcherServlet以外,我們還可能需要額外的DispatcherServletFilter,我們可能還需要對(duì)DispatcherServlet本身做一些額外的配置:或者,如果我們需要將應(yīng)用部署到Servlet3.0之前的容器中,那么還需要將DispatcherServlet配置到傳統(tǒng)的web.xml中。

7.1.1 自定義DispatcherServlet配置
public class SpitterWebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

  @Override
  protected Class[] getRootConfigClasses() {
    return new Class[] { RootConfig.class };
  }

  @Override
  protected Class[] getServletConfigClasses() {
    return new Class[] { WebConfig.class };
  }

  @Override
  protected String[] getServletMappings() {
    return new String[] { "/" };
  }

}

AbstractAnnotationConfigDispatcherServletInitializer所完成的事其實(shí)比看上去要多,在SpitterWebInitializer中我們所編寫的三個(gè)方法僅僅是必須要重載的三個(gè)抽象方法,但實(shí)際上還有更多的方法可以進(jìn)行重載,從而實(shí)現(xiàn)額外的配置。

此類的方法之一就是customizeRegistration().在AbstractAnnotationConfigDispatcherServletInitializerDispatcherServlet注冊(cè)到Servlet容器中就會(huì)調(diào)用customizeRegistration(),并將Servlet注冊(cè)后得到的Registration.Dynamic傳遞進(jìn)來(lái),通過(guò)重載customizeRegistration()方法,我們就可以對(duì)DispatcherServlet進(jìn)行額外的配置。

在本章稍后,我們將會(huì)看到如何在Spirng MVC中處理multiparty請(qǐng)求和文件上傳。如果計(jì)劃使用Servlet3.0對(duì)multiparty配置的支持,那么我們需要使用DispatcherServlet的registration來(lái)啟用multilpart請(qǐng)求。我們可以重載customizeRegistration()方法來(lái)設(shè)置MultipartConfigElement,

@Override
protected void customizeRegistration(Dynamic registration) {
    registration.setMultipartConfig(
            new MultipartConfigElement("C:Temp"));   //設(shè)置上傳文件目錄
}

借助customizeRegistration()方法中的ServletRegistration.Dynamic我們能夠完成更多的任務(wù),

包括通過(guò)調(diào)用setLoadOnstartup()設(shè)置load-on-startup 優(yōu)先級(jí),

通過(guò)setInitParameter()設(shè)置初始化參數(shù),

通過(guò)調(diào)用setMultipartConfig()配置Servlet3.0對(duì)multipart的支持,

7.1.2 添加其他的Servlet和Filter

按照AbstractAnnotationConfigDispatcherServletInitializer的定義,它會(huì)創(chuàng)建DispatcherServletContextLoaderListener.但是如果你想要注冊(cè)其他的Servlet、Filter、Listener的話,那該怎么辦?

基于Java的初始化器(initializer)的一個(gè)好處在于我們可以定義任意數(shù)量的初始化類。如果我們想要往Web容器中注冊(cè)其他組件的話,只需要?jiǎng)?chuàng)建一個(gè) 新的初始化類就可以了,最簡(jiǎn)單的方式就是實(shí)現(xiàn)Spring的WebApplicationInitializer并注冊(cè)一個(gè)Servlet。

public class MyServletInitializer implements WebApplicationInitializer {
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
      Dynamic  myServlet = servletContext.addServlet("myServlet",myServlet.class);
      myServlet.addMapping("/custom/**");
    }
}

以上程序相當(dāng)基礎(chǔ)的Servlet注冊(cè)初始化器類,它注冊(cè)了一個(gè)Servlet并將其映射到了一個(gè)路徑上,我們也可以通過(guò)這種方式來(lái)手動(dòng)注冊(cè)DispatcherServlet.(但是沒(méi)必要,因?yàn)?b>AbstractAnnotationConfigDispatcherServletInitializer沒(méi)用太多代碼就將這項(xiàng)任務(wù)完成得很漂亮)

類似的,我們還可以創(chuàng)建新的WebApplicationInitializer來(lái)實(shí)現(xiàn)注冊(cè)Listener和 Filter,

@Override
public void onStartup(ServletContext servletContext) throws ServletException {
    javax.servlet.FilterRegistration.Dynamic filter = servletContext.addFilter("myFilter",myFilter.class);
    filter.addMappingForUrlPatterns(null,false,"/custom/*");
}

如果你將應(yīng)用部署到Servlet3.0的容器中,那么WebApplicationInitializer提供了一種通用的方法,實(shí)現(xiàn)在Java中注冊(cè)Servlet和Filter、Listener,如果你只是注冊(cè)Filter,并且該Filter只會(huì)映射到DispatcherServlet上的話,那么AbstractAnnotationConfigDispatcherServletInitializer還有一種快捷的方式。

為了注冊(cè)Filter并將其映射到DispatcherServlet,所需要做的僅僅是重載AbstractAnnotationConfigDispatcherServletInitializer的getServletFilter()方法。

@Override
protected Filter[] getServletFilters() {
    return new Filter[] {new Myfilter()};
}

這個(gè)方法返回一個(gè)javax.servlet.filter數(shù)組。在這里沒(méi)有必要聲明它的映射路徑,getServletFilter()方法返回所有Filter都會(huì)被映射到DispatcherServlet上。

如果要將應(yīng)用部署到Servlet3.0上,那么Spring容器提供了多種注冊(cè)方式,而不必創(chuàng)建web.xml文件,但是,如果你不想采取上述方案的話,也是可以的,假設(shè)你將應(yīng)用部署到不支持Servlet3.0的容器中(或者你只希望使用web.xml),那么我們完全可以按照傳統(tǒng)的方式,通過(guò)web.xml配置Spirng MVC,

7.1.3 在web.xml中聲明DispatcherServlet

在典型的Spirng MVC應(yīng)用中,我們會(huì)需要DispatcherServletContextLoaderListener.AbstractAnnotationConfigDispatcherServletInitializer會(huì)自動(dòng)注冊(cè)它們,但如果需要在web.xml中注冊(cè)的話,那就需要我們自己動(dòng)手來(lái)完成了。



    appServlet
    
        index.html
    
    
    
        contextConfigLocation
        classpath:spring/applicationContext-*.xml
    
    
        org.springframework.web.context.ContextLoaderListener
    
    
    
        CharacterEncodingFilter
        org.springframework.web.filter.CharacterEncodingFilter
        
            encoding
            utf-8
        
    
    
        CharacterEncodingFilter
        /*
    
    
    
        appServlet
        org.springframework.web.servlet.DispatcherServlet
    
        
            contextConfigLocation
            classpath:spring/springmvc.xml
        
        1
    
    
        appServlet
        /
    

ContextLoaderListenerDispatcherServlet各自都會(huì)加載一個(gè)Spirng應(yīng)用上下文。上下文ContextLoaderLocation指定了一個(gè)XMl文件的地址,這個(gè)文件定義了根據(jù)應(yīng)用上下文,它會(huì)被ContextLoaderListener加載。根上下文會(huì)從"/WEB-INF/spring/applicationContext-*.xml"中加載bean的定義

DispatcherServlet會(huì)根據(jù)Servlet的名字找到一個(gè)文件,并基于該文件加載應(yīng)用上下文。

如果你希望指定DispatcherServlet配置文件的話,那么可以在Servlet指定一個(gè)ContextLoaderLocation初始化參數(shù)。



  appServlet
  org.springframework.web.servlet.DispatcherServlet
  
  
    contextConfigLocation
    classpath:spring/springmvc.xml
  
  1


  appServlet
  /

現(xiàn)在我們已經(jīng)看到了如何以多種不同的方式來(lái)搭建Spring MVC,那么接下來(lái)我們看一下如何使用Spring MVC來(lái)處理文件上傳。

7.2 處理multipart形式的數(shù)據(jù)

在Web應(yīng)用中,允許用戶上傳內(nèi)容是很常見(jiàn)的需求,在Facebook和Flickr這樣的網(wǎng)站中,允許用戶會(huì)上傳圖片和視頻,并與家人朋友分享。還有一些服務(wù)器中允許用戶上傳照片,然后按照傳統(tǒng)的方式將其打印在紙上,或者咖啡杯上。

Spittr應(yīng)用有兩個(gè)地方需要文件上傳。當(dāng)新用戶注冊(cè)的時(shí)候,我們希望能夠上傳一張照片,從而與他的個(gè)人信息相關(guān)聯(lián)。當(dāng)用戶提交新的Spittle時(shí),除了文本信息外,他們可能還會(huì)上傳一張照片。

一般表單提交所形成的請(qǐng)求結(jié)果是非常簡(jiǎn)單的,就是以"&"符號(hào)分割的多個(gè)name-value對(duì),盡管這種方式簡(jiǎn)單,并且對(duì)于典型的基于文本的表單提交也足夠滿足需求,但是對(duì)于二進(jìn)制數(shù)據(jù),就顯得力不從心了。與之不同的是multipart格式的數(shù)據(jù)會(huì)將一個(gè)表單拆分為多個(gè)部分(part),每個(gè)部分對(duì)應(yīng)一個(gè)輸入域。在一般的表單輸入域中,它所對(duì)應(yīng)的部分中會(huì)放置文本數(shù)據(jù),但是如果是上傳文件的話,它所對(duì)應(yīng)的部分可以是二進(jìn)制。

Content-Type 他表它的類型。盡管multipart請(qǐng)求看起來(lái)很復(fù)雜,但是在SpringMVC中處理它卻很容易,在編寫控制器方法處理文件上傳之前,我們必須配置一個(gè)multipart解析器,通過(guò)它來(lái)告訴DispatcherServlet該如何讀取multipart請(qǐng)求。

7.2.1 配置multipart解析器

DispatcherServlet并沒(méi)有實(shí)現(xiàn)愛(ài)你任何解析multipart請(qǐng)求數(shù)據(jù)的功能。它將該任務(wù)委托給了Spring中的MultipartResolver策略接口的實(shí)現(xiàn),通過(guò)這個(gè)實(shí)現(xiàn)類來(lái)解析multipart請(qǐng)求中的內(nèi)容。從Spirng 3.1開(kāi)始,Spirng內(nèi)置了兩個(gè)MultipartResolver的實(shí)現(xiàn)供我們選擇。

CommonsMultipartResolver:使用Jakarta Commons FileUpload解析multipart請(qǐng)求。

StandardServletMultipartResolver:依賴于Servlet3.0對(duì)multipart請(qǐng)求的支持。

一般來(lái)講StandardServletMultipartResolver可能會(huì)是優(yōu)選方案,他使用Servlet所提供的功能支持。并不需要依賴任何其他的項(xiàng)目。如果,我們需要將項(xiàng)目部署到Sevrvlet3.0之前的容器中,或者還沒(méi)有使用Spring 3.1 或者更高的版本,那么可能就需要 CommonsMultipartResolver了。

使用Servlet3.0解析multipart

兼容Servlet3.0的StandardServletMultipartResolver沒(méi)有構(gòu)造器參數(shù),也沒(méi)有要設(shè)置的參數(shù),這樣,在Spring應(yīng)用上下文中,將其聲明為bean就會(huì)非常簡(jiǎn)單。

@Bean
public MultipartResolver multipartResolver() throws IOException {
    return new StandardServletMultipartResolver();
}

如果我們采用Servlet初始化類的方式來(lái)配置DispatcherServlet的話,這個(gè)初始化類應(yīng)該已經(jīng)實(shí)現(xiàn)了WebApplicationInitializer,那么我們可以在ServletRegistration上調(diào)用setMultipartConfig()方法,傳入一個(gè)MultipartConfigElement實(shí)例,具體的配置如下:

@Override
protected void customizeRegistration(Dynamic registration) {
    registration.setMultipartConfig(
            new MultipartConfigElement("C:Temp"));
}
}

通過(guò)重載customizeRegistration()方法(它會(huì)得到一個(gè)Dynamic作為參數(shù))類配置multipart的具體細(xì)節(jié)。

到目前為止,我們所使用的是只有一個(gè)參數(shù)的MultipartConfigElemenet構(gòu)造器,這個(gè)參數(shù)指定的是文件系統(tǒng)中一個(gè)絕對(duì)目錄,上傳文件將會(huì)臨時(shí)寫入該目錄,但是,我們還可以通過(guò)其他的構(gòu)造器來(lái)限制上傳文件的大小,除了臨時(shí)路徑的位置,其他的構(gòu)造器可以接受的參數(shù)如下:

上傳文件的最大容量(以字節(jié)為單位)。默認(rèn)是沒(méi)有限制的

整個(gè)multipart請(qǐng)求的容量。不會(huì)關(guān)心有多少個(gè)part以及每個(gè)part的大小。默認(rèn)是沒(méi)有限制的。

在上傳的過(guò)程中,如果文件大小達(dá)到了一個(gè)指定最大容量,將會(huì)寫入到臨時(shí)文件路徑中,默認(rèn)值為0,也就是所有上傳的文件都會(huì)寫入磁盤上。

例如,假設(shè)我們想要限制文件的大小不超過(guò)2MB,整個(gè)請(qǐng)求不超過(guò)4MB,而且所有的文件都要寫入磁盤,

@Override
protected void customizeRegistration(Dynamic registration) {
    registration.setMultipartConfig(
            new MultipartConfigElement("C:Tempuploads",2097152, 4194304, 0));
}

如果使用更為傳統(tǒng)的web.xml來(lái)配置MultipartConfigResolver的話,那么可以使用中的元素


  appServlet
  org.springframework.web.servlet.DispatcherServlet
  1
  
    C:Tempuploads
    2097152
    4194304 
  

配置Jakarta Commons FileUpload Multipart解析器

Spring內(nèi)置了CommonsMultipartResolver,可以作為StandardServletMultipartResolver的替代方案。

7.2.2 處理multipart請(qǐng)求。

已經(jīng)配置好multipart請(qǐng)求的處理器,那么接下來(lái)我們就編寫控制器方法來(lái)接收上傳的文件。要實(shí)現(xiàn)這一點(diǎn),最常見(jiàn)的方法就是在某個(gè)控制器方法參數(shù)上添加@RequestPart注解。

:

標(biāo)簽現(xiàn)在將enctype屬性設(shè)置為multipart/form-data,這會(huì)告訴瀏覽器以multipart數(shù)據(jù)的形式提交表單,而不是以表單數(shù)據(jù)的形式進(jìn)行提交。還添加了一個(gè)新的< input>域其type為file。 accept屬性用來(lái)將文件類型限制為jpeg,png,gif格式的。根據(jù)name屬性,圖片數(shù)據(jù)將會(huì)發(fā)送到multipart請(qǐng)求中的profilePicture之中。

現(xiàn)在我們需要修改processRegistration()方法,使其能夠接受上傳的圖片。其中一種方式就是添加btye數(shù)組,并為其添加@RequestPart注解。

@RequestMapping(value="/register", method=POST)
public String processRegistration(
    @RequestPart(value = "profilePictures") byte[] profilePicture,
    @Valid Spitter spitter,
    Errors errors) {

當(dāng)表單提交的時(shí)候,profilePicture屬性將會(huì)給定一個(gè)byte數(shù)組,這個(gè)數(shù)組中包含了請(qǐng)求中對(duì)應(yīng)的part的數(shù)據(jù)(通過(guò)@RequestPart指定的)。如果沒(méi)有選擇文件,那么這個(gè)數(shù)據(jù)為空(而不是null),獲取到圖片數(shù)據(jù)后,processRegistration()方法剩下的任務(wù)就是將文件保存到某個(gè)地方。

接受MultipartFile

使用上傳文件的原始byte比較簡(jiǎn)單,但是功能有限。因此,Spring提供了MultipartFile接口,它為處理multipart數(shù)據(jù)提供了內(nèi)容更為豐富的對(duì)象。

package org.springframework.web.multipart;
/**
 * A representation of an uploaded file received in a multipart request.
 * @author Juergen Hoeller
 * @author Trevor D. Cook
 */
public interface MultipartFile {
    /**
     * Return the name of the parameter in the multipart form.
     * @return the name of the parameter (never {@code null} or empty)
     */
    String getName();
    /**
     * Return the original filename in the client"s filesystem.
     */
    String getOriginalFilename();
    /**
     * Return the content type of the file.
     */
    String getContentType();
    /**
     * Return whether the uploaded file is empty, that is, either no file has
     * been chosen in the multipart form or the chosen file has no content.
     */
    boolean isEmpty();
    /**
     * Return the size of the file in bytes.
     */
    long getSize();
    /**
     * Return the contents of the file as an array of bytes.
     */
    byte[] getBytes() throws IOException;
    /**
     * Return an InputStream to read the contents of the file from.
     */
    InputStream getInputStream() throws IOException;
    /**
     * Transfer the received file to the given destination file.
     */
    void transferTo(File dest) throws IOException, IllegalStateException;
}

可以看到,MultipartFile提供了獲取文件上傳文件byte的方式,還能獲取原始的文件名,大小以及內(nèi)容類型、還提供了一個(gè)InputStream用來(lái)將文件數(shù)據(jù)以流的方式進(jìn)行讀取。

除此之外,還提供了一個(gè)transferTo()方法,它能夠幫助我們將上傳文件寫入到文件系統(tǒng)中。作為樣例,我們?cè)诳梢栽?b>processRegistration()方法中添加如下的幾行代碼,從而將上傳的圖片文件寫入到文件系統(tǒng)中

profilePicture.transferTo(
        new File("date/spittr" + profilePicture.getOriginalFilename()));

將文件保存到本地文件系統(tǒng)中是非常簡(jiǎn)單的,但是這需要我們對(duì)這些文件進(jìn)行管理。我們需要確保有足夠的空間,確保當(dāng)出現(xiàn)硬件故障時(shí),文件進(jìn)行了備份,還需要在集群的多個(gè)服務(wù)器之間處理這些圖片文件的同步。

以Part的形式接受上傳的文件

Spring MVC接受javax.servlet.http.Part作為控制器方法的參數(shù),如果使用part來(lái)替換MultiFile的話,那么processRegistration()方法簽名會(huì)變成如下的形式。

@RequestMapping(value="/register", method=POST)
public String processRegistration(
    @RequestPart(value="profilePictures", required=false) Part fileBytes,
    RedirectAttributes redirectAttributes,
    @Valid Spitter spitter,
    Errors errors) throws IOException {
  if (errors.hasErrors()) {
    return "registerForm";
  }

Part接口

package javax.servlet.http;
public interface Part {
  public InputStream getInputStream() throws IOException;

  public String getContentType();

  public String getName();

  public String getSubmittedFileName();

  public long getSize();

  public void write(String fileName) throws IOException;

  public void delete() throws IOException;

  public String getHeader(String name);

  public Collection getHeaders(String name);

  public Collection getHeaderNames();
}

很多情況下,Part方法的名稱與MultiPartFile方法的名稱是完全相同的。有一些比較類似,但是稍有差別。
比如getSubmittedFileName()方法對(duì)應(yīng)getOriginalFilename().類似的,write()方法對(duì)應(yīng)于transfer()方法,借助該方法我們能夠?qū)⑸蟼鞯奈募懭胛募到y(tǒng)中。

值得一提的是,如果沒(méi)有在編寫控制器方法的時(shí)候,通過(guò)Part參數(shù)的形式接受文件上傳,那就沒(méi)必要配置MultipartResolver了。只有使用MultipartFile的時(shí)候 ,我們才需要MultipartResolver.

7.3 處理異常

Spring提供了多種方式將異常轉(zhuǎn)換為響應(yīng)

特定的Spring異常將會(huì)自動(dòng)映射為指定的HTTP狀態(tài)碼

異常上可以添加@RequestStatus注解,從而將其映射為某一個(gè)HTTP狀態(tài)

在方法上添加@ExceptionHandle注解,使其用來(lái)處理異常。

處理異常最簡(jiǎn)單的方式就是將其映射到HTTP狀態(tài)碼上。

7.3.1 將異常映射 為HTTP狀態(tài)碼

異常一般由Spring自身拋出,作為DispatcherServlet處理過(guò)程中或執(zhí)行校驗(yàn)時(shí)出現(xiàn)問(wèn)題的結(jié)果。

Spring提供了一種機(jī)制,能夠通過(guò)使用@RequestStatus注解將其映射為HTTP狀態(tài)碼

@RequestMapping(value="/{spittleId}", method=RequestMethod.GET)
public String spittle(
    @PathVariable("spittleId") long spittleId,
    Model model) {
  Spittle spittle = spittleRepository.findOne(spittleId);
  if (spittle == null) {
    throw new SpittleNotFoundException();     //這里會(huì)拋出異常
  }
  model.addAttribute(spittle);
  return "spittle";
}

如果資源沒(méi)有找到的話,HTTP狀態(tài)碼404是最為精確的響應(yīng)狀態(tài)碼

@ResponseStatus(value=HttpStatus.NOT_FOUND, reason="Spittle Not Found")
public class SpittleNotFoundException extends RuntimeException {
}
7.3.2 編寫異常處理方法

如果響應(yīng)中不僅包含狀態(tài)碼,還要包含所產(chǎn)生的錯(cuò)誤信息,需要按照請(qǐng)求的方式來(lái)處理異常。

@RequestMapping(method=RequestMethod.POST)
public String saveSpittle(SpittleForm form, Model model) {
  try {
    spittleRepository.save(new Spittle(null, form.getMessage(), new Date(),
        form.getLongitude(), form.getLatitude()));
    return "redirect:/spittles";
  } catch (DuplicateSpittleException e) {     //捕獲異常
    return "error/duplicate";
  }
}
@RequestMapping(method=RequestMethod.POST)
public String saveSpittle(SpittleForm form, Model model) {
    spittleRepository.save(new Spittle(null, form.getMessage(), new Date(),
        form.getLongitude(), form.getLatitude()));
    return "redirect:/spittles";
    return "error/duplicate";
}

它只關(guān)注成功保存Spittle的情況,所以只需要一個(gè)執(zhí)行路徑,很容易理解和測(cè)試。

@ExceptionHandler(DuplicateSpittleException.class)
public String handleNotFound() {
  return "error/duplicate";
}

方法上加上@ExceptionHandler注解后,當(dāng)方法拋出異常的時(shí)候,將委托該方法來(lái)處理,它能夠處理同一個(gè)控制器中所有的方法拋出的異常。

7.4 為控制器添加通知

如果控制器類的特定切面能夠 運(yùn)用到整個(gè)應(yīng)用程序的所有控制器中,那么這將會(huì)便利很多。,為了 避免重復(fù),我們會(huì)創(chuàng)建一個(gè)基礎(chǔ)的控制器,所有的控制器類要擴(kuò)展這個(gè)類,從而繼承通用的@ExceptionHandler方法。

Spring3.2 引入了一個(gè)新的解決方法:控制器通知。控制器通知(controllerAdvice)是任意帶有@ControllerAdvice注解的類,這個(gè)類會(huì)包含一個(gè)或多個(gè) 如下類型的方法:

@ExceptionHandle注解標(biāo)注的方法

@InitBinder注解標(biāo)注的方法

@ModelAttribute注解標(biāo)注的方法。

@ControllerAdvice
public class AppWideExceptionHandler {

  @ExceptionHandler(DuplicateSpittleException.class)
  public String handleNotFound() {
    return "error/duplicate";
  }

}
7.5 跨重定向請(qǐng)求傳遞數(shù)據(jù)

“redirect:”前綴能讓重定向功能變得更簡(jiǎn)單,但是,請(qǐng)稍等,Spirng為重定向功能還提供了一些其他的輔助功能。

當(dāng)一個(gè)處理器方法完成之后,該方法所指定的模型數(shù)據(jù)會(huì)將復(fù)制到請(qǐng)求中,并作為請(qǐng)求中的屬性,請(qǐng)求會(huì)轉(zhuǎn)發(fā)(forward)到視圖上進(jìn)行渲染。

對(duì)于 重定向來(lái)說(shuō),模型并不能徹底數(shù)據(jù),有一些其他方法,能夠從發(fā)起重定向的方法傳遞數(shù)據(jù)給處理重定向的方法

使用URL模板以路徑變量和/或查詢參數(shù)的形式傳遞數(shù)據(jù)

通過(guò)flash屬性發(fā)生數(shù)據(jù)

7.5.1 通過(guò)URL模板進(jìn)行重定向
@RequestMapping(value="/register", method=POST)
public String processRegistration(
        @Valid SpitterForm spitterForm,
        Errors errors) throws IllegalStateException, IOException {

    if (errors.hasErrors()) {
        return "registerForm";
    }
    Spitter spitter = spitterForm.toSpitter();
    spitterRepository.save(spitter);
    MultipartFile profilePicture = spitterForm.getProfilePicture();
    profilePicture.transferTo(new File("/tmp/spittr/" + spitter.getUsername() + ".jpg"));
    return "redirect:/spitter/" + spitter.getUsername();    //根據(jù)名字重定向
}

通過(guò)路徑變量和查詢參數(shù)的形式跨重定向傳遞數(shù)據(jù)是很簡(jiǎn)單直接的方式,但是也有限制它只能發(fā)送簡(jiǎn)單的值,如String和數(shù)字的值。在URl中,并沒(méi)有 辦法發(fā)送更為復(fù)雜的值,但這正是flash屬性能夠提供幫助。

### 7.5.2 使用flash屬性。

有個(gè)方案是將Spittr放到會(huì)話中,會(huì)話能長(zhǎng)期存在,并且會(huì)話能夠跨多個(gè)請(qǐng)求,所以我們可以在重定向之前將Spittr放到會(huì)話中,并在重定向后,從會(huì)話中取出 ,當(dāng)然,我們需要負(fù)責(zé)在重定向之后在會(huì)話中將其清理掉。

Spring提供了將數(shù)據(jù)發(fā)送為flash屬性的功能,按照定義,flash屬性會(huì)一直攜帶這些數(shù)據(jù),直到下一次請(qǐng)求,然后才消失

Spring提供了通過(guò)RedirectAttributes設(shè)置flash屬性的方式,這是Spring3.1引入的Modwl的一個(gè)子接口 。 RedirectAttributes提供了Model的所有功能。除此之外,還有幾個(gè)方法用來(lái)設(shè)置flash屬性。

public String processRegistration(
   @RequestPart(value="profilePictures", required=false) Part fileBytes,
   RedirectAttributes redirectAttributes,
   @Valid Spitter spitter,
   Errors errors) throws IOException {
 if (errors.hasErrors()) {
   return "registerForm";
 }

 spitterRepository.save(spitter);
 redirectAttributes.addAttribute("username", spitter.getUsername());
   //調(diào)用方法,將spitter作為ket,Spitter作為值。也可以不設(shè)置值,根據(jù)值得類型自行判斷。
 redirectAttributes.addFlashAttribute(spitter);
 return "redirect:/spitter/" + spitter.getUsername();

在重定向之前,所有的flash屬性都會(huì)復(fù)制到會(huì)話中,在重定向結(jié)束后,存在會(huì)話中的 flash屬性會(huì)被取出,并從會(huì)話中轉(zhuǎn)移到模型之中。

@RequestMapping(value="/{username}", method=GET)
public String showSpitterProfile(
        @PathVariable String username, Model model) {
  if (!model.containsAttribute("spitter")) {
    model.addAttribute(
        spitterRepository.findByUsername(username));
  }
  return "profile";
}

showSpitterProfile()方法首先檢查是否存在key為sptter的modle屬性。如果模型中包含的話,那就什么都不用做了。包含的Spitter對(duì)象將會(huì)傳遞到視圖中進(jìn)行渲染。如果不包含則從spitterRepository中查找Spitter,并將其放到模型中。

7.6 小節(jié)(最喜歡這里)

在Spirng中,總是會(huì)有“還沒(méi)有結(jié)束”的感覺(jué)更多的特性,更多的選擇,以及實(shí)現(xiàn)開(kāi)發(fā)目標(biāo)的更多方式。Spring MVC有很多功能和技巧。

當(dāng)然,Spirng MVC的環(huán)境搭建是由多種可選方案的一個(gè)領(lǐng)域。在本章中,我們首先看來(lái)一下搭建Spring MVC中DispatcherServletContextLoaderListener的多種方式。還看到了如何調(diào)整DispatcherServlet的注冊(cè)功能以及如何注冊(cè)自定義的Servlet和FIlterr。如果你需要將應(yīng)用部署到更老的服務(wù)器上,我們還快速了解了如何使用web.xml聲明DispatcherServletContextLoaderListener.

然后我們了解 如何處理Spirng MVC控制器所拋出的異常,盡管帶有@Requestmapping注解的方法可以在自身的代碼中處理異常,但是如果將異常處理的代碼抽取到多帶帶的方法中,那么控制器的代碼會(huì)整潔很多。

為了采用一致的方式處理通用的任務(wù),包括在應(yīng)用中的所有控制器 中處理異常,Spirng 3.2 引入了@ControllerAdvice,他所創(chuàng)建的類能夠?qū)⒖刂破鞯耐ㄓ眯袨槌槿〉酵粋€(gè)方法。

最后,我們看了下如何跨重定向傳遞數(shù)據(jù),包括Spring對(duì)flash屬性的支持:類似于模板,但是能在重定向后存活下來(lái)。這樣的話,就能采用非常恰當(dāng)?shù)姆绞綖镻OST請(qǐng)求執(zhí)行一個(gè)重定向回應(yīng)。而且能夠?qū)⑻幚鞵OST請(qǐng)求時(shí)的模型數(shù)據(jù)傳遞過(guò)來(lái),然后再重定向后使用或展現(xiàn)這些模型數(shù)據(jù)。

如果你有疑惑的話,那么可以告訴你,這就是我所說(shuō)的“更多的功能”,其實(shí),我們并沒(méi)有討論到Spirng MVC 的每個(gè)方面。我們將會(huì)在16章中重新討論 Spirng MVC,到時(shí)你會(huì)看到如何使用它來(lái)創(chuàng)建REST API。

但現(xiàn)在,我們將會(huì)暫時(shí)放下Spring MVC,看一下Spirng web Flow,這是一個(gè)構(gòu)建在Spirng MVC 之上的流程框架,它能夠引導(dǎo)用戶執(zhí)行一系列向?qū)Р襟E。

納悶,你忘記總結(jié)文件上傳了。期待下一章。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/68576.html

相關(guān)文章

  • Spring之旅第十二站:Spring Security 數(shù)據(jù)存儲(chǔ)、攔截請(qǐng)求 、認(rèn)證用戶、*、

    摘要:?jiǎn)⒂冒踩赃@個(gè)簡(jiǎn)單的默認(rèn)配置指定了如何保護(hù)請(qǐng)求,以及客戶端認(rèn)證用戶的方案。基于數(shù)據(jù)庫(kù)進(jìn)行認(rèn)證用戶數(shù)據(jù)通常會(huì)存儲(chǔ)在關(guān)系型數(shù)據(jù)庫(kù)中,并通過(guò)進(jìn)行訪問(wèn)。必須經(jīng)過(guò)認(rèn)證其他所有請(qǐng)求都是允許的,不需要認(rèn)證。要求用戶不僅需要認(rèn)證,還要具備權(quán)限。 Spring Security Spring Security 是基于Spring 應(yīng)用程序提供的聲明式安全保護(hù)的安全框架。Spring Sercurity ...

    YuboonaZhang 評(píng)論0 收藏0
  • Spring之旅第八站:Spring MVC Spittr舞臺(tái)的搭建、基本的制器請(qǐng)求的輸入、表

    摘要:請(qǐng)求旅程的第一站是的。的任務(wù)是將請(qǐng)求發(fā)送控制器控制器是一個(gè)用于處理請(qǐng)求的組件。處理映射器根據(jù)請(qǐng)求攜帶的信息來(lái)進(jìn)行決策。這樣的結(jié)果就是,只能找到顯示聲明在配置類中的控制器。 構(gòu)建Spring Web應(yīng)用 說(shuō)明 如果你有幸能看到。 1、本文參考了《Spring 實(shí)戰(zhàn)》重點(diǎn)內(nèi)容,參考了GitHub上的代碼 2、本文只為記錄作為以后參考,要想真正領(lǐng)悟Spring的強(qiáng)大,請(qǐng)看原書。 3、在一次...

    maybe_009 評(píng)論0 收藏0
  • 超實(shí)用百道Java面試題

    摘要:是的簡(jiǎn)稱,運(yùn)行環(huán)境,為的運(yùn)行提供了所需的環(huán)境。分割字符串,返回分割后的字符串?dāng)?shù)組。當(dāng)計(jì)算的值相同時(shí),我們稱之為沖突,的做法是用鏈表和紅黑樹存儲(chǔ)相同的值的。迭代器取代了集合框架中的,迭代器允許調(diào)用者在迭代過(guò)程中移除元素。 Java基礎(chǔ)1.JDK和JRE有什么區(qū)別? JDK 是java development kit的簡(jiǎn)稱,java開(kāi)發(fā)工具包,提供java的開(kāi)發(fā)環(huán)境和運(yùn)行環(huán)境。JRE 是j...

    MkkHou 評(píng)論0 收藏0
  • 通過(guò)項(xiàng)目逐步深入了解Spring MVC(一)

    摘要:是一個(gè)基于的框架。控制器將視圖響應(yīng)給用戶通過(guò)視圖展示給用戶要的數(shù)據(jù)或處理結(jié)果。有了減少了其它組件之間的耦合度。 相關(guān)閱讀: 本文檔和項(xiàng)目代碼地址:https://github.com/zhisheng17/springmvc 轉(zhuǎn)載請(qǐng)注明出處和保留以上文字! 了解 Spring: Spring 官網(wǎng):http://spring.io/ 一個(gè)好的東西一般都會(huì)有一個(gè)好的文檔解釋說(shuō)明,如果你...

    whataa 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<