All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.datalking.web.mvc.ModelFactory Maven / Gradle / Ivy

package com.github.datalking.web.mvc;

import com.github.datalking.annotation.ModelAttribute;
import com.github.datalking.common.BindingResult;
import com.github.datalking.common.Conventions;
import com.github.datalking.common.GenericTypeResolver;
import com.github.datalking.common.MethodParameter;
import com.github.datalking.util.BeanUtils;
import com.github.datalking.util.StringUtils;
import com.github.datalking.web.bind.WebDataBinder;
import com.github.datalking.web.bind.WebDataBinderFactory;
import com.github.datalking.web.context.request.WebRequest;
import com.github.datalking.web.mvc.method.HandlerMethod;
import com.github.datalking.web.servlet.InvocableHandlerMethod;
import com.github.datalking.web.support.ModelAndViewContainer;
import com.github.datalking.web.support.SessionAttributesHandler;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * @author yaoo on 5/2/18
 */
public class ModelFactory {

    private final List attributeMethods;

    private final WebDataBinderFactory binderFactory;

    private final SessionAttributesHandler sessionAttributesHandler;

    public ModelFactory(List attributeMethods,
                        WebDataBinderFactory binderFactory,
                        SessionAttributesHandler sessionAttributesHandler) {

        this.attributeMethods = (attributeMethods != null) ? attributeMethods : new ArrayList<>();
        this.binderFactory = binderFactory;
        this.sessionAttributesHandler = sessionAttributesHandler;
    }

    public void initModel(WebRequest request, ModelAndViewContainer mavContainer, HandlerMethod handlerMethod) throws Exception {

        Map attributesInSession = this.sessionAttributesHandler.retrieveAttributes(request);
        mavContainer.mergeAttributes(attributesInSession);

        // 处理@ModelAttribute注解
        invokeModelAttributeMethods(request, mavContainer);

        for (String name : findSessionAttributeArguments(handlerMethod)) {
            if (!mavContainer.containsAttribute(name)) {
                Object value = this.sessionAttributesHandler.retrieveAttribute(request, name);
                if (value == null) {
                    throw new Exception("Expected session attribute '" + name + "'");
                }
                mavContainer.addAttribute(name, value);
            }
        }
    }

    // 处理@ModelAttribute注解
    private void invokeModelAttributeMethods(WebRequest request, ModelAndViewContainer mavContainer)
            throws Exception {

        for (InvocableHandlerMethod attrMethod : this.attributeMethods) {
            String modelName = attrMethod.getMethodAnnotation(ModelAttribute.class).value();
            if (mavContainer.containsAttribute(modelName)) {
                continue;
            }

            Object returnValue = attrMethod.invokeForRequest(request, mavContainer);

            if (!attrMethod.isVoid()) {
                String returnValueName = getNameForReturnValue(returnValue, attrMethod.getReturnType());
                if (!mavContainer.containsAttribute(returnValueName)) {
                    mavContainer.addAttribute(returnValueName, returnValue);
                }
            }
        }
    }

    private List findSessionAttributeArguments(HandlerMethod handlerMethod) {
        List result = new ArrayList<>();
        for (MethodParameter param : handlerMethod.getMethodParameters()) {
            if (param.hasParameterAnnotation(ModelAttribute.class)) {
                String name = getNameForParameter(param);
                if (this.sessionAttributesHandler.isHandlerSessionAttribute(name, param.getParameterType())) {
                    result.add(name);
                }
            }
        }
        return result;
    }

    public static String getNameForReturnValue(Object returnValue, MethodParameter returnType) {
        ModelAttribute annot = returnType.getMethodAnnotation(ModelAttribute.class);
        if (annot != null && StringUtils.hasText(annot.value())) {
            return annot.value();
        } else {
            Method method = returnType.getMethod();
            Class resolvedType = GenericTypeResolver.resolveReturnType(method, returnType.getDeclaringClass());
            return Conventions.getVariableNameForReturnType(method, resolvedType, returnValue);
        }
    }

    public static String getNameForParameter(MethodParameter parameter) {
        ModelAttribute annot = parameter.getParameterAnnotation(ModelAttribute.class);
        String attrName = (annot != null) ? annot.value() : null;
        return StringUtils.hasText(attrName) ? attrName : Conventions.getVariableNameForParameter(parameter);
    }

    public void updateModel(WebRequest request, ModelAndViewContainer mavContainer) throws Exception {

        if (mavContainer.getSessionStatus().isComplete()) {
            this.sessionAttributesHandler.cleanupAttributes(request);
        } else {
            this.sessionAttributesHandler.storeAttributes(request, mavContainer.getModel());
        }

        if (!mavContainer.isRequestHandled()) {
            updateBindingResult(request, mavContainer.getModel());
        }
    }

    private void updateBindingResult(WebRequest request, ModelMap model) throws Exception {
        List keyNames = new ArrayList<>(model.keySet());
        for (String name : keyNames) {
            Object value = model.get(name);

            if (isBindingCandidate(name, value)) {
                String bindingResultKey = BindingResult.MODEL_KEY_PREFIX + name;

                if (!model.containsAttribute(bindingResultKey)) {

                    WebDataBinder dataBinder = binderFactory.createBinder(request, value, name);
                    model.put(bindingResultKey, dataBinder.getBindingResult());
                }
            }
        }
    }

    private boolean isBindingCandidate(String attributeName, Object value) {
        if (attributeName.startsWith(BindingResult.MODEL_KEY_PREFIX)) {
            return false;
        }

        Class attrType = (value != null) ? value.getClass() : null;
        if (this.sessionAttributesHandler.isHandlerSessionAttribute(attributeName, attrType)) {
            return true;
        }

        return (value != null && !value.getClass().isArray() && !(value instanceof Collection) &&
                !(value instanceof Map) && !BeanUtils.isSimpleValueType(value.getClass()));
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy