博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JEE6 CDI 扩展实现 MVC (二)
阅读量:6504 次
发布时间:2019-06-24

本文共 7158 字,大约阅读时间需要 23 分钟。

  hot3.png

        在上一篇中,我们完成了对MVC的Controller 的基本信息的初始化。现在我们注册一个Servlet 来拦截我们的请求然后我们根据请求路径来匹配找到对应的 Controller 的某一个方法。

public class DelegatingServlet extends HttpServlet {	private static final long serialVersionUID = -3941041507536315510L;	@Inject	private MvcHandler mvcHandler;	private static final Logger logger = LoggerFactory			.getLogger(DelegatingServlet.class);	@Override	protected void doGet(HttpServletRequest req, HttpServletResponse resp)			throws ServletException, IOException {		doHandleRequest(req, resp, RequestMethod.GET);	}	@Override	protected void doPost(HttpServletRequest req, HttpServletResponse resp)			throws ServletException, IOException {		doHandleRequest(req, resp, RequestMethod.POST);	}	public void doHandleRequest(HttpServletRequest request,			HttpServletResponse response, RequestMethod requestMethod) {		RequestContext context = new RequestContext(getServletContext(),				request, response, requestMethod);		logger.debug("Servlet delegating the {} request from {}",				requestMethod, request.getRequestURI());		mvcHandler.handleRequest(context);	}}

然后,我们在 web.xml 添加配置,拦截所有 /cdi/* 下面的请求。我们对一次请求里面所涉及到的 对象数据 定义了一个实体。

public class RequestContext {		private final ServletContext servletContext;	private final HttpServletRequest request;	private final HttpServletResponse response;	private final RequestMethod requestMethod;	private Object controller;  // 对应的 controller	private ControllerMethod method;  // controller 的相关参数	private Object outcome;   // controller 的返回值         // gets, sets}

然后把这个实体传给 MvcHandler 处理, MvcHandler 通过请求路径和我们初始化好的Controller 来匹配找出对应的Controller。

public void handleRequest(RequestContext context) {		context.setMethod(matcher.findMatching(controllerInfo, context)); //查找出Controller                 if (context.getMethod() != null) {			Object controller = locateController(context.getMethod()					.getControllerClass());			context.setController(controller);			// start executing the controller method			executeControllerMethod(context); // 找到对应的Controller后,开始执行对应的方法 			                        handleResponse(context);		} else {			throw new RuntimeException("Unable to find method for "					+ context.getRequestMethod() + " request with url "					+ context.getPath());		}	}

public ControllerMethod findMatching(ControllerInfo info,			RequestContext context) {		for (ControllerMethod method : info.getControllerMethods()) {			if (matches(method, context)) {				return method;			}		}		return null;	}	protected boolean matches(ControllerMethod methodToTest, RequestContext context) {		String path = context.getPath();		boolean result = methodToTest.matchesRequestMethod(context.getRequestMethod())				&& (methodToTest.getPrefix() == null || path.startsWith(methodToTest.getPrefix()))				&& (methodToTest.getSuffix() == null || path.endsWith(methodToTest.getSuffix()));		logger.debug("match result = " + result);		return result;	}

找到对应的Controller后,我们开始调用方法。这里分为带参数和不带参数的两种情况。目前参数还是不支持实体。

private void executeControllerMethod(RequestContext context) {		ControllerMethod controllerMethod = context.getMethod();		Method javaMethod = controllerMethod.getMethod();		Object outcome = null;		try {			if (!controllerMethod.getArgs().isEmpty()) {				// 处理带参数的 Controller 方法 				                        HttpServletRequest request = context.getRequest();				outcome = javaMethod.invoke(context.getController(),						handleMethodArgs(controllerMethod,request));			} else {				outcome = javaMethod.invoke(context.getController());			}		} catch (Exception e) {			e.printStackTrace();		}		context.setOutcome(outcome);	}

        处理带参数的方法

private Object[] handleMethodArgs(ControllerMethod controllerMethod,HttpServletRequest request) throws InstantiationException, IllegalAccessException, IllegalArgumentException, SecurityException, InvocationTargetException, NoSuchMethodException{		List
>> args = controllerMethod.getArgs(); List
postArgs = new ArrayList(); for (Map
> map : args) { for (Iterator
iterator = map.keySet().iterator(); iterator .hasNext();) { String key = iterator.next(); String postValue = request.getParameter(key); if (postValue == null || postValue.equals("")) { if(map.get(key).isPrimitive()){ throw new ClassCastException("null value can not be cast to " + map.get(key)+" : " + key); } postArgs.add(map.get(key).newInstance()); }else{ if (map.get(key).isPrimitive()) { // 这里对基本数据类型处理,需要先获得其包装类 Class
wrapClass = ReflectionUtil.getWrapClass(map.get(key)); postArgs.add(wrapClass.getMethod("valueOf", String.class).invoke(wrapClass, request.getParameter(key))); } else { postArgs.add(map.get(key).cast( request.getParameter(key))); } } } } return postArgs.toArray(); }

执行完 Controller 方法,我们根据其返回的 View 的路径来跳转到对应的页面。

private void handleResponse(RequestContext context) {		if (context.getOutcome() instanceof String) {			String outcome = (String) context.getOutcome();			String view = "/" + outcome + ".jsp";			logger.debug("resolved outcome {} to view {}", outcome, view);			context.forwardTo(view);		}	}public void forwardTo(String url) {		if(url == null){			throw new NullPointerException();		}		if (!url.startsWith("/")) {			url = "/" + url;		}		try {			servletContext.getRequestDispatcher(url).forward(request, response);		} catch (Exception e) {			e.printStackTrace();		}	}

        这样,我们就完成了 MVC 一个处理过程。但是我们 Controller 如何向 View 传值呢, CDI 本身是支持 EL 表达式的,所以我们这里可以直接使用 EL 表达式来把 Controller 的数据在 View 上面展示出来。

      基本的MVC demo

        编写我们的Controller,如果需要通过 EL 来传值给 View ,那么就需要加上 @Named 注解。并且为变量添加get方法。

@Controller@RequestMapping("/user/")@Named@RequestScopedpublic class UserController {			private String username;	private int age;	@Inject	public void Page_Load(){		username = "Feng J";	}		@RequestMapping(value = "userinfo")	public String userInfo() {		return "userInfo";	}		@RequestMapping(value = "edit", method = RequestMethod.POST)	public String userInfo(@Param("username") String _username,@Param("age") int _age) {		System.out.println(_username + ":" + _age);		username = _username;		age = _age;		return "viewUser";	}	public String getUsername() {		return username;	}	public void setUsername(String username) {		this.username = username;	}	public int getAge() {		return age;	}	public void setAge(int age) {		this.age = age;	}}

        我们首先访问 /cdi/user/userinfo 。MVC就会帮我们跳转到userInfo.jsp页面。

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%><%String path = request.getContextPath();String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%>					
姓名
年龄

我们看到姓名已经有值,说明通过 EL 表达式拿到了后台 Controller 的值。然后我们修改提交,这里Form的Action是user/edit ,会执行 UserController 的 userInfo 方法,并将参数传过去。然后跳转到 viewUser.jsp 页面。

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%><%String path = request.getContextPath();String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%>          ${userController.username} : ${userController.age}  

在这个页面上面显示修改后的 username 和 age 的值。

提交Form:

        这样我们就完成了一个简单的MVC 处理,当然功能还是比较弱,下面会加上 对整个Form提交的支持,POJO实体提交,返回普通字符串,返回JSon。如果可能的话,还有对 freemarker 这样的支持。

转载于:https://my.oschina.net/FengJ/blog/74192

你可能感兴趣的文章
AI+社交,快手商业化落地之道
查看>>
re:Invent大会第四天:为什么Lambda值得你更多关注?
查看>>
11个Visual Studio代码性能分析工具
查看>>
vue2.0一起在懵逼的海洋里越陷越深(四)
查看>>
为什么Python发展得如此之快?
查看>>
Kubernetes日志分析利器:Elassandra部署使用指南
查看>>
与Susan Fowler探讨生产就绪微服务之问答
查看>>
云原生持续交付的模式和实践
查看>>
美国国会为苹果和FBI举行了听证会
查看>>
Reinhold就Jigsaw投票一事向JCP提交公开信
查看>>
QCon全球软件开发大会(北京站)2015精彩回顾和总结
查看>>
Kong 发布 Kong Brain 和 Kong Immunity,可进行智能自动化和适应性监控
查看>>
es6(二):字符串的扩展
查看>>
智能手机拍照进化论:从传感器到算法摄影
查看>>
magento2项目上线注意事项
查看>>
2018年OpenStack用户调查报告出炉:Kubernetes仍居首
查看>>
集成软件开发工具有多难?现实很残酷!
查看>>
与专门团队一起持续交付
查看>>
Eclipse基金会发布Eclipse Photon IDE
查看>>
Scott Guthrie访谈:定制仪表板与Azure Monitor
查看>>