spring mvc 3.2 使用總結

用spring mvc有一段時間了,今天有時間對這個框架的一些使用進行一些總結。
官網上面對spring mvc有一個很詳細的demo,地址:
就拿這個例子做爲總結的代碼。
1.首先介紹一下WebApplicationInitializer,能夠經過下面的代碼來實現對spring servlet的配置
public class MyWebApplicationInitializer implements WebApplicationInitializer {
    @Override
    public void onStartup(ServletContext container) {
        ServletRegistration.Dynamic registration = container.addServlet("dispatcher", new DispatcherServlet());
        registration.setLoadOnStartup(1);
        registration.addMapping("/example/*");
    }
}
上面的代碼功能等價於
<web-app>
    <servlet>
        <servlet-name>example</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>example</servlet-name>
        <url-pattern>/example/*</url-pattern>
    </servlet-mapping>
</web-app>
2.定義一個controller
@Controller
public class SimpleController {
 
    @RequestMapping("/simple")
    public @ResponseBody String simple() {
        return "Hello world!";
    }
 
}
這樣就完成了一個controller,@RequestMapping( "/simple")定義訪問的url,其中可使用一個參數「method」, 取值能夠是RequestMethod.POST,RequestMethod.GET, RequestMethod.DEL等,用來限定訪問的方法
 
3.使用hibernate validation做爲驗證
定義一個JavaBean:
public class JavaBean {
 
    @NotNull
    @Max(5)
    private Integer number;
 
    @NotNull
    @Future
    @DateTimeFormat(iso=ISO.DATE)
    private Date date;
 
    public Integer getNumber() {
        return number;
    }
 
    public void setNumber(Integer number) {
        this.number = number;
    }
 
    public Date getDate() {
        return date;
    }
 
    public void setDate(Date date) {
        this.date = date;
    }
 
}
定義一個controller:
@Controller
public class ValidationController {
 
    // enforcement of constraints on the JavaBean arg require a JSR-303 provider on the classpath
 
    @RequestMapping("/validate")
    public @ResponseBody String validate(@Valid JavaBean bean, BindingResult result) {
        if (result.hasErrors()) {
            return "Object has validation errors";
        } else {
            return "No errors";
        }
    }
 
}
@Valid說明須要對JavaBean這個參數進行驗證,驗證的規則由hibernate的validation限定,裏面有最基本的@NotNull,@Max,@Min,@reg等等,強大的驗證規則。其中BindingResult會返回驗證的信息。
 
4.定義返回值類型:
@Controller
public class MappingController {
 
    @RequestMapping("/mapping/path")
    public @ResponseBody String byPath() {
        return "Mapped by path!";//最簡單的,只定義了request的url
    }
 
    @RequestMapping(value="/mapping/path/*", method=RequestMethod.GET)
    public @ResponseBody String byPathPattern(HttpServletRequest request) {//拿到的HttpServletRequest基本上什麼均可以作到了
        return "Mapped by path pattern ('" + request.getRequestURI() + "')";
    }
 
    @RequestMapping(value="/mapping/method", method=RequestMethod.GET)
    public @ResponseBody String byMethod() {
        return "Mapped by path + method";
    }
 
    @RequestMapping(value="/mapping/parameter", method=RequestMethod.GET, params="foo")
    public @ResponseBody String byParameter() {
        return "Mapped by path + method + presence of query parameter!";//定義了必須符合url+方法+參數三個規則的請求才能夠被捕捉
    }
 
    @RequestMapping(value="/mapping/parameter", method=RequestMethod.GET, params="!foo")
    public @ResponseBody String byParameterNegation() {
        return "Mapped by path + method + not presence of query parameter!";//params="!foo",不能有foo這個參數的url+方法的請求
    }
 
    @RequestMapping(value="/mapping/header", method=RequestMethod.GET, headers="FooHeader=foo")
    public @ResponseBody String byHeader() {
        return "Mapped by path + method + presence of header!";//附加header的規則
    }
 
    @RequestMapping(value="/mapping/header", method=RequestMethod.GET, headers="!FooHeader")
    public @ResponseBody String byHeaderNegation() {
        return "Mapped by path + method + absence of header!";//沒有FooHeader的headers
    }
 
    @RequestMapping(value="/mapping/consumes", method=RequestMethod.POST, consumes=MediaType.APPLICATION_JSON_VALUE)
    public @ResponseBody String byConsumes(@RequestBody JavaBean javaBean) {
        return "Mapped by path + method + consumable media type (javaBean '" + javaBean + "')";//這個在後面的convert再說
    }
 
    @RequestMapping(value="/mapping/produces", method=RequestMethod.GET, produces=MediaType.APPLICATION_JSON_VALUE)
    public @ResponseBody JavaBean byProducesJson() {//返回JavaBean的json數據
        return new JavaBean();
    }
 
    @RequestMapping(value="/mapping/produces", method=RequestMethod.GET, produces=MediaType.APPLICATION_XML_VALUE)
    public @ResponseBody JavaBean byProducesXml() {//返回JavaBean的xml數據
        return new JavaBean();
    }
}
5.請求參數的處理
@Controller
@RequestMapping("/data")
public class RequestDataController {
 
    @RequestMapping(value="param", method=RequestMethod.GET)
    public @ResponseBody String withParam(@RequestParam String foo) {
        return "Obtained 'foo' query parameter value '" + foo + "'";//RequestParam ,得到一個foo的參數,還能夠指定參數的名字,例以下面的的
    }
 
    @RequestMapping(value="group", method=RequestMethod.GET)
    public @ResponseBody String withParamGroup(JavaBean bean) {
        return "Obtained parameter group " + bean;
    }
 
    @RequestMapping(value="path/{var}", method=RequestMethod.GET)
    public @ResponseBody String withPathVariable(@PathVariable String var) {//使用@PathVariable ,參數須要在url中出現例如  xxx/path/hello
        return "Obtained 'var' path variable value '" + var + "'";// "hello"這個參數就會被獲取到
    }
 
    @RequestMapping(value="{path}/simple", method=RequestMethod.GET)// url=/pets;foo=11/simple
    public @ResponseBody String withMatrixVariable(@PathVariable String path, @MatrixVariable String foo) {
        //path=pets; foo=11
        return "Obtained matrix variable 'foo=" + foo + "' from path segment '" + path + "'";
    }
 
    @RequestMapping(value="{path1}/{path2}", method=RequestMethod.GET)// url = /42;foo1=11/21;foo2=22
    public @ResponseBody String withMatrixVariablesMultiple (
            @PathVariable String path1, @MatrixVariable(value="foo", pathVar="path1") String foo1,
            @PathVariable String path2, @MatrixVariable(value="foo", pathVar="path2") String foo2) {//相似上面的,分塊分解參數
 
        return "Obtained matrix variable foo=" + foo1 + " from path segment '" + path1
                + "' and variable 'foo=" + foo2 + " from path segment '" + path2 + "'";
    }
    
@RequestMapping("/owners/{ownerId}")// 例如url:/owners/42/pets/21.
public class RelativePathUriTemplateController {
  @RequestMapping("/pets/{petId}")
  public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {
    // implementation omitted
  }
}
 
// GET /owners/42;q=11/pets/21;q=22
@RequestMapping(value = "/owners/{ownerId}/pets/{petId}", method = RequestMethod.GET)
public void findPet(
    @MatrixVariable(value="q", pathVar="ownerId") int q1,
    @MatrixVariable(value="q", pathVar="petId") int q2) {
  // q1 == 11
  // q2 == 22
}
 
// GET /owners/42;q=11;r=12/pets/21;q=22;s=23
@RequestMapping(value = "/owners/{ownerId}/pets/{petId}", method = RequestMethod.GET)//@MatrixVariable 容許組合全部參數成爲一個
  public void findPet(
        @MatrixVariable Map < String, String > matrixVars,
        @MatrixVariable(pathVar = "petId" ) Map<String, String> petMatrixVars) {
    // matrixVars: [" q " : [11,22], " r " : 12, " s " : 23]
    // petMatrixVars: [" q " : 11, " s " : 23]
 }
/*
Host                    localhost:8080
Accept                  text/html,application/xhtml+xml,application/xml;q=0.9
Accept-Language         fr,en-gb;q=0.7,en;q=0.3
Accept-Encoding         gzip,deflate
Accept-Charset          ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive              300
*/
    @RequestMapping(value="header", method=RequestMethod.GET)
    public @ResponseBody String withHeader(@RequestHeader String Accept) {//@RequestHeader 能夠指定你想或者header中的哪一個屬性的信息
        return "Obtained 'Accept' header '" + Accept + "'";//例如@RequestHeader("Keep-Alive") 得到 300 
    }
 
    // cookie中有一個值openid_provider=415A4AC178C59DACE0B2C9CA727CDD84 ,也能夠指定變量名withCookie(@CookieValue("openid_provider") param);
    @RequestMapping(value="cookie", method=RequestMethod.GET)
    public @ResponseBody String withCookie(@CookieValue String openid_provider) {
        return "Obtained 'openid_provider' cookie '" + openid_provider + "'";
    }
 
/**
*響應流媒體,通常是xml和json數據,可使用consumes="application/json"指定接受的是json仍是xml
*spring能夠把POST的數據轉換成爲一個bean
*例若有個class JavaBean implements Serializable {
*                private Interger id;
*                private Stirng name;
*                private String status;
*                public JavaBean (){
*
*                }
*            }
*    @RequestMapping(value="body", method=RequestMethod.POST)
*    public @ResponseBody String withBody(@RequestBody JavaBean bean) {//響應流媒體
*        return "Posted request body '" + bean + "'";
*    }
*    $.post("/body",{'id':1, 'name': 'people', 'status': 'yes'},function(result){
*        alert(result);
*    });
*    spring 會把post過來的數據組成一個bean,這種方式儘可能少用
*/
    @RequestMapping(value="body", method=RequestMethod.POST)
    public @ResponseBody String withBody(@RequestBody String body) {//響應流媒體
        return "Posted request body '" + body + "'";
    }
 
    @RequestMapping(value="entity", method=RequestMethod.POST)
    public @ResponseBody String withEntity(HttpEntity<String> entity) {
        return "Posted request body '" + entity.getBody() + "'; headers = " + entity.getHeaders();
    }//這個就牛b了,把整個http請求的數據都給你了,有HttpEntity來傳遞請求數據固然有一個返回應答的數據流類
    
@RequestMapping("/something")
public ResponseEntity<String> handle(HttpEntity<byte[]> requestEntity) throws
UnsupportedEncodingException {
  String requestHeader = requestEntity.getHeaders().getFirst("MyRequestHeader"));
  byte[] requestBody = requestEntity.getBody();
  // do something with request header and body
  HttpHeaders responseHeaders = new HttpHeaders();
  responseHeaders.set("MyResponseHeader", "MyValue");//設置好header後和body-〉hello world組成ResponseEntity返回
  return new ResponseEntity<String>("Hello World", responseHeaders, HttpStatus.CREATED);
}
    /**
    *@RequestBody @ResponseBody分別是HttpEntity和ResponseEntity的去掉header的body部分
    */
 
}
在這裏還有一種參數的形式@ModelAttribute,@ModelAttribute的定義有兩種,一種是定義在方法上,另外一種是定義在參數裏,當這個annotation定義在方法上,表示controller返回的是一個JavaBean,當annotation定義在參數裏,表示post過來的數據會被轉換成爲JavaBean。
首先定義一個JavaBean的class:
import java.io.Serializable;
 
public class Person implements Serializable {
 
    private static final long serialVersionUID = -8333984959652704635L;
 
    private Integer id;
    private String firstName;
    private String lastName;
    private String currency;
    private Double money;
 
  ......getter/setter
 
}
有一個controller:
@Controller
@RequestMapping("EDIT")
public class PetSitesEditController {
 @ModelAttribute("people")
    public Person getPerson() {
        return this.person ;
    }//對於這個這個controller來講,其餘的方法的返回的jsp頁面裏面都會有一個people屬性被返回,由於@ModelAttribute註解的方法會在這個controller的其餘方法調用前被調用
}
在jsp頁面中能夠訪問${ people}這個屬性,若是在 @ModelAttribute沒有指定屬性的名字,那麼默認就是person
看下面
有一個jsp頁面
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
 
<h1>Edit Person</h1>
 
<c:url var="saveUrl" value="/main/edit/${personAttribute.id}" />
 
<form:form modelAttribute="personAttribute" method="POST" action="${saveUrl}">
    <table>
        <tr>
            <td><form:label path="id">Id:</form:label></td>
            <td><form:input path="id" disabled="true"/></td>
        </tr>
 
        <tr>
            <td><form:label path="firstName">First Name:</form:label></td>
            <td><form:input path="firstName"/></td>
        </tr>
 
        <tr>
            <td><form:label path="lastName">Last Name</form:label></td>
            <td><form:input path="lastName"/></td>
        </tr>
 
        <tr>
            <td><form:label path="money">Money</form:label></td>
            <td><form:input path="money"/></td>
        </tr>
 
        <tr>
            <td><form:label path="currency">Currency:</form:label></td>
            <td><form:select path="currency"  items="${currencies}"/></td>
        </tr>
    </table>
 
    <input type="submit" value="Save" />
</form:form>
 
</body>
</html>
效果
post過來的數據
personAttribute.id = 1, personAttribute. firstName = John....
@RequestMapping(value = "/edit/{id}", method = RequestMethod.POST)
    public String saveEdit(@ModelAttribute("personAttribute") Person person,
      @PathVariable Integer id) {
      //spring會把post過來的person信息組合成爲一個JavaBean,這裏還得到了id這個信息
}
controller代碼
根據@ModelAttribute兩種用法,能夠這樣子實現
@Controller
    public class PersonController { 
 
        @ModelAttribute("person") 
        public Person getPerson() { 
           return new Person();
        } 
 
        @RequestMapping(value = "/new") 
        public String add(@ModelAttribute("person") Person person) { 
           return "add person";
        }
   }
/*
* 訪問url  /new
* 首先會執行getPerson的方法,而後再執行add方法,其中person這個bean已經被new出來了,因此在add方法中能夠被得到,這個有點像下面要說的convert,可是功能要稍微弱一些。
*/
6.convert,這是spring mvc最令我佩服的地方
首先定義一個convert
public class AccountConverter implements Converter<String, Account> {
 
    private AccountManager accountManager;
 
    @Autowired
    public AccountConverter(AccountManager accountManager) {//ioc一個accoutManager,用來根據id查出accout
        this.accountManager = accountManager;
    }
 
    @Override
    public Account convert(String id) {
        return this.accountManager.getAccount(id);
    }
 
}
下面一個controller:
@Controller
@RequestMapping("/accounts")
public class AccountController {

    @RequestMapping(value="/{account}/edit", method = RequestMethod.GET)
    public String edit(@PathVariable Account account) {
        //操做accout類
        return "accounts/edit";
    }
}
下面描述了convert的運做過程
7.redirect,重點用法在return中
@Controller
@RequestMapping("/redirect")
public class RedirectController {
 
    private final ConversionService conversionService;
 
    @Inject
    public RedirectController(ConversionService conversionService) {
        this.conversionService = conversionService;
    }
 
    @RequestMapping(value="/uriTemplate", method=RequestMethod.GET)
    public String uriTemplate(RedirectAttributes redirectAttrs) {
        redirectAttrs.addAttribute("account", "a123");  // Used as URI template variable
        redirectAttrs.addAttribute("date", new LocalDate(2011, 12, 31));  // Appended as a query parameter
        return "redirect:/redirect/{account}";
    }
 
    @RequestMapping(value="/uriComponentsBuilder", method=RequestMethod.GET)
    public String uriComponentsBuilder() {
        String date = this.conversionService.convert(new LocalDate(2011, 12, 31), String.class);
        UriComponents redirectUri = UriComponentsBuilder.fromPath("/redirect/{account}").queryParam("date", date)
                .build().expand("a123").encode();
        return "redirect:" + redirectUri.toUriString();
    }
 
    @RequestMapping(value="/{account}", method=RequestMethod.GET)
    public String show(@PathVariable String account, @RequestParam(required=false) LocalDate date) {
        return "redirect/redirectResults";
    }
 
}
8.org.springframework.ui.Model,Model這個類中有一些css的配置,能夠容許咱們使用,有時可能會用到
@Controller
@RequestMapping("/views/*")
public class ViewsController {
 
    @RequestMapping(value="html", method=RequestMethod.GET)
    public String prepare(Model model) {
        model.addAttribute("foo", "bar");
        model.addAttribute("fruit", "apple");
        return "views/html";
    }
}
9.文件上傳、下載:
上傳代碼
@Controller
@RequestMapping("/fileupload")
public class FileUploadController {
 
    @ModelAttribute
    public void ajaxAttribute(WebRequest request, Model model) {
        model.addAttribute("ajaxRequest", AjaxUtils.isAjaxRequest(request));
    }
 
    @RequestMapping(method=RequestMethod.GET)
    public void fileUploadForm() {
    }
 
    @RequestMapping(method=RequestMethod.POST)
    public void processUpload(@RequestParam MultipartFile file, Model model) throws IOException {//MultipartFile能夠指定變量名@MultipartFile("file001") file
        //file.isEmpty(),file.getBytes();,file.getInputStream();
        model.addAttribute("message", "File '" + file.getOriginalFilename() + "' uploaded successfully");
    }
}

文件下載
@RequestMapping(value = "/files/{file_name}", method = RequestMethod.GET)
public void getFile(
    @PathVariable("file_name") String fileName,
    HttpServletResponse response) {
    try {
      // get your file as InputStream
      InputStream is = ...;
      // copy it to response's OutputStream
      IOUtils.copy(is, response.getOutputStream());
      response.flushBuffer();
    } catch (IOException ex) {
      log.info("Error writing file to output stream. Filename was '" + fileName + "'");
      throw new RuntimeException("IOError writing file to output stream");
    }
}//本人比較喜歡這個

@RequestMapping(value = "/files/{file_name}", method = RequestMethod.GET)
@ResponseBody
public FileSystemResource getFile(@PathVariable("file_name") String fileName) {
    return new FileSystemResource(myService.getFileFor(fileName));
}
10.ajax 部分,有關 Servlet 3 async processing feature:
 首先說一下Servlet 3 的一些特性, 一個普通 Servlet 的主要工做流程大體以下:首先,Servlet 接收到請求以後,可能須要對請求攜帶的數據進行一些預處理;接着,調用業務接口的某些方法,以完成業務處理;最後,根據處理的結果提交響應,Servlet 線程結束。其中第二步的業務處理一般是最耗時的,這主要體如今數據庫操做,以及其它的跨網絡調用等,在此過程當中,Servlet 線程一直處於阻塞狀態,直到業務方法執行完畢。在處理業務的過程當中,Servlet 資源一直被佔用而得不到釋放,對於併發較大的應用,這有可能形成性能的瓶頸。對此,在之前一般是採用私有解決方案來提早結束 Servlet 線程,並及時釋放資源
 
如今經過使用 Servlet 3.0 的異步處理支持,以前的 Servlet 處理流程能夠調整爲以下的過程:首先,Servlet 接收到請求以後,可能首先須要對請求攜帶的數據進行一些預處理;接着,Servlet 線程將請求轉交給一個異步線程來執行業務處理,線程自己返回至容器,此時 Servlet 尚未生成響應數據,異步線程處理完業務之後,能夠直接生成響應數據(異步線程擁有 ServletRequest 和 ServletResponse 對象的引用),或者將請求繼續轉發給其它 Servlet。如此一來, Servlet 線程再也不是一直處於阻塞狀態以等待業務邏輯的處理,而是啓動異步線程以後能夠當即返回。
一個簡單的demo
@WebServlet(urlPatterns = "/demo", asyncSupported = true)
public class AsyncDemoServlet extends HttpServlet {
    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse resp)
    throws IOException, ServletException {
        resp.setContentType("text/html;charset=UTF-8");
        PrintWriter out = resp.getWriter();
        out.println("開始時間:" + new Date() + ".");
        out.flush();
 
        //在子線程中執行業務調用,並由其負責輸出響應,主線程退出
        AsyncContext ctx = req.startAsync();
        new Thread(new Executor(ctx)).start();
 
        out.println("結束時間:" + new Date() + ".");
        out.flush();
    }
}
 
public class Executor implements Runnable {
    private AsyncContext ctx = null;
    public Executor(AsyncContext ctx){
        this.ctx = ctx;
    }
 
    public void run(){
        try {
            //等待十秒鐘,以模擬業務方法的執行
            Thread.sleep(10000);
            PrintWriter out = ctx.getResponse().getWriter();
            out.println("業務處理完畢的時間:" + new Date() + ".");
            out.flush();
            ctx.complete();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
輸出的結果:
開始時間:Thu Jul 27 09:49:30 CST 2013
開始時間:Thu Jul 27 09:49:30 CST 2013
業務處理完畢的時間: Thu Jul 27 09:49:40 CST 2013
 
下面是spring  mvc 3.2 對其的支持。對於spring mvc 裏面有三種方式的支持,分別是Callable,DeferredResult,WebAsyncTask
Callable:
@RequestMapping("/response-body")
    public @ResponseBody Callable<String> callable(final @RequestParam(required=false, defaultValue="true") boolean handled) {
         //進行一些與處理以後,把最耗時的業務邏輯部分放到Callable中,注意,若是你須要在new Callable中用到從頁面傳入的參數,須要在參數前加入final
        return new Callable<String>() {
            @Override
            public String call() throws Exception {
                if(handled){
                    Thread.sleep(2000);
                }else{
                    Thread.sleep(2000*2);
                }
                return "Callable result";
            }
        };
    }
WebAsyncTask:
(一)對於Callable來講會默認使用SimpleAsyncTaskExecutor類來執行,這個類很是簡單並且沒有重用線程。而在實際中,你將可能會須要使用AsyncTaskExecutor類來針對你所處的環境進行適當的配置。
(二)在servlet中timeout是一個很重要的問題,servlet容器會嘗試重用request和response對象,對於一個timeout可是實際上沒有結束的異步請求來講,使用同一個request和response對象影響將沒法估量。
WebAsyncTask中有一個setTimeout的選項,其中他的核心原理是callable
@RequestMapping("/custom-timeout-handling")
    public @ResponseBody WebAsyncTask<String> callableWithCustomTimeoutHandling() {
 
        Callable<String> callable = new Callable<String>() {
            @Override
            public String call() throws Exception {
                Thread.sleep(2000);
                return "Callable result";
            }
        };
 
        return new WebAsyncTask<String>(1000, callable);//容許指定timeout時間
    }
最後一個是DeferredResult<?> ,一個DeferredResult<?> 容許應用程序從一個線程中返回,而什麼時候返回則由線程決定
@Controller
@RequestMapping("/async")
public class DeferredResultController {
 
    private final Queue<DeferredResult<String>> responseBodyQueue = new ConcurrentLinkedQueue<DeferredResult<String>>();
 
    private final Queue<DeferredResult<ModelAndView>> mavQueue = new ConcurrentLinkedQueue<DeferredResult<ModelAndView>>();
 
    private final Queue<DeferredResult<String>> exceptionQueue = new ConcurrentLinkedQueue<DeferredResult<String>>();
 
 
    @RequestMapping("/deferred-result/response-body")
    public @ResponseBody DeferredResult<String> deferredResult() {
        DeferredResult<String> result = new DeferredResult<String>();
        this.responseBodyQueue.add(result);
        return result;
    }
 
    @RequestMapping("/deferred-result/model-and-view")
    public @ResponseBody DeferredResult<ModelAndView> deferredResultWithView() {
        DeferredResult<ModelAndView> result = new DeferredResult<ModelAndView>();
        this.mavQueue.add(result);
        return result;
    }
 
    @RequestMapping("/deferred-result/exception")
    public @ResponseBody DeferredResult<String> deferredResultWithException() {
        DeferredResult<String> result = new DeferredResult<String>();
        this.exceptionQueue.add(result);
        return result;
    }
     //上面三個分別接受了請求以後就return了
    // 這裏容許咱們在其餘的線程中處理數據,而且無需實時返回
    @RequestMapping("/deferred-result/timeout-value")
    public @ResponseBody DeferredResult<String> deferredResultWithTimeoutValue() {
 
        // Provide a default result in case of timeout and override the timeout value
        // set in src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml
 
        return new DeferredResult<String>(1000L, "Deferred result after timeout");
    }
     //建立一個計劃任務,每2秒處理一次
    @Scheduled(fixedRate=2000)
    public void processQueues() {
        for (DeferredResult<String> result : this.responseBodyQueue) {
            result.setResult("Deferred result");
            this.responseBodyQueue.remove(result);
        }
        for (DeferredResult<String> result : this.exceptionQueue) {
            result.setErrorResult(new IllegalStateException("DeferredResult error"));
            this.exceptionQueue.remove(result);
        }
        for (DeferredResult<ModelAndView> result : this.mavQueue) {
            result.setResult(new ModelAndView("views/html", "javaBean", new JavaBean("bar", "apple")));
            this.mavQueue.remove(result);
        }
    }
 
    @ExceptionHandler
    @ResponseBody
    public String handleException(IllegalStateException ex) {
        return "Handled exception: " + ex.getMessage();
    }
 
}

11. Interceptor,經過繼承HandlerInterceptor, 實現preHandle(..)方法來 定義一些列方法執行先後的動做
官方例子
<mvc:interceptors>
    <ref bean="officeHoursInterceptor"/>
</mvc:interceptors>
<bean id="officeHoursInterceptor"
          class="samples.TimeBasedAccessInterceptor">
        <property name="openingTime" value="9"/>
        <property name="closingTime" value="18"/>
</bean>
package samples;
public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter {
    private int openingTime;
    private int closingTime;
    public void setOpeningTime(int openingTime) {
        this.openingTime = openingTime;
    }
    public void setClosingTime(int closingTime) {
        this.closingTime = closingTime;
    }
    public boolean preHandle(
            HttpServletRequest request,
            HttpServletResponse response,
            Object handler) throws Exception {
        Calendar cal = Calendar.getInstance();
        int hour = cal.get(HOUR_OF_DAY);
        if (openingTime <= hour && hour < closingTime) {
            return true;
        } else {
            response.sendRedirect("http://host.com/outsideOfficeHours.html");
            return false;
        }
    }
}
HandlerInterceptorAdapter 裏面有不少方法,下面是api的部分文檔
 
 
那些pre,after和post開頭的方法基本能夠知足interceptor的各類須要
 
這裏基本結束了spring mvc 3.2的總結,在寫這個文章的前幾天spring已經出4.0了,看了一下,發現裏面開始有websocket的支持了。
 
相關文章
相關標籤/搜索