Skip to content

Commit

Permalink
Demonstrate Spring 3.2 features
Browse files Browse the repository at this point in the history
Add "Async" tab and CallableController and DeferredResultController.

Add links for mapping requests by content type via URL extension.

Add global @ExceptionHandler example.
  • Loading branch information
rstoyanchev committed Oct 16, 2012
1 parent ca7ea7f commit 9c13d23
Show file tree
Hide file tree
Showing 17 changed files with 442 additions and 40 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package org.springframework.samples.mvc.async;

import java.util.concurrent.Callable;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.async.AsyncTask;

@Controller
@RequestMapping("/async/callable")
public class CallableController {


@RequestMapping("/response-body")
public @ResponseBody Callable<String> callable() {

return new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(2000);
return "Callable result";
}
};
}

@RequestMapping("/view")
public Callable<String> callableWithView(final Model model) {

return new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(2000);
model.addAttribute("foo", "bar");
model.addAttribute("fruit", "apple");
return "views/html";
}
};
}

@RequestMapping("/exception")
public @ResponseBody Callable<String> callableWithException(
final @RequestParam(required=false, defaultValue="true") boolean handled) {

return new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(2000);
if (handled) {
// see handleException method further below
throw new IllegalStateException("Callable error");
}
else {
throw new IllegalArgumentException("Callable error");
}
}
};
}

@RequestMapping("/custom-timeout")
public @ResponseBody AsyncTask<String> callableWithCustomTimeout() {

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

return new AsyncTask<String>(1000, callable);
}

@ExceptionHandler
@ResponseBody
public String handleException(IllegalStateException ex) {
return "Handled exception: " + ex.getMessage();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package org.springframework.samples.mvc.async;

import java.util.Queue;
import java.util.concurrent.PriorityBlockingQueue;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.async.DeferredResult;
import org.springframework.web.servlet.ModelAndView;

@Controller
@RequestMapping("/async")
public class DeferredResultController {

private final Queue<DeferredResult<String>> responseBodyQueue = new PriorityBlockingQueue<DeferredResult<String>>();

private final Queue<DeferredResult<ModelAndView>> mavQueue = new PriorityBlockingQueue<DeferredResult<ModelAndView>>();

private final Queue<DeferredResult<String>> exceptionQueue = new PriorityBlockingQueue<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;
}

@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");
}

@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();
}

}
30 changes: 30 additions & 0 deletions src/main/java/org/springframework/samples/mvc/async/JavaBean.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.springframework.samples.mvc.async;

public class JavaBean {

private String foo;

private String fruit;

public JavaBean(String foo, String fruit) {
this.foo = foo;
this.fruit = fruit;
}

public String getFoo() {
return foo;
}

public void setFoo(String foo) {
this.foo = foo;
}

public String getFruit() {
return fruit;
}

public void setFruit(String fruit) {
this.fruit = fruit;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/convert/*")
@RequestMapping("/convert")
public class ConvertController {

@RequestMapping("primitive")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import org.springframework.http.HttpEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.MatrixVariable;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
Expand All @@ -12,30 +13,30 @@
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/data/*")
@RequestMapping("/data")
public class RequestDataController {

@RequestMapping(value="param")
@RequestMapping(value="param", method=RequestMethod.GET)
public @ResponseBody String withParam(@RequestParam String foo) {
return "Obtained 'foo' query parameter value '" + foo + "'";
}

@RequestMapping(value="group")
@RequestMapping(value="group", method=RequestMethod.GET)
public @ResponseBody String withParamGroup(JavaBean bean) {
return "Obtained parameter group " + bean;
}

@RequestMapping(value="path/{var}")
@RequestMapping(value="path/{var}", method=RequestMethod.GET)
public @ResponseBody String withPathVariable(@PathVariable String var) {
return "Obtained 'var' path variable value '" + var + "'";
}

@RequestMapping(value="header")
@RequestMapping(value="header", method=RequestMethod.GET)
public @ResponseBody String withHeader(@RequestHeader String Accept) {
return "Obtained 'Accept' header '" + Accept + "'";
}

@RequestMapping(value="cookie")
@RequestMapping(value="cookie", method=RequestMethod.GET)
public @ResponseBody String withCookie(@CookieValue String openid_provider) {
return "Obtained 'openid_provider' cookie '" + openid_provider + "'";
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.springframework.samples.mvc.exceptions;

@SuppressWarnings("serial")
public class BusinessException extends Exception {

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,19 @@
@Controller
public class ExceptionController {

@ExceptionHandler
public @ResponseBody String handle(IllegalStateException e) {
return "IllegalStateException handled!";
}

@RequestMapping("/exception")
public @ResponseBody String exception() {
throw new IllegalStateException("Sorry!");
}

@RequestMapping("/global-exception")
public @ResponseBody String businessException() throws BusinessException {
throw new BusinessException();
}

@ExceptionHandler
public @ResponseBody String handle(IllegalStateException e) {
return "IllegalStateException handled!";
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.springframework.samples.mvc.exceptions;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

@ControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler
public @ResponseBody String handleBusinessException(BusinessException ex) {
return "Handled BusinessException";
}

}
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package org.springframework.samples.mvc.mapping;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class JavaBean {

private String foo = "bar";

private String fruit = "apple";
Expand All @@ -22,4 +25,9 @@ public void setFruit(String fruit) {
this.fruit = fruit;
}

@Override
public String toString() {
return "JavaBean {foo=[" + foo + "], fruit=[" + fruit + "]}";
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import javax.servlet.http.HttpServletRequest;

import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
Expand Down Expand Up @@ -46,13 +47,18 @@ public class MappingController {
return "Mapped by path + method + absence of header!";
}

@RequestMapping(value="/mapping/consumes", method=RequestMethod.POST, consumes="application/json")
@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 + "')";
}

@RequestMapping(value="/mapping/produces", method=RequestMethod.GET, produces="application/json")
public @ResponseBody JavaBean byProduces() {
@RequestMapping(value="/mapping/produces", method=RequestMethod.GET, produces=MediaType.APPLICATION_JSON_VALUE)
public @ResponseBody JavaBean byProducesJson() {
return new JavaBean();
}

@RequestMapping(value="/mapping/produces", method=RequestMethod.GET, produces=MediaType.APPLICATION_XML_VALUE)
public @ResponseBody JavaBean byProducesXml() {
return new JavaBean();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import com.sun.syndication.feed.rss.Channel;

@Controller
@RequestMapping("messageconverters/*")
@RequestMapping("/messageconverters")
public class MessageConvertersController {

// StringHttpMessageConverter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,31 @@
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping(value="/response", method=RequestMethod.GET)
public class ResponseController {

@RequestMapping(value="/response/annotation", method=RequestMethod.GET)
@RequestMapping("/annotation")
public @ResponseBody String responseBody() {
return "The String ResponseBody";
}

@RequestMapping(value="/response/charset/accept", method=RequestMethod.GET)
@RequestMapping("/charset/accept")
public @ResponseBody String responseAcceptHeaderCharset() {
return "\u3053\u3093\u306b\u3061\u306f\u4e16\u754c\uff01 (\"Hello world!\" in Japanese)";
}

@RequestMapping(value="/response/charset/produce", method=RequestMethod.GET, produces="text/plain;charset=UTF-8")
@RequestMapping(value="/charset/produce", produces="text/plain;charset=UTF-8")
public @ResponseBody String responseProducesConditionCharset() {
return "\u3053\u3093\u306b\u3061\u306f\u4e16\u754c\uff01 (\"Hello world!\" in Japanese)";
}

@RequestMapping(value="/response/entity/status", method=RequestMethod.GET)
@RequestMapping("/entity/status")
public ResponseEntity<String> responseEntityStatusCode() {
return new ResponseEntity<String>("The String ResponseBody with custom status code (403 Forbidden)",
HttpStatus.FORBIDDEN);
}

@RequestMapping(value="/response/entity/headers", method=RequestMethod.GET)
@RequestMapping("/entity/headers")
public ResponseEntity<String> responseEntityCustomHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.TEXT_PLAIN);
Expand Down
Loading

0 comments on commit 9c13d23

Please sign in to comment.