Skip to content

Commit 9c13d23

Browse files
committed
Demonstrate Spring 3.2 features
Add "Async" tab and CallableController and DeferredResultController. Add links for mapping requests by content type via URL extension. Add global @ExceptionHandler example.
1 parent ca7ea7f commit 9c13d23

File tree

17 files changed

+442
-40
lines changed

17 files changed

+442
-40
lines changed
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package org.springframework.samples.mvc.async;
2+
3+
import java.util.concurrent.Callable;
4+
5+
import org.springframework.stereotype.Controller;
6+
import org.springframework.ui.Model;
7+
import org.springframework.web.bind.annotation.ExceptionHandler;
8+
import org.springframework.web.bind.annotation.RequestMapping;
9+
import org.springframework.web.bind.annotation.RequestParam;
10+
import org.springframework.web.bind.annotation.ResponseBody;
11+
import org.springframework.web.context.request.async.AsyncTask;
12+
13+
@Controller
14+
@RequestMapping("/async/callable")
15+
public class CallableController {
16+
17+
18+
@RequestMapping("/response-body")
19+
public @ResponseBody Callable<String> callable() {
20+
21+
return new Callable<String>() {
22+
@Override
23+
public String call() throws Exception {
24+
Thread.sleep(2000);
25+
return "Callable result";
26+
}
27+
};
28+
}
29+
30+
@RequestMapping("/view")
31+
public Callable<String> callableWithView(final Model model) {
32+
33+
return new Callable<String>() {
34+
@Override
35+
public String call() throws Exception {
36+
Thread.sleep(2000);
37+
model.addAttribute("foo", "bar");
38+
model.addAttribute("fruit", "apple");
39+
return "views/html";
40+
}
41+
};
42+
}
43+
44+
@RequestMapping("/exception")
45+
public @ResponseBody Callable<String> callableWithException(
46+
final @RequestParam(required=false, defaultValue="true") boolean handled) {
47+
48+
return new Callable<String>() {
49+
@Override
50+
public String call() throws Exception {
51+
Thread.sleep(2000);
52+
if (handled) {
53+
// see handleException method further below
54+
throw new IllegalStateException("Callable error");
55+
}
56+
else {
57+
throw new IllegalArgumentException("Callable error");
58+
}
59+
}
60+
};
61+
}
62+
63+
@RequestMapping("/custom-timeout")
64+
public @ResponseBody AsyncTask<String> callableWithCustomTimeout() {
65+
66+
Callable<String> callable = new Callable<String>() {
67+
@Override
68+
public String call() throws Exception {
69+
Thread.sleep(2000);
70+
return "Callable result";
71+
}
72+
};
73+
74+
return new AsyncTask<String>(1000, callable);
75+
}
76+
77+
@ExceptionHandler
78+
@ResponseBody
79+
public String handleException(IllegalStateException ex) {
80+
return "Handled exception: " + ex.getMessage();
81+
}
82+
83+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package org.springframework.samples.mvc.async;
2+
3+
import java.util.Queue;
4+
import java.util.concurrent.PriorityBlockingQueue;
5+
6+
import org.springframework.scheduling.annotation.Scheduled;
7+
import org.springframework.stereotype.Controller;
8+
import org.springframework.web.bind.annotation.ExceptionHandler;
9+
import org.springframework.web.bind.annotation.RequestMapping;
10+
import org.springframework.web.bind.annotation.ResponseBody;
11+
import org.springframework.web.context.request.async.DeferredResult;
12+
import org.springframework.web.servlet.ModelAndView;
13+
14+
@Controller
15+
@RequestMapping("/async")
16+
public class DeferredResultController {
17+
18+
private final Queue<DeferredResult<String>> responseBodyQueue = new PriorityBlockingQueue<DeferredResult<String>>();
19+
20+
private final Queue<DeferredResult<ModelAndView>> mavQueue = new PriorityBlockingQueue<DeferredResult<ModelAndView>>();
21+
22+
private final Queue<DeferredResult<String>> exceptionQueue = new PriorityBlockingQueue<DeferredResult<String>>();
23+
24+
25+
@RequestMapping("/deferred-result/response-body")
26+
public @ResponseBody DeferredResult<String> deferredResult() {
27+
DeferredResult<String> result = new DeferredResult<String>();
28+
this.responseBodyQueue.add(result);
29+
return result;
30+
}
31+
32+
@RequestMapping("/deferred-result/model-and-view")
33+
public @ResponseBody DeferredResult<ModelAndView> deferredResultWithView() {
34+
DeferredResult<ModelAndView> result = new DeferredResult<ModelAndView>();
35+
this.mavQueue.add(result);
36+
return result;
37+
}
38+
39+
@RequestMapping("/deferred-result/exception")
40+
public @ResponseBody DeferredResult<String> deferredResultWithException() {
41+
DeferredResult<String> result = new DeferredResult<String>();
42+
this.exceptionQueue.add(result);
43+
return result;
44+
}
45+
46+
@RequestMapping("/deferred-result/timeout-value")
47+
public @ResponseBody DeferredResult<String> deferredResultWithTimeoutValue() {
48+
49+
// Provide a default result in case of timeout and override the timeout value
50+
// set in src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml
51+
52+
return new DeferredResult<String>(1000L, "Deferred result after timeout");
53+
}
54+
55+
@Scheduled(fixedRate=2000)
56+
public void processQueues() {
57+
for (DeferredResult<String> result : this.responseBodyQueue) {
58+
result.setResult("Deferred result");
59+
this.responseBodyQueue.remove(result);
60+
}
61+
for (DeferredResult<String> result : this.exceptionQueue) {
62+
result.setErrorResult(new IllegalStateException("DeferredResult error"));
63+
this.exceptionQueue.remove(result);
64+
}
65+
for (DeferredResult<ModelAndView> result : this.mavQueue) {
66+
result.setResult(new ModelAndView("views/html", "javaBean", new JavaBean("bar", "apple")));
67+
this.mavQueue.remove(result);
68+
}
69+
}
70+
71+
@ExceptionHandler
72+
@ResponseBody
73+
public String handleException(IllegalStateException ex) {
74+
return "Handled exception: " + ex.getMessage();
75+
}
76+
77+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package org.springframework.samples.mvc.async;
2+
3+
public class JavaBean {
4+
5+
private String foo;
6+
7+
private String fruit;
8+
9+
public JavaBean(String foo, String fruit) {
10+
this.foo = foo;
11+
this.fruit = fruit;
12+
}
13+
14+
public String getFoo() {
15+
return foo;
16+
}
17+
18+
public void setFoo(String foo) {
19+
this.foo = foo;
20+
}
21+
22+
public String getFruit() {
23+
return fruit;
24+
}
25+
26+
public void setFruit(String fruit) {
27+
this.fruit = fruit;
28+
}
29+
30+
}

src/main/java/org/springframework/samples/mvc/convert/ConvertController.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import org.springframework.web.bind.annotation.ResponseBody;
1313

1414
@Controller
15-
@RequestMapping("/convert/*")
15+
@RequestMapping("/convert")
1616
public class ConvertController {
1717

1818
@RequestMapping("primitive")

src/main/java/org/springframework/samples/mvc/data/RequestDataController.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import org.springframework.http.HttpEntity;
44
import org.springframework.stereotype.Controller;
55
import org.springframework.web.bind.annotation.CookieValue;
6+
import org.springframework.web.bind.annotation.MatrixVariable;
67
import org.springframework.web.bind.annotation.PathVariable;
78
import org.springframework.web.bind.annotation.RequestBody;
89
import org.springframework.web.bind.annotation.RequestHeader;
@@ -12,30 +13,30 @@
1213
import org.springframework.web.bind.annotation.ResponseBody;
1314

1415
@Controller
15-
@RequestMapping("/data/*")
16+
@RequestMapping("/data")
1617
public class RequestDataController {
1718

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

23-
@RequestMapping(value="group")
24+
@RequestMapping(value="group", method=RequestMethod.GET)
2425
public @ResponseBody String withParamGroup(JavaBean bean) {
2526
return "Obtained parameter group " + bean;
2627
}
2728

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

33-
@RequestMapping(value="header")
34+
@RequestMapping(value="header", method=RequestMethod.GET)
3435
public @ResponseBody String withHeader(@RequestHeader String Accept) {
3536
return "Obtained 'Accept' header '" + Accept + "'";
3637
}
3738

38-
@RequestMapping(value="cookie")
39+
@RequestMapping(value="cookie", method=RequestMethod.GET)
3940
public @ResponseBody String withCookie(@CookieValue String openid_provider) {
4041
return "Obtained 'openid_provider' cookie '" + openid_provider + "'";
4142
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package org.springframework.samples.mvc.exceptions;
2+
3+
@SuppressWarnings("serial")
4+
public class BusinessException extends Exception {
5+
6+
}

src/main/java/org/springframework/samples/mvc/exceptions/ExceptionController.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,19 @@
88
@Controller
99
public class ExceptionController {
1010

11-
@ExceptionHandler
12-
public @ResponseBody String handle(IllegalStateException e) {
13-
return "IllegalStateException handled!";
14-
}
15-
1611
@RequestMapping("/exception")
1712
public @ResponseBody String exception() {
1813
throw new IllegalStateException("Sorry!");
1914
}
2015

16+
@RequestMapping("/global-exception")
17+
public @ResponseBody String businessException() throws BusinessException {
18+
throw new BusinessException();
19+
}
20+
21+
@ExceptionHandler
22+
public @ResponseBody String handle(IllegalStateException e) {
23+
return "IllegalStateException handled!";
24+
}
25+
2126
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package org.springframework.samples.mvc.exceptions;
2+
3+
import org.springframework.web.bind.annotation.ControllerAdvice;
4+
import org.springframework.web.bind.annotation.ExceptionHandler;
5+
import org.springframework.web.bind.annotation.ResponseBody;
6+
7+
@ControllerAdvice
8+
public class GlobalExceptionHandler {
9+
10+
@ExceptionHandler
11+
public @ResponseBody String handleBusinessException(BusinessException ex) {
12+
return "Handled BusinessException";
13+
}
14+
15+
}

src/main/java/org/springframework/samples/mvc/mapping/JavaBean.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package org.springframework.samples.mvc.mapping;
22

3+
import javax.xml.bind.annotation.XmlRootElement;
4+
5+
@XmlRootElement
36
public class JavaBean {
4-
7+
58
private String foo = "bar";
69

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

28+
@Override
29+
public String toString() {
30+
return "JavaBean {foo=[" + foo + "], fruit=[" + fruit + "]}";
31+
}
32+
2533
}

src/main/java/org/springframework/samples/mvc/mapping/MappingController.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import javax.servlet.http.HttpServletRequest;
44

5+
import org.springframework.http.MediaType;
56
import org.springframework.stereotype.Controller;
67
import org.springframework.web.bind.annotation.RequestBody;
78
import org.springframework.web.bind.annotation.RequestMapping;
@@ -46,13 +47,18 @@ public class MappingController {
4647
return "Mapped by path + method + absence of header!";
4748
}
4849

49-
@RequestMapping(value="/mapping/consumes", method=RequestMethod.POST, consumes="application/json")
50+
@RequestMapping(value="/mapping/consumes", method=RequestMethod.POST, consumes=MediaType.APPLICATION_JSON_VALUE)
5051
public @ResponseBody String byConsumes(@RequestBody JavaBean javaBean) {
5152
return "Mapped by path + method + consumable media type (javaBean '" + javaBean + "')";
5253
}
5354

54-
@RequestMapping(value="/mapping/produces", method=RequestMethod.GET, produces="application/json")
55-
public @ResponseBody JavaBean byProduces() {
55+
@RequestMapping(value="/mapping/produces", method=RequestMethod.GET, produces=MediaType.APPLICATION_JSON_VALUE)
56+
public @ResponseBody JavaBean byProducesJson() {
57+
return new JavaBean();
58+
}
59+
60+
@RequestMapping(value="/mapping/produces", method=RequestMethod.GET, produces=MediaType.APPLICATION_XML_VALUE)
61+
public @ResponseBody JavaBean byProducesXml() {
5662
return new JavaBean();
5763
}
5864

0 commit comments

Comments
 (0)