JEE6 CDI 擴展實現 MVC (三) 支持返回String,JSon,Freemarker

        前面咱們實現了 MVC 的最基本的功能,視圖跳轉以及基本數據的傳遞。這部分咱們對 Controller 的返回值進行擴展,支持返回 字符串, JSon 以及 對Freemarker模板引擎的支持。javascript

       添加註解

        @ResponseBody 當Controller的方法 ResponseBody 註解的時候說明放回的值既是爲 String 的話,也不是跳轉到View。它的 value 爲 ResponseType 枚舉,用來表示 Response 返回內容的類型。html

        @ResponseTemplate 表示Controller方法返回時調用模板引擎來返回靜態頁面。他的value的值爲模板頁面的路徑,type值表示爲哪種模板引擎。java

        固然,爲了方便處理,一個Controller 方法不能同時擁有 這兩個註解。jquery

@Target({ ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface  ResponseBody {
	ResponseType value();

}
@Qualifier
@Target({ElementType.METHOD,ElementType.TYPE,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface  ResponseTemplate {
	String value() default "";
	TemplateType type();
}

      擴展 Controller 方法的元數據

        咱們對保存Controller方法的元數據對象擴展,添加這個兩個註解的屬性。
ajax

public class ControllerMethod {

	private final String prefix;
	private final String suffix;
	private final RequestMethod[] requestMethod;
	private final Method method;
	private final List<Map<String,Class<?>>> args;
	private final ResponseBody responseBody;
	private final ResponseTemplate responseTemplate;

        // gets, sets
}

      根據Controller方法具備的不一樣註解來處理放回值

        咱們在拿到Controller方法的返回值以後,咱們來判斷這個方法應該是返回什麼樣的數據類型來進行不一樣的處理。
json

if (context.hasBodyAndTemplate()) {
    throw new ControllerException("Controller method can not has both ResponseBody and ResponseTemplate");
}
if (context.isOutView()) {
    handleResponse(context);
} else {
    handleResponseNotView(context);
}
private void handleResponseNotView(RequestContext context)
			throws IOException {
		if (context.isResponseBody()) {
			try {
				responseBodyHandler.handler(context);
			} catch (JSONException e) {
				e.printStackTrace();
			}
		}
		if(context.isResponseTemplate()){
			templateHandler.handle(context);
		}
	}

      處理ResponseBody

        在處理ResponseBody類型的時候,咱們先根據註解的值來肯定是否須要先處理成JSon 或者xml 等形式的數據,而後返回。我這裏處理JSon直接使用了 json-lib.jar 。
app

public class DefaultResponseHandler implements ResponseBodyHandler{

	public void handler(RequestContext context) throws IOException, JSONException {
		ResponseType responseType = context.getMethod().getResponseBody().value();
		if(responseType.equals(ResponseType.TEXT_HTML)){
			handlerText(context.getOutcome(), context);
		}else if(responseType.equals(ResponseType.APPLICATION_JSON)){
			handlerJson(context.getOutcome(), context);
		}
	}

	private void handlerText(Object obj, RequestContext context) throws IOException{
		context.getResponse().setContentType("text/html");
		context.getResponse().getWriter().write(obj.toString());
	}
	
	private void handlerJson(Object obj, RequestContext context) throws IOException, JSONException{
		context.getResponse().setContentType("application/json");
		String jsonString = null ;
		if(obj instanceof Collection){
			jsonString= JSONArray.fromObject(obj).toString();
		}else{
			jsonString= JSONObject.fromObject(obj).toString();
		}
		System.out.println(jsonString);
		context.getResponse().getWriter().write(jsonString==null? "":jsonString);
	}
}

      處理ResponseTemplate

        對於模板引擎的支持,Seam3 Rest 模塊只能同時啓用一種模板引擎。我這裏打算同時支持多種模板引擎,因此在ResponseTemplate註解中加了TemplateType的,能夠經過它的值來注入不一樣的模塊引擎來處理。這功能還在完成中,下一部分會給出。這裏直接使用了 Freemarker來處理。
jsp

public class DefaultTemplateHandler {

	@Inject @ResponseTemplate(type=TemplateType.FREEMARKER) 
        private ResponeseTemplateHandler templateHandler;
	public void handle(RequestContext context){
		try {
			templateHandler.process(context);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
@ResponseTemplate(type = TemplateType.FREEMARKER)
public class FreeMarkerTemplate implements ResponeseTemplateHandler{

	private Configuration cfg;

	
	public void init(String path) throws IOException {
		 cfg = new Configuration();
	     cfg.setDirectoryForTemplateLoading(new File(path));
	}

	public void process(RequestContext context) throws IOException {
		init(context.getRequest().getSession().getServletContext().getRealPath("/"));
		String templatePath = context.getMethod().getResponseTemplate().value();
		Template t = cfg.getTemplate(templatePath);
		try {
			HttpServletResponse response =  context.getResponse();
			response.setContentType("text/html");
			t.process(context.getOutcome(), context.getResponse().getWriter());
		} catch (TemplateException e) {
			e.printStackTrace();
		}
	}

}

      演示實例

        咱們使用 ajax 來請求來或者這些返回值。先編寫頁面:
url

<html>
  <head>
    <base href="<%=basePath%>">
    
    <title>My JSP 'index.jsp' starting page</title>
    <script type="text/javascript" src="resources/jquery-1.7.2.min.js"></script>
    <script type="text/javascript">
		$(document).ready(function(){
			$("#btn-string").click(function(){
				$.ajax({
					url: "cdi/person/str",
					success:function(data){
						alert(data);
						$("#value-string").append(data);
					}
				});
			});
			$("#btn-json").click(function(){
				$.ajax({
					url: "cdi/person/json",
					success:function(data){
						alert(data);
						$("#value-json").html(data.firstName+":"+data.lastName);
					}
				});
			});
			$("#btn-freemarker").click(function(){
				$.ajax({
					url: "cdi/person/freemarker",
					success:function(data){
						alert(data);
						$("#value-freemarker").html(data);
					}
				});
			});
		});
    </script>
  </head>
  
  <body>
   	<input type="button" value="Ajax請求String" id="btn-string" />
   	<span id="value-string"></span>
   	<br />
   	<input type="button" value="Ajax請求JSon" id="btn-json" />
   	<span id="value-json"></span>
   	<br />
   	<input type="button" value="Ajax請求Freemarker" id="btn-freemarker" />
   	<span id="value-freemarker"></span>
  </body>
</html>

編寫PersonController.javaspa

@Controller
@RequestMapping("/person/")
@Named
@RequestScoped
public class PersonController {

	@RequestMapping("str")
	@ResponseBody(ResponseType.TEXT_HTML)
	public String returnStr(){
		return "Hello CDI";
	}
	
	@RequestMapping("json")
	@ResponseBody(ResponseType.APPLICATION_JSON)
	public Person returnJson(){
		return new Person(1L, "Feng", "J");
	}
	
	@RequestMapping("freemarker")
	@ResponseTemplate(value="templates/user.ftl",type=TemplateType.FREEMARKER)
	public Map<String,Object> returnFreemarker(){
		Map<String,Object> map = new HashMap<String, Object>();
		List<Object> list = new ArrayList<Object>();
		list.add(new Person(1L,"Feng" , "J"));
		list.add(new Person(2L,"CDI" , "MVC"));
		map.put("users", list);
		return map;
	}
}

user.ftl

<#list users as user>
	<span style="color:red">${user.id}:${user.firstName}:${user.lastName}</span>
</#list>

結果:

相關文章
相關標籤/搜索