com.fengduo.bee.commons.velocity.CustomVelocityLayoutView.java Source code

Java tutorial

Introduction

Here is the source code for com.fengduo.bee.commons.velocity.CustomVelocityLayoutView.java

Source

/*
 * Copyright 2015-2020 Fengduo.com All right reserved. This software is the confidential and proprietary information of
 * Fengduo.com ("Confidential Information"). You shall not disclose such Confidential Information and shall use it only
 * in accordance with the terms of the license agreement you entered into with Fengduo.com.
 */
package com.fengduo.bee.commons.velocity;

import java.io.File;
import java.io.StringWriter;
import java.util.Collection;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.velocity.Template;
import org.apache.velocity.context.Context;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextException;
import org.springframework.web.servlet.view.velocity.VelocityLayoutView;

/**
 * @author zxc May 28, 2015 11:55:45 AM
 */
public class CustomVelocityLayoutView extends VelocityLayoutView {

    private static final Logger logger = LoggerFactory.getLogger(CustomVelocityLayoutView.class);

    public static final String DEFAULT_LAYOUT_DIRECTORY = "/layout";
    public static final String DEFAULT_WIDGET_DIRECTORY = "/widget";
    public static final String DEFAULT_VIEW_DIRECTORY = "/view";
    private static final String DEFAULT_LAYOUT_VM = "default.vm";

    public static final String USE_LAYOUT = "_$_velocity_user_layout_$_"; // ??layoutkey

    private String screenContentKey = DEFAULT_SCREEN_CONTENT_KEY;
    private String contextPath;

    private String suffix;
    private static Map<String, Object> viewTools;
    private ApplicationContext applicationContext;

    public CustomVelocityLayoutView() {

    }

    protected void initApplicationContext(ApplicationContext applicationContext) {
        super.initApplicationContext(applicationContext);
        this.applicationContext = applicationContext;
    }

    /**
     * velocityContext?widget
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    protected Context createVelocityContext(Map model, HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        Context context = super.createVelocityContext(model, request, response);
        if (contextPath == null) {
            contextPath = request.getContextPath();
        }
        context.put("base", contextPath);

        if (viewTools == null) {
            initViewTools();
        }
        if (viewTools.size() != 0) {
            for (String name : viewTools.keySet()) {
                context.put(name, viewTools.get(name));
                logger.debug("the view tool named " + name + " is added to velocity context");
            }
        }

        context.put("widget", new Widget(applicationContext, request, response));
        return context;
    }

    protected void doRender(Context context, HttpServletResponse response) throws Exception {
        Object o = context.get(Widget.IS_WIDGET);
        Object layout = context.get(USE_LAYOUT);
        // widget??
        if (o != null && "true".equals(o.toString())) {
            renderScreenContent(context, response, getUrl());
        }
        // ????
        else if (layout != null && "false".equals(layout.toString())) {
            renderScreenContent(context, response, buildViewName());
        } else {
            mergeScreenContent(context);
            mergeTemplate(getLayoutTemplate(buildViewName()), context, response);
        }
    }

    /**
     * ?<br>
     * ??????<br>
     * ????/namespace/layout/default.vm
     * 
     * @see org.springframework.web.servlet.view.velocity.VelocityLayoutView#checkTemplate()
     */
    @Override
    public boolean checkResource(Locale locale) throws ApplicationContextException {
        return true;
    }

    /**
     * vm
     * 
     * @param viewname
     * @return
     */
    private Template getLayoutTemplate(String viewname) throws Exception {
        /**
         * ??,????<br>
         * ???<br>
         * "/namespace/view/zzz.vm"<br>
         * "/namespace/view/yyy/zzz.vm"<br>
         * "/namespace/view/xxx/yyy/zzz.vm"<br>
         */
        Object obj = getVelocityEngine().getProperty("file.resource.loader.path");
        String resourcePath = "";
        if (obj != null && obj instanceof String) {
            resourcePath = (String) obj;
        }
        // ???
        int index = viewname.indexOf(".");
        if (index != -1) {
            viewname = viewname.substring(0, index);
        }
        viewname += suffix;
        // ?"/"
        if (!viewname.startsWith("/")) {
            viewname = "/" + viewname;
        }
        int base = viewname.indexOf(DEFAULT_VIEW_DIRECTORY);
        base = base + 1 + DEFAULT_LAYOUT_DIRECTORY.length();
        // ?????
        viewname = viewname.replaceFirst(DEFAULT_VIEW_DIRECTORY, DEFAULT_LAYOUT_DIRECTORY);
        String defaultLayout = viewname.substring(0, base) + DEFAULT_LAYOUT_VM;
        String layoutUrlToUse = viewname;
        if (layOutTemplateExists(resourcePath + layoutUrlToUse)) {
            return getTemplate(layoutUrlToUse);
        }
        // ???
        // /namespace/layout/xxx/yyy/zzz.vm ---> /namespace/layout/xxx/yyy/default.vm
        // /namespace/layout/zzz.vm ---> /namespace/layout/default.vm
        layoutUrlToUse = layoutUrlToUse.substring(0, layoutUrlToUse.lastIndexOf("/") + 1).concat(DEFAULT_LAYOUT_VM);
        if (layOutTemplateExists(resourcePath + layoutUrlToUse)) {
            return getTemplate(layoutUrlToUse);
        }
        // 
        // ??
        while (true) {
            // ?/default.vm
            index = layoutUrlToUse.lastIndexOf("/");
            if (index == -1) {
                break;
            }
            layoutUrlToUse = layoutUrlToUse.substring(0, index);
            // 
            index = layoutUrlToUse.lastIndexOf("/");
            if (index == -1) {
                break;
            }
            layoutUrlToUse = layoutUrlToUse.substring(0, index + 1).concat(DEFAULT_LAYOUT_VM);
            // ????
            if (layoutUrlToUse.length() < defaultLayout.length()) {
                break;
            }
            if (layOutTemplateExists(resourcePath + layoutUrlToUse)) {
                return getTemplate(layoutUrlToUse);
            }
        }
        return getTemplate(defaultLayout);
    }

    private boolean layOutTemplateExists(String fileName) {
        File file = new File(fileName);
        return file.exists();
    }

    private void renderScreenContent(Context context, HttpServletResponse response, String name) throws Exception {
        Template screenContentTemplate = getTemplate(name);
        screenContentTemplate.merge(context, response.getWriter());
    }

    private void mergeScreenContent(Context velocityContext) throws Exception {
        StringWriter sw = new StringWriter();
        Template screenContentTemplate = getTemplate(buildViewName());
        screenContentTemplate.merge(velocityContext, sw);
        // Put rendered content into Velocity context.
        velocityContext.put(this.screenContentKey, new ViewContent(sw.toString()));
    }

    public void setScreenContentKey(String screenContentKey) {
        super.setScreenContentKey(screenContentKey);
        this.screenContentKey = screenContentKey;
    }

    public void setSuffix(String suffix) {
        this.suffix = suffix;
    }

    private String buildViewName() {
        String url = getUrl();
        if (StringUtils.startsWith(url, "/")) {
            url = url.substring(1, url.length());
        }
        return DEFAULT_VIEW_DIRECTORY + "/" + url;
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    private void initViewTools() {
        viewTools = new HashMap<String, Object>();
        Map matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext,
                ViewToolsFactory.class, true, false);
        Collection<ViewToolsFactory> values = matchingBeans.values();
        for (ViewToolsFactory factory : values) {
            Map<String, Object> vt = factory.getViewTools();
            if (vt != null) {
                viewTools.putAll(vt);
            }
        }
    }

    public class ViewContent {

        private String content;

        public ViewContent(String content) {
            this.content = content;
        }

        public String toString() {
            if (this.content == null)
                return StringUtils.EMPTY;
            return this.content;
        }
    }
}