MVC架构探究及其源码兑现(5)-相关组件实现
MVC架构探究及其源码实现(5)-相关组件实现
本文将讨论HandlerMapping,HandlerAdapter,ViewResolver组件类的具体实现。
URLHandlerMapping,利用request中包含的url信息,找到对应Handler对象,URLHandlerMapping是最典型的映射方式。
- package com.google.mvc.web.servlet.handler;
- import java.util.Map;
- import java.util.concurrent.ConcurrentHashMap;
- import java.util.concurrent.atomic.AtomicBoolean;
- import javax.servlet.http.HttpServletRequest;
- import org.apache.log4j.Logger;
- import com.google.mvc.web.context.WebApplicationContext;
- import com.google.mvc.web.context.WebApplicationContextAware;
- import com.google.mvc.web.servlet.HandlerMapping;
- import com.google.mvc.web.servlet.mvc.Controller;
- import com.google.mvc.web.servlet.mvc.HttpRequestHandler;
- public class URLHandlerMapping implements HandlerMapping, WebApplicationContextAware{
- private static final Logger LOGGER = Logger.getLogger(URLHandlerMapping.class);
- private WebApplicationContext wac;
- private Map<String, Object> handlerMap = new ConcurrentHashMap<String, Object>();
- private AtomicBoolean initialize = new AtomicBoolean(false);
- @Override
- public void setWebApplicationContext(WebApplicationContext wac) {
- this.wac = wac;
- }
- @Override
- public Object getHandler(HttpServletRequest request) throws Exception {
- if(LOGGER.isDebugEnabled()){
- LOGGER.debug("Find handler for request " + request.getServletPath());
- }
- if(initialize.compareAndSet(false, true)){
- Map<String, HttpRequestHandler> map1 = wac.beansOfType(HttpRequestHandler.class);
- for(String key : map1.keySet()){
- handlerMap.put(key, map1.get(key));
- }
- Map<String, Controller> map2 = wac.beansOfType(Controller.class);
- for(String key : map2.keySet()){
- handlerMap.put(key, map2.get(key));
- }
- }
- Object handler = handlerMap.get(getHandlerName(request));
- if(handler == null){
- handler = handlerMap.get("404");
- }
- return handler;
- }
- protected String getHandlerName(HttpServletRequest request){
- String path = request.getServletPath();
- int index = path.lastIndexOf('/');
- String handleName = path.substring(index + 1, path.length());
- return handleName;
- }
- }
HandlerAdapter用于把不同的Handler对象处理的结果封装成一个统一的对象ModelAndView,以达到逻辑上的一致处理。在这里,我们定义两种Handler类型
- Controller:用于处理用户的业务逻辑,并返回具体ModelAndView对象,具体接口定义如下
- package com.google.mvc.web.servlet.mvc;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import com.google.mvc.web.servlet.ModelAndView;
- public interface Controller {
- ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception;
- }
- HttpRequestHandler:用于处理简单的HTTP请求。接口定义如下
- package com.google.mvc.web.servlet.mvc;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- public interface HttpRequestHandler {
- void handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception;
- }
- package com.google.mvc.web.servlet.mvc;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- public class HandlerFor404 implements HttpRequestHandler {
- @Override
- public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
- response.sendRedirect("404.html");
- }
- }
我们需要为每一种不同的Handler类型指定一种HandlerAdapter,但这不是必须的。
ControllerHandlerAdapter
- package com.google.mvc.web.servlet.mvc;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import com.google.mvc.web.servlet.HandlerAdapter;
- import com.google.mvc.web.servlet.ModelAndView;
- public class ControllerHandlerAdapter implements HandlerAdapter{
- public boolean supports(Object handler) {
- return (handler instanceof Controller);
- }
- public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
- throws Exception {
- return ((Controller) handler).handleRequest(request, response);
- }
- public long getLastModified(HttpServletRequest request, Object handler) {
- return -1L;
- }
- }
HttpRequestHandlerAdapter
- package com.google.mvc.web.servlet.mvc;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import com.google.mvc.web.servlet.HandlerAdapter;
- import com.google.mvc.web.servlet.ModelAndView;
- public class HttpRequestHandlerAdapter implements HandlerAdapter {
- @Override
- public long getLastModified(HttpServletRequest request, Object handler) {
- return 0;
- }
- @Override
- public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
- throws Exception {
- ((HttpRequestHandler) handler).handleRequest(request, response);
- return null;
- }
- @Override
- public boolean supports(Object handler) {
- return (handler instanceof HttpRequestHandler);
- }
- }
ViewResolver用于指定View的生成方式,我们先来看下AbstractView的定义
- package com.google.mvc.web.servlet.mvc;
- import java.util.Iterator;
- import java.util.Map;
- import java.util.Map.Entry;
- import javax.servlet.ServletRequest;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import org.apache.log4j.Logger;
- import com.google.mvc.web.servlet.View;
- public abstract class AbstractView implements View {
- private static final Logger LOGGER = Logger.getLogger(AbstractView.class);
- public static final String INCLUDE_REQUEST_URI_ATTRIBUTE = "javax.servlet.include.request_uri";
- public static final String FORWARD_REQUEST_URI_ATTRIBUTE = "javax.servlet.forward.request_uri";
- public static final String FORWARD_CONTEXT_PATH_ATTRIBUTE = "javax.servlet.forward.context_path";
- public static final String FORWARD_SERVLET_PATH_ATTRIBUTE = "javax.servlet.forward.servlet_path";
- public static final String FORWARD_PATH_INFO_ATTRIBUTE = "javax.servlet.forward.path_info";
- public static final String FORWARD_QUERY_STRING_ATTRIBUTE = "javax.servlet.forward.query_string";
- public static final String DEFAULT_CONTENT_TYPE = "text/html;charset=ISO-8859-1";
- private String contentType = DEFAULT_CONTENT_TYPE;
- private boolean alwaysInclude = false;
- @Override
- public String getContentType() {
- return contentType;
- }
- protected void exposeModelAsRequestAttributes(Map<String, Object> model, HttpServletRequest request){
- Iterator<Entry<String, Object>> it = model.entrySet().iterator();
- while (it.hasNext()) {
- Entry<String, Object> entry = it.next();
- String modelName = entry.getKey();
- Object modelValue = entry.getValue();
- if (modelValue != null) {
- request.setAttribute(modelName, modelValue);
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Added model object '" + modelName + "' of type [" + modelValue.getClass().getName() +
- "] to request in view with name '" + this + "'");
- }
- } else {
- request.removeAttribute(modelName);
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Removed model object '" + modelName + "' from request in view with name '"
- + this + "'");
- }
- }
- }
- }
- protected boolean useInclude(HttpServletRequest request, HttpServletResponse response) {
- return (this.alwaysInclude || request.getAttribute(INCLUDE_REQUEST_URI_ATTRIBUTE) != null || response
- .isCommitted());
- }
- protected void exposeForwardRequestAttributes(HttpServletRequest request) {
- exposeRequestAttributeIfNotPresent(request, FORWARD_REQUEST_URI_ATTRIBUTE, request.getRequestURI());
- exposeRequestAttributeIfNotPresent(request, FORWARD_CONTEXT_PATH_ATTRIBUTE, request.getContextPath());
- exposeRequestAttributeIfNotPresent(request, FORWARD_SERVLET_PATH_ATTRIBUTE, request.getServletPath());
- exposeRequestAttributeIfNotPresent(request, FORWARD_PATH_INFO_ATTRIBUTE, request.getPathInfo());
- exposeRequestAttributeIfNotPresent(request, FORWARD_QUERY_STRING_ATTRIBUTE, request.getQueryString());
- }
- private void exposeRequestAttributeIfNotPresent(ServletRequest request, String name, Object value) {
- if (request.getAttribute(name) == null) {
- request.setAttribute(name, value);
- }
- }
- public void setContentType(String contentType) {
- this.contentType = contentType;
- }
- public boolean isAlwaysInclude() {
- return alwaysInclude;
- }
- public void setAlwaysInclude(boolean alwaysInclude) {
- this.alwaysInclude = alwaysInclude;
- }
- }
在这里我们仅实现一种View类型,也就是对jsp页面的简单处理。
- package com.google.mvc.web.servlet.mvc;
- import java.io.IOException;
- import java.util.Map;
- import javax.servlet.RequestDispatcher;
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import org.apache.log4j.Logger;
- public class InternalResourceView extends AbstractView {
- private static final Logger LOGGER = Logger.getLogger(InternalResourceView.class);
- private String url;
- @Override
- public void render(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Rendering view with name '" + this + "' with model " + model);
- }
- if(model != null){
- exposeModelAsRequestAttributes(model, request);
- }
- RequestDispatcher rd = request.getRequestDispatcher(url);
- if (rd == null) {
- throw new ServletException("Could not get RequestDispatcher for ["
- + getUrl() + "]: check that this file exists within your WAR");
- }
- if (useInclude(request, response)) {
- response.setContentType(getContentType());
- rd.include(request, response);
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Included resource [" + getUrl() + "] in InternalResourceView '" + url + "'");
- }
- }else {
- exposeForwardRequestAttributes(request);
- rd.forward(request, response);
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Forwarded to resource [" + getUrl() + "] in InternalResourceView '" + url + "'");
- }
- }
- }
- public String getUrl() {
- return url;
- }
- public void setUrl(String url) {
- this.url = url;
- }
- public String toString(){
- return this.url;
- }
- }
好了,到这里,我们再来看看ViewResolver类的实现
- package com.google.mvc.web.servlet.mvc;
- import org.apache.log4j.Logger;
- import com.google.mvc.web.servlet.View;
- import com.google.mvc.web.servlet.ViewResolver;
- public class DefaultViewResolver implements ViewResolver
- {
- private static final Logger LOGGER = Logger.getLogger(DefaultViewResolver.class);
- private String prefix = "";
- private String suffix = "";
- private Class<View> viewClass;
- @Override
- public View resolveViewName(String viewName) throws Exception {
- View view = viewClass.newInstance();
- if(view instanceof InternalResourceView){
- ((InternalResourceView)view).setUrl(prefix + viewName + suffix);
- }
- return view;
- }
- public void setViewClass(String viewClass){
- try {
- this.viewClass = (Class<View>) this.getClass().getClassLoader().loadClass(viewClass);
- } catch (ClassNotFoundException e) {
- LOGGER.error("Can't load view class " + viewClass, e);
- }
- }
- public String getPrefix() {
- return prefix;
- }
- public void setPrefix(String prefix) {
- this.prefix = prefix;
- }
- public String getSuffix() {
- return suffix;
- }
- public void setSuffix(String suffix) {
- this.suffix = suffix;
- }
- }
到这里,我们在整个MVC架构的源码实现已经完成了,下一篇,我们将介绍一个基于我们这个MVC架构的Demo。
文章来源:http://blog.****.net/zhiqiangzhan/article/details/4768172