AJAXJS MVC 使用教程(下)

Posted sp42a

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AJAXJS MVC 使用教程(下)相关的知识,希望对你有一定的参考价值。

模板和返回响应数据

输出html

控制器处理完业务后会返回结果数据给前端:要么在前后端分离的情况下直接返回JSON数据,无须经过视图层;要么返回HTML则要在View层进行转化。传统Servlet做法是对request进行setAttribute()/getAttribute()的操作,它实质是一个Map<String, Object>的读写。MVC新框架下独立出来这个中介媒介map为ModelAndView对象,用于存储页面所要显示的数据,穿梭于控制器与视图层之间。在控制器方法中加入ModelAndView参数即可,它本身就是HashMap的子类。

以下例子是输出不同类似的数据到页面v中。

package com.demo.mvc;

import java.util.ArrayList;
import java.util.HashMap;

import javax.ws.rs.GET;
import javax.ws.rs.Path;

import com.ajaxjs.web.mvc.ModelAndView;
import com.ajaxjs.web.mvc.controller.IController;

@Path("/output")
public class OutputController implements IController {
	@GET
	public String jsp(ModelAndView mv) {
		mv.put("showText", "测试字符串"); // 测试字符串
		mv.put("showLong", 100000L); // 测试 long
		mv.put("list", new ArrayList<Object>() { // 测试列表
			private static final long serialVersionUID = 1L;
			{
				add("foo");
				add(123456);
				add(true);
			}
		});
		mv.put("array", new String[] { "abc", "bar", "12345a" });// 测试数组
		mv.put("map", new HashMap<String, Object>() {// //测试 Map
			private static final long serialVersionUID = 1L;
			{
				put("key1", "FOO");
				put("key2", "BAR");
				put("key3", false);
			}
		});

		return "/WEB-INF/jsp/output"; // 可以省略 .jsp 的扩展名
	}
}

EL表达式+页面标签赋予了读取ModelAndView的能力,在下面这个JSP中最终显示HTML出来。

<%@ page pageEncoding="UTF-8"%>
<%@taglib uri="/ajaxjs" prefix="c"%>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>输出 Model 数据</title>
	</head>
	<body>
		<h4>测试字符串</h4>
		<div>${showText}</div>
		<h4>测试 long</h4>
		<div>${showLong}</div>
		<h4>测试列表</h4>
		<c:foreach items="${list}">${item} <br /></c:foreach>
		<h4>测试数组</h4>
		<c:foreach items="${array}">${item} <br /></c:foreach>
		<h4>测试 Map</h4>
		<c:foreach items="${map}">
			<div>${item.key} - ${item.value}</div>
		</c:foreach>
	</body>
</html>

输出JSON

控制器方法返回如“json::{"foo":"bar"}”的字符串即可迅速输出JSON。不过为了避免手工拼接字符串,多数情况下采用BaseController下的实用工具方法toJson()Bean/Map/List转换为 JSON 字符串。

@GET
@Path("jsonStr")
public String toJson() {
	// 第二个参数为 true 表示自动附上 json:: 的前缀
	return BaseController.toJson("{\\"foo\\":\\"bar\\"}", true);
}

@GET
@Path("jsonMap")
public String toJsonMap() {
	return BaseController.toJson(new HashMap<String, Object>() {// //测试 Map
		private static final long serialVersionUID = 1L;
		{
			put("key1", "FOO");
			put("key2", "BAR");
			put("key3", false);
		}
	});
}

@GET
@Path("jsonList")
public String toJsonList() {
	return BaseController.toJson(new ArrayList<String>() { // 测试列表
		private static final long serialVersionUID = 1L;
		{
			add("foo"); // 只能是特定的一种泛型,如String/Integer等等,不能是 Object
			add("bar");
		}
	});
}

@GET
@Path("jsonBean")
public String toJsonBean() {
	News news = new News();
	news.setId(1000L);
	news.setName("foo");
	
	return BaseController.toJson(news);
}

MVC过滤器

过滤器的主要目的是拦截每次请求之前和之后的一些操作。有别于Servlet标准过滤器,这是MVC框架中重写的过滤器。为简化概念,框架中不单独另设AOP机制,但可把过滤器当作AOP的代替品。其发挥如下作用:初始化数据库连接、日志记录、权限校验等等。

如下例子中注解@MvcFilter引入了数据库连接过滤器DataBaseFilter,通过过滤器before()方法在list()执行之前调用了数据库连接的逻辑。除此之外@Authority也是过滤器注解,引入PrivilegeFilter实现权限的校验,注解的value属性是创建PrivilegeFilter所必需的构造器参数。

@GET
@MvcFilter(filters = { DataBaseFilter.class })
@Authority(filter = PrivilegeFilter.class, value = RightConstant.ARTICLE_ONLINE)
public String list(@QueryParam(START) int start, @QueryParam(LIMIT) int limit) {
	return page("article-list");
}

MvcFilter的filters属性是FilterAction接口派生类的数组,类型为Class<? extends FilterAction>[]。当用户自定义过滤器时须实现FilterAction接口,给出before(FilterContext ctx)after(FilterAfterArgs ctx)的实现。接口FilterAction源码如下。

package com.ajaxjs.web.mvc.filter;

/**
 * 过滤器动作
 * 
 * @author sp42 frank@ajaxjs.com
 */
public interface FilterAction {
	/**
	 * 是异常但不记录到 FileHandler,例如密码错误之类的。放在 ModelAndView 中传递,例如
	 * model.put(NOT_LOG_EXCEPTION, true);
	 */
	public static final String NOT_LOG_EXCEPTION = "NOT_LOG_EXCEPTION";

	/**
	 * 在 MVC 方法之前调用
	 * 
	 * @return 是否要中止控制器方法的执行,true 表示为不中断
	 */
	public boolean before(FilterContext ctx);

	/**
	 * 在 MVC 方法之后调用
	 * 
	 * @param model    页面数据中间件
	 * @param request  请求对象
	 * @param response 响应对象
	 * @param method   方法对象
	 * @param isbeforeSkip   是否已经中止控制器方法的执行,也就是 before() 返回的值
	 * @return 是否要中止控制器方法默认返回的执行,一般返回 true 表示按原来的执行(大多数情况)
	 */
	public boolean after(FilterAfterArgs ctx);
}

FilterContext/FilterAfterArgs均是前置/后置方法所需的参数列表,用户可按需调用。值得注意是方法的boolean类型返回值,决定了后续方法是否继续执行。前置方法before()返回true是一般正常情况,控制器方法会继续执行;若before()返回false或抛出异常会发生如下两件事:一、中止后续的过滤器执行;二、控制器方法不会执行。没有了控制器执行的结果,自然也不能按原流程返回结果给客户端。此时有两种分支可供用户选择:

  • 后置方法after()参数中的FilterAfterArgs.isbeforeSkip属性就是前置方法为false时的状态,用户在after()实现中应判断isbeforeSkip而给出相应的response响应。
  • 如果想简单一点,可在before()中抛出异常,那样控制器也会接受到异常进而转化为response响应输出(可兼容HTML/JSON格式)。后者的做法更简单直接一点。本来多数情况下,若前置方法不能满足,则后面的未执行逻辑亦无须执行,除非有需要进行特定情况的处理。

框架中内建若干实用的过滤器供用户使用,如下表格所示,在com.ajaxjs.framework.filter.*包和用户模块的com.ajaxjs.user.filter.*

在这里插入图片描述

以上是关于AJAXJS MVC 使用教程(下)的主要内容,如果未能解决你的问题,请参考以下文章

AJAXJS MVC 使用教程(中)

学写一个 Java Web MVC 框架

VIM 代码片段插件 ultisnips 使用教程

Spring MVC 3.2 Thymeleaf Ajax 片段

Spring MVC 教程

ASP.net MVC 代码片段问题中的 Jqgrid 实现