spring mvc

本文来自:http://my.oschina.net/541996928/blog/145897

用spring mvc有一段时间了,今天有时间对这个框架的一些使用进行一些总结。
官网上面对spring mvc有一个很详细的demo,地址:
就拿这个例子作为总结的代码。
1.首先介绍一下WebApplicationInitializer,可以通过下面的代码来实现对spring servlet的配置
public classMyWebApplicationInitializerimplementsWebApplicationInitializer {
    @Override
    publicvoidonStartup(ServletContext container) {
        ServletRegistration.Dynamic registration = container.addServlet("dispatcher",newDispatcherServlet());
        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 classSimpleController {
  
    @RequestMapping("/simple")
    public@ResponseBodyString simple() {
        return"Hello world!";
    }
  
}

这样就完成了一个controller,@RequestMapping( "/simple")定义访问的url,其中可以使用一个参数“method”, 取值可以是RequestMethod.POST,RequestMethod.GET, RequestMethod.DEL等,用来限定访问的方法

 
3.使用hibernate validation作为验证
定义一个JavaBean:
public classJavaBean {
  
    @NotNull
    @Max(5)
    privateInteger number;
  
    @NotNull
    @Future
    @DateTimeFormat(iso=ISO.DATE)
    privateDate date;
  
    publicInteger getNumber() {
        returnnumber;
    }
  
    publicvoidsetNumber(Integer number) {
        this.number = number;
    }
  
    publicDate getDate() {
        returndate;
    }
  
    publicvoidsetDate(Date date) {
        this.date = date;
    }
  
}
定义一个controller:
@Controller
public classValidationController {
  
    // enforcement of constraints on the JavaBean arg require a JSR-303 provider on the classpath
  
    @RequestMapping("/validate")
    public@ResponseBodyString validate(@ValidJavaBean 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.定义返回值类型:
01 
@Controller
public classMappingController {
  
    @RequestMapping("/mapping/path")
    public@ResponseBodyString byPath() {
        return"Mapped by path!";//最简单的,只定义了request的url
    }
  
    @RequestMapping(value="/mapping/path/*", method=RequestMethod.GET)
    public@ResponseBodyString byPathPattern(HttpServletRequest request) {//拿到的HttpServletRequest基本上什么都可以做到了
        return"Mapped by path pattern ('"+ request.getRequestURI() +"')";
    }
  
    @RequestMapping(value="/mapping/method", method=RequestMethod.GET)
    public@ResponseBodyString byMethod() {
        return"Mapped by path + method";
    }
  
    @RequestMapping(value="/mapping/parameter", method=RequestMethod.GET, params="foo")
    public@ResponseBodyString byParameter() {
        return"Mapped by path + method + presence of query parameter!";//定义了必须符合url+方法+参数三个规则的请求才可以被捕捉
    }
  
    @RequestMapping(value="/mapping/parameter", method=RequestMethod.GET, params="!foo")
    public@ResponseBodyString 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@ResponseBodyString byHeader() {
        return"Mapped by path + method + presence of header!";//附加header的规则
    }
  
    @RequestMapping(value="/mapping/header", method=RequestMethod.GET, headers="!FooHeader")
    public@ResponseBodyString byHeaderNegation() {
        return"Mapped by path + method + absence of header!";//没有FooHeader的headers
    }
  
    @RequestMapping(value="/mapping/consumes", method=RequestMethod.POST, consumes=MediaType.APPLICATION_JSON_VALUE)
    public@ResponseBodyString byConsumes(@RequestBodyJavaBean 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@ResponseBodyJavaBean byProducesJson() {//返回JavaBean的json数据
        returnnewJavaBean();
    }
  
    @RequestMapping(value="/mapping/produces", method=RequestMethod.GET, produces=MediaType.APPLICATION_XML_VALUE)
    public@ResponseBodyJavaBean byProducesXml() {//返回JavaBean的xml数据
        returnnewJavaBean();
    }
}


5.请求参数的处理
@Controller
@RequestMapping("/data")
public classRequestDataController {
  
    @RequestMapping(value="param", method=RequestMethod.GET)
    public@ResponseBodyString withParam(@RequestParamString foo) {
        return"Obtained 'foo' query parameter value '"+ foo + "'";//RequestParam ,获得一个foo的参数,还可以指定参数的名字,例如下面的的
    }
  
    @RequestMapping(value="group", method=RequestMethod.GET)
    public@ResponseBodyString withParamGroup(JavaBean bean) {
        return"Obtained parameter group "+ bean;
    }
  
    @RequestMapping(value="path/{var}", method=RequestMethod.GET)
    public@ResponseBodyString withPathVariable(@PathVariableString 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@ResponseBodyString withMatrixVariable(@PathVariableString path,@MatrixVariableString 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@ResponseBodyString withMatrixVariablesMultiple (
            @PathVariableString path1,@MatrixVariable(value="foo", pathVar="path1") String foo1,
            @PathVariableString 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 classRelativePathUriTemplateController {
  @RequestMapping("/pets/{petId}")
  publicvoidfindPet(@PathVariableString ownerId,@PathVariableString petId, Model model) {
    // implementation omitted
  }
}
  
// GET /owners/42;q=11/pets/21;q=22
@RequestMapping(value ="/owners/{ownerId}/pets/{petId}", method = RequestMethod.GET)
public voidfindPet(
    @MatrixVariable(value="q", pathVar="ownerId")intq1,
    @MatrixVariable(value="q", pathVar="petId")intq2) {
  // 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 允许组合所有参数成为一个
  publicvoidfindPet(
        @MatrixVariableMap < 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 classPersonimplements Serializable {
  
    privatestaticfinal long serialVersionUID = -8333984959652704635L;
  
    privateInteger id;
    privateString firstName;
    privateString lastName;
    privateString currency;
    privateDouble money;
  
  ......getter/setter
  
}
有一个controller:
@Controller
@RequestMapping("EDIT")
public classPetSitesEditController {
 @ModelAttribute("people")
    publicPerson getPerson() {
        returnthis.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)
    publicString saveEdit(@ModelAttribute("personAttribute") Person person,
      @PathVariableInteger id) {
      //spring会把post过来的person信息组合成为一个JavaBean,这里还获得了id这个信息
}
controller代码
根据@ModelAttribute两种用法,可以这样子实现

  @Controller
    publicclassPersonController {
  
        @ModelAttribute("person")
        publicPerson getPerson() {
           returnnewPerson();
        }
  
        @RequestMapping(value ="/new")
        publicString add(@ModelAttribute("person") Person person) {
           return"add person";
        }
   }
/*
* 访问url  /new
* 首先会执行getPerson的方法,然后再执行add方法,其中person这个bean已经被new出来了,所以在add方法中可以被获得,这个有点像下面要说的convert,但是功能要稍微弱一些。
*/

01    @Controller
02    publicclassPersonController {
03  
04        @ModelAttribute("person")
05        publicPerson getPerson() {
06           returnnewPerson();
07        }
08  
09        @RequestMapping(value ="/new")
10        publicString add(@ModelAttribute("person") Person person) {
11           return"add person";
12        }
13   }
14/*
15* 访问url  /new
16* 首先会执行getPerson的方法,然后再执行add方法,其中person这个bean已经被new出来了,所以在add方法中可以被获得,这个有点像下面要说的convert,但是功能要稍微弱一些。
17*/
6.convert,这是spring mvc最令我佩服的地方
首先定义一个convert
01public classAccountConverterimplementsConverter<String, Account> {
02  
03    privateAccountManager accountManager;
04  
05    @Autowired
06    publicAccountConverter(AccountManager accountManager) {//ioc一个accoutManager,用来根据id查出accout
07        this.accountManager = accountManager;
08    }
09  
10    @Override
11    publicAccount convert(String id) {
12        returnthis.accountManager.getAccount(id);
13    }
14  
15}
下面一个controller:
01@Controller
02@RequestMapping("/accounts")
03public classAccountController {
04 
05    @RequestMapping(value="/{account}/edit", method = RequestMethod.GET)
06    publicString edit(@PathVariableAccount account) {
07        //操作accout类
08        return"accounts/edit";
09    }
10}
下面描述了convert的运作过程
7.redirect,重点用法在return中
01@Controller
02@RequestMapping("/redirect")
03public classRedirectController {
04  
05    privatefinalConversionService conversionService;
06  
07    @Inject
08    publicRedirectController(ConversionService conversionService) {
09        this.conversionService = conversionService;
10    }
11  
12    @RequestMapping(value="/uriTemplate", method=RequestMethod.GET)
13    publicString uriTemplate(RedirectAttributes redirectAttrs) {
14        redirectAttrs.addAttribute("account","a123"); // Used as URI template variable
15        redirectAttrs.addAttribute("date",newLocalDate(2011,12,31)); // Appended as a query parameter
16        return"redirect:/redirect/{account}";
17    }
18  
19    @RequestMapping(value="/uriComponentsBuilder", method=RequestMethod.GET)
20    publicString uriComponentsBuilder() {
21        String date =this.conversionService.convert(newLocalDate(2011,12,31), String.class);
22        UriComponents redirectUri = UriComponentsBuilder.fromPath("/redirect/{account}").queryParam("date", date)
23                .build().expand("a123").encode();
24        return"redirect:"+ redirectUri.toUriString();
25    }
26  
27    @RequestMapping(value="/{account}", method=RequestMethod.GET)
28    publicString show(@PathVariableString account, @RequestParam(required=false) LocalDate date) {
29        return"redirect/redirectResults";
30    }
31  
32}
8.org.springframework.ui.Model,Model这个类中有一些css的配置,可以允许我们使用,有时可能会用到
01 
9.文件上传、下载:
上传代码
@Controller
@RequestMapping("/fileupload")
public classFileUploadController {
  
    @ModelAttribute
    publicvoidajaxAttribute(WebRequest request, Model model) {
        model.addAttribute("ajaxRequest", AjaxUtils.isAjaxRequest(request));
    }
  
    @RequestMapping(method=RequestMethod.GET)
    publicvoidfileUploadForm() {
    }
  
    @RequestMapping(method=RequestMethod.POST)
    publicvoidprocessUpload(@RequestParamMultipartFile file, Model model)throwsIOException {//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 voidgetFile(
    @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 +"'");
      thrownewRuntimeException("IOError writing file to output stream");
    }
}//本人比较喜欢这个

@RequestMapping(value ="/files/{file_name}", method = RequestMethod.GET)
@ResponseBody
public FileSystemResource getFile(@PathVariable("file_name") String fileName) {
    returnnewFileSystemResource(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 classAsyncDemoServletextends HttpServlet {
    @Override
    publicvoiddoGet(HttpServletRequest req, HttpServletResponse resp)
    throwsIOException, ServletException {
        resp.setContentType("text/html;charset=UTF-8");
        PrintWriter out = resp.getWriter();
        out.println("开始时间:"+new Date() + ".");
        out.flush();
  
        //在子线程中执行业务调用,并由其负责输出响应,主线程退出
        AsyncContext ctx = req.startAsync();
        newThread(newExecutor(ctx)).start();
  
        out.println("结束时间:"+new Date() + ".");
        out.flush();
    }
}
  
public classExecutorimplements Runnable {
    privateAsyncContext ctx =null;
    publicExecutor(AsyncContext ctx){
        this.ctx = ctx;
    }
  
    publicvoidrun(){
        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 @ResponseBodyCallable<String> callable(final@RequestParam(required=false, defaultValue="true")booleanhandled) {
     //进行一些与处理之后,把最耗时的业务逻辑部分放到Callable中,注意,如果你需要在new Callable中用到从页面传入的参数,需要在参数前加入final
    returnnewCallable<String>() {
        @Override
        publicString 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 @ResponseBodyWebAsyncTask<String> callableWithCustomTimeoutHandling() {

    Callable<String> callable =newCallable<String>() {
        @Override
        publicString call()throws Exception {
            Thread.sleep(2000);
            return"Callable result";
        }
    };

    returnnewWebAsyncTask<String>(1000, callable);//允许指定timeout时间
}


最后一个是DeferredResult<?> ,一个DeferredResult<?> 允许应用程序从一个线程中返回,而何时返回则由线程决定
@Controller
@RequestMapping("/async")
public classDeferredResultController {
  
    privatefinalQueue<DeferredResult<String>> responseBodyQueue =newConcurrentLinkedQueue<DeferredResult<String>>();
  
    privatefinalQueue<DeferredResult<ModelAndView>> mavQueue =newConcurrentLinkedQueue<DeferredResult<ModelAndView>>();
  
    privatefinalQueue<DeferredResult<String>> exceptionQueue =newConcurrentLinkedQueue<DeferredResult<String>>();
  
  
    @RequestMapping("/deferred-result/response-body")
    public@ResponseBodyDeferredResult<String> deferredResult() {
        DeferredResult<String> result =newDeferredResult<String>();
        this.responseBodyQueue.add(result);
        returnresult;
    }
  
    @RequestMapping("/deferred-result/model-and-view")
    public@ResponseBodyDeferredResult<ModelAndView> deferredResultWithView() {
        DeferredResult<ModelAndView> result =newDeferredResult<ModelAndView>();
        this.mavQueue.add(result);
        returnresult;
    }
  
    @RequestMapping("/deferred-result/exception")
    public@ResponseBodyDeferredResult<String> deferredResultWithException() {
        DeferredResult<String> result =newDeferredResult<String>();
        this.exceptionQueue.add(result);
        returnresult;
    }
     //上面三个分别接受了请求之后就return了
    // 这里允许我们在其他的线程中处理数据,并且无需实时返回
    @RequestMapping("/deferred-result/timeout-value")
    public@ResponseBodyDeferredResult<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
  
        returnnewDeferredResult<String>(1000L,"Deferred result after timeout");
    }
     //创建一个计划任务,每2秒处理一次
    @Scheduled(fixedRate=2000)
    publicvoidprocessQueues() {
        for(DeferredResult<String> result :this.responseBodyQueue) {
            result.setResult("Deferred result");
            this.responseBodyQueue.remove(result);
        }
        for(DeferredResult<String> result :this.exceptionQueue) {
            result.setErrorResult(newIllegalStateException("DeferredResult error"));
            this.exceptionQueue.remove(result);
        }
        for(DeferredResult<ModelAndView> result :this.mavQueue) {
            result.setResult(newModelAndView("views/html","javaBean",newJavaBean("bar","apple")));
            this.mavQueue.remove(result);
        }
    }
  
    @ExceptionHandler
    @ResponseBody
    publicString handleException(IllegalStateException ex) {
        return"Handled exception: "+ ex.getMessage();
    }
  
}


11. Interceptor,通过继承HandlerInterceptor, 实现preHandle(..)方法来 定义一些列方法执行前后的动作
官方例子
<mvc:interceptors>
    <refbean="officeHoursInterceptor"/>
</mvc:interceptors>
<beanid="officeHoursInterceptor"
          class="samples.TimeBasedAccessInterceptor">
        <propertyname="openingTime"value="9"/>
        <propertyname="closingTime"value="18"/>
</bean>
package samples;
public classTimeBasedAccessInterceptorextendsHandlerInterceptorAdapter {
    privateintopeningTime;
    privateintclosingTime;
    publicvoidsetOpeningTime(intopeningTime) {
        this.openingTime = openingTime;
    }
    publicvoidsetClosingTime(intclosingTime) {
        this.closingTime = closingTime;
    }
    publicbooleanpreHandle(
            HttpServletRequest request,
            HttpServletResponse response,
            Object handler)throwsException {
        Calendar cal = Calendar.getInstance();
        inthour = cal.get(HOUR_OF_DAY);
        if(openingTime <= hour && hour < closingTime) {
            returntrue;
        } else {
            response.sendRedirect("http://host.com/outsideOfficeHours.html");
            returnfalse;
        }
    }
}


HandlerInterceptorAdapter 里面有很多方法,下面是api的部分文档
 
 
那些pre,after和post开头的方法基本可以满足interceptor的各种需要
 
这里基本结束了spring mvc 3.2的总结,在写这个文章的前几天spring已经出4.0了,看了一下,发现里面开始有websocket的支持了。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值