成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

從原理層面掌握@ModelAttribute的使用(核心原理篇)【一起學(xué)Spring MVC】

wdzgege / 3543人閱讀

摘要:雖然它不是必須,但是它是個(gè)很好的輔助官方解釋首先看看官方的對(duì)它怎么說它將方法參數(shù)方法返回值綁定到的里面。解析注解標(biāo)注的方法參數(shù),并處理標(biāo)注的方法返回值。

每篇一句
我們應(yīng)該做一個(gè):胸中有藍(lán)圖,腳底有計(jì)劃的人
前言

Spring MVC提供的基于注釋的編程模型,極大的簡(jiǎn)化了web應(yīng)用的開發(fā),我們都是受益者。比如我們?cè)?b>@RestController標(biāo)注的Controller控制器組件上用@RequestMapping、@ExceptionHandler等注解來表示請(qǐng)求映射、異常處理等等。
使用這種注解的方式來開發(fā)控制器我認(rèn)為最重要的優(yōu)勢(shì)是:

靈活的方法簽名(入?yún)㈦S意寫)

不必繼承基類

不必實(shí)現(xiàn)接口

==總之一句話:靈活性非常強(qiáng),耦合度非常低。==

在眾多的注解使用中,Spring MVC中有一個(gè)非常強(qiáng)大但幾乎被忽視的一員:@ModelAttribute。關(guān)于這個(gè)注解的使用情況,我在群里/線下問了一些人,感覺很少人會(huì)使用這個(gè)注解(甚至有的不知道有這個(gè)注解),這著實(shí)讓我非常的意外。我認(rèn)為至少這對(duì)于"久經(jīng)戰(zhàn)場(chǎng)"的一個(gè)老程序員來說這是不應(yīng)該的吧。

不過沒關(guān)系,有幸看到此文,能夠幫你彌補(bǔ)彌補(bǔ)這塊的盲區(qū)。
@ModelAttribute它不是開發(fā)必須的注解(不像@RequestMapping那么重要),so即使你不知道它依舊能正常書寫控制器。當(dāng)然,正所謂沒有最好只有更好,倘若你掌握了它,便能夠幫助你更加高效的寫代碼,讓你的代碼復(fù)用性更強(qiáng)、代碼更加簡(jiǎn)潔、可維護(hù)性更高。

這種知識(shí)點(diǎn)就像反射、就像內(nèi)省,即使你不知道它你完全也可以工作、寫業(yè)務(wù)需求。但是若你能夠熟練使用,那你的可想象空間就會(huì)更大了,未來可期。雖然它不是必須,但是它是個(gè)很好的輔助~

@ModelAttribute官方解釋

首先看看Spring官方的JavaDoc對(duì)它怎么說:它將方法參數(shù)/方法返回值綁定到web viewModel里面。只支持@RequestMapping這種類型的控制器哦。它既可以標(biāo)注在方法入?yún)⑸希部梢詷?biāo)注在方法(返回值)上。

但是請(qǐng)注意,當(dāng)請(qǐng)求處理導(dǎo)致異常時(shí),引用數(shù)據(jù)和所有其他模型內(nèi)容對(duì)Web視圖不可用,因?yàn)樵摦惓kS時(shí)可能引發(fā),使Model內(nèi)容不可靠。因此,標(biāo)注有@Exceptionhandler的方法不提供對(duì)Model參數(shù)的訪問~

// @since 2.5  只能用在入?yún)?、方法?@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ModelAttribute {

    @AliasFor("name")
    String value() default "";
    // The name of the model attribute to bind to. 注入如下默認(rèn)規(guī)則
    // 比如person對(duì)應(yīng)的類是:mypackage.Person(類名首字母小寫)
    // personList對(duì)應(yīng)的是:List  這些都是默認(rèn)規(guī)則咯~~~ 數(shù)組、Map的省略
    // 具體可以參考方法:Conventions.getVariableNameForParameter(parameter)的處理規(guī)則
    @AliasFor("value")
    String name() default "";

    // 若是false表示禁用數(shù)據(jù)綁定。
    // @since 4.3
    boolean binding() default true;
}
基本原理

我們知道@ModelAttribute能標(biāo)注在入?yún)⑸?,也可以?biāo)注在方法上。下面就從原理處深入理解,從而掌握它的使用,后面再給出多種使用場(chǎng)景的使用Demo。
和它相關(guān)的兩個(gè)類是ModelFactoryModelAttributeMethodProcessor

@ModelAttribute缺省處理的是Request請(qǐng)求域,Spring MVC還提供了@SessionAttributes來處理和Session域相關(guān)的模型數(shù)據(jù),詳見:從原理層面掌握@SessionAttributes的使用【一起學(xué)Spring MVC】

關(guān)于ModelFactory的介紹,在這里講解@SessionAttributes的時(shí)候已經(jīng)介紹一大部分了,但特意留了一部分關(guān)于@ModelAttribute的內(nèi)容,在本文繼續(xù)講解

ModelFactory

ModelFactory所在包org.springframework.web.method.annotation,可見它和web是強(qiáng)關(guān)聯(lián)的在一起的。作為上篇文章的補(bǔ)充說明,接下里只關(guān)心它對(duì)@ModelAttribute的解析部分:

// @since 3.1
public final class ModelFactory {

    // 初始化Model 這個(gè)時(shí)候`@ModelAttribute`有很大作用
    public void initModel(NativeWebRequest request, ModelAndViewContainer container, HandlerMethod handlerMethod) throws Exception {
        // 拿到sessionAttr的屬性
        Map sessionAttributes = this.sessionAttributesHandler.retrieveAttributes(request);
        // 合并進(jìn)容器內(nèi)
        container.mergeAttributes(sessionAttributes);
        // 這個(gè)方法就是調(diào)用執(zhí)行標(biāo)注有@ModelAttribute的方法們~~~~
        invokeModelAttributeMethods(request, container);
        ... 
    }

    //調(diào)用標(biāo)注有注解的方法來填充Model
    private void invokeModelAttributeMethods(NativeWebRequest request, ModelAndViewContainer container) throws Exception {
        // modelMethods是構(gòu)造函數(shù)進(jìn)來的  一個(gè)個(gè)的處理吧
        while (!this.modelMethods.isEmpty()) {
            // getNextModelMethod:通過next其實(shí)能看出 執(zhí)行是有順序的  拿到一個(gè)可執(zhí)行的InvocableHandlerMethod
            InvocableHandlerMethod modelMethod = getNextModelMethod(container).getHandlerMethod();

            // 拿到方法級(jí)別的標(biāo)注的@ModelAttribute~~
            ModelAttribute ann = modelMethod.getMethodAnnotation(ModelAttribute.class);
            Assert.state(ann != null, "No ModelAttribute annotation");
            if (container.containsAttribute(ann.name())) {
                if (!ann.binding()) { // 若binding是false  就禁用掉此name的屬性  讓不支持綁定了  此方法也處理完成
                    container.setBindingDisabled(ann.name());
                }
                continue;
            }

            // 調(diào)用目標(biāo)的handler方法,拿到返回值returnValue 
            Object returnValue = modelMethod.invokeForRequest(request, container);
            // 方法返回值不是void才需要繼續(xù)處理
            if (!modelMethod.isVoid()){

                // returnValueName的生成規(guī)則 上文有解釋過  本處略
                String returnValueName = getNameForReturnValue(returnValue, modelMethod.getReturnType());
                if (!ann.binding()) { // 同樣的 若禁用了綁定,此處也不會(huì)放進(jìn)容器里
                    container.setBindingDisabled(returnValueName);
                }
        
                //在個(gè)判斷是個(gè)小細(xì)節(jié):只有容器內(nèi)不存在此屬性,才會(huì)放進(jìn)去   因此并不會(huì)有覆蓋的效果哦~~~
                // 所以若出現(xiàn)同名的  請(qǐng)自己控制好順序吧
                if (!container.containsAttribute(returnValueName)) {
                    container.addAttribute(returnValueName, returnValue);
                }
            }
        }
    }

    // 拿到下一個(gè)標(biāo)注有此注解方法~~~
    private ModelMethod getNextModelMethod(ModelAndViewContainer container) {
        
        // 每次都會(huì)遍歷所有的構(gòu)造進(jìn)來的modelMethods
        for (ModelMethod modelMethod : this.modelMethods) {
            // dependencies:表示該方法的所有入?yún)⒅?標(biāo)注有@ModelAttribute的入?yún)?            // checkDependencies的作用是:所有的dependencies依賴們必須都是container已經(jīng)存在的屬性,才會(huì)進(jìn)到這里來
            if (modelMethod.checkDependencies(container)) {
                // 找到一個(gè) 就移除一個(gè)
                // 這里使用的是List的remove方法,不用擔(dān)心并發(fā)修改異常??? 哈哈其實(shí)不用擔(dān)心的  小伙伴能知道為什么嗎??
                this.modelMethods.remove(modelMethod);
                return modelMethod;
            }
        }

        // 若并不是所有的依賴屬性Model里都有,那就拿第一個(gè)吧~~~~
        ModelMethod modelMethod = this.modelMethods.get(0);
        this.modelMethods.remove(modelMethod);
        return modelMethod;
    }
    ...
}

ModelFactory這部分做的事:執(zhí)行所有的標(biāo)注有@ModelAttribute注解的方法,并且是順序執(zhí)行哦。那么問題就來了,這些handlerMethods是什么時(shí)候被“找到”的呢???這個(gè)時(shí)候就來到了RequestMappingHandlerAdapter,來看看它是如何找到這些標(biāo)注有此注解@ModelAttribute的處理器的~~~

RequestMappingHandlerAdapter

RequestMappingHandlerAdapter是個(gè)非常龐大的體系,本處我們只關(guān)心它對(duì)@ModelAttribute也就是對(duì)ModelFactory的創(chuàng)建,列出相關(guān)源碼如下:

//  @since 3.1
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter implements BeanFactoryAware, InitializingBean {

    // 該方法不能標(biāo)注有@RequestMapping注解,只標(biāo)注了@ModelAttribute才算哦~
    public static final MethodFilter MODEL_ATTRIBUTE_METHODS = method ->
            (!AnnotatedElementUtils.hasAnnotation(method, RequestMapping.class) && AnnotatedElementUtils.hasAnnotation(method, ModelAttribute.class));
    ...
    // 從Advice里面分析出來的標(biāo)注有@ModelAttribute的方法(它是全局的)
    private final Map> modelAttributeAdviceCache = new LinkedHashMap<>();

    @Nullable
    protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
        WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
        // 每調(diào)用一次都會(huì)生成一個(gè)ModelFactory ~~~
        ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
        ...
        ModelAndViewContainer mavContainer = new ModelAndViewContainer();
        mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
        // 初始化Model
        modelFactory.initModel(webRequest, mavContainer, invocableMethod);
        mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
        ...
        return getModelAndView(mavContainer, modelFactory, webRequest);
    }

    // 創(chuàng)建出一個(gè)ModelFactory,來管理Model
    // 顯然和Model相關(guān)的就會(huì)有@ModelAttribute @SessionAttributes等注解啦~
    private ModelFactory getModelFactory(HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) {
        // 從緩存中拿到和此Handler相關(guān)的SessionAttributesHandler處理器~~處理SessionAttr
        SessionAttributesHandler sessionAttrHandler = getSessionAttributesHandler(handlerMethod);
        Class handlerType = handlerMethod.getBeanType();

        // 找到當(dāng)前類(Controller)所有的標(biāo)注的@ModelAttribute注解的方法
        Set methods = this.modelAttributeCache.get(handlerType);
        if (methods == null) {
            methods = MethodIntrospector.selectMethods(handlerType, MODEL_ATTRIBUTE_METHODS);
            this.modelAttributeCache.put(handlerType, methods);
        }
        
        List attrMethods = new ArrayList<>();
        // Global methods first
        // 全局的有限,最先放進(jìn)List最先執(zhí)行~~~~
        this.modelAttributeAdviceCache.forEach((clazz, methodSet) -> {
            if (clazz.isApplicableToBeanType(handlerType)) {
                Object bean = clazz.resolveBean();
                for (Method method : methodSet) {
                    attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
                }
            }
        });
        for (Method method : methods) {
            Object bean = handlerMethod.getBean();
            attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
        }
        return new ModelFactory(attrMethods, binderFactory, sessionAttrHandler);
    }

    // 構(gòu)造InvocableHandlerMethod 
    private InvocableHandlerMethod createModelAttributeMethod(WebDataBinderFactory factory, Object bean, Method method) {
        InvocableHandlerMethod attrMethod = new InvocableHandlerMethod(bean, method);
        if (this.argumentResolvers != null) {
            attrMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
        }
        attrMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
        attrMethod.setDataBinderFactory(factory);
        return attrMethod;
    }
}

RequestMappingHandlerAdapter這部分處理邏輯:每次請(qǐng)求過來它都會(huì)創(chuàng)建一個(gè)ModelFactory,從而收集到全局的(來自@ControllerAdvice)+ 本Controller控制器上的所有的標(biāo)注有@ModelAttribute注解的方法們。
@ModelAttribute標(biāo)注在多帶帶的方法上(木有@RequestMapping注解),它可以在每個(gè)控制器方法調(diào)用之前,創(chuàng)建出一個(gè)ModelFactory從而管理Model數(shù)據(jù)~

ModelFactory管理著Model,提供了@ModelAttribute以及@SessionAttributes等對(duì)它的影響

同時(shí)@ModelAttribute可以標(biāo)注在入?yún)?、方法(返回值)上的,?biāo)注在不同地方處理的方式是不一樣的,那么接下來又一主菜ModelAttributeMethodProcessor就得登場(chǎng)了。

ModelAttributeMethodProcessor

從命名上看它是個(gè)Processor,所以根據(jù)經(jīng)驗(yàn)它既能處理入?yún)ⅲ材芴幚矸椒ǖ姆祷刂担?b>HandlerMethodArgumentResolver + HandlerMethodReturnValueHandler。解析@ModelAttribute注解標(biāo)注的方法參數(shù),并處理@ModelAttribute標(biāo)注的方法返回值。

==先看它對(duì)方法入?yún)⒌奶幚恚ㄉ燥@復(fù)雜):==

// 這個(gè)處理器用于處理入?yún)?、方法返回值~~~~
// @since 3.1
public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResolver, HandlerMethodReturnValueHandler {

    private static final ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
    private final boolean annotationNotRequired;

    public ModelAttributeMethodProcessor(boolean annotationNotRequired) {
        this.annotationNotRequired = annotationNotRequired;
    }


    // 入?yún)⒗飿?biāo)注了@ModelAttribute 或者(注意這個(gè)或者) annotationNotRequired = true并且不是isSimpleProperty()
    // isSimpleProperty():八大基本類型/包裝類型、Enum、Number等等 Date Class等等等等
    // 所以劃重點(diǎn):即使你沒標(biāo)注@ModelAttribute  單子還要不是基本類型等類型,都會(huì)進(jìn)入到這里來處理
    // 當(dāng)然這個(gè)行為是是收到annotationNotRequired屬性影響的,具體的具體而論  它既有false的時(shí)候  也有true的時(shí)候
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return (parameter.hasParameterAnnotation(ModelAttribute.class) ||
                (this.annotationNotRequired && !BeanUtils.isSimpleProperty(parameter.getParameterType())));
    }

    // 說明:能進(jìn)入到這里來的  證明入?yún)⒗锟隙ㄊ怯袑?duì)應(yīng)注解的???
    // 顯然不是,上面有說  這事和屬性值annotationNotRequired有關(guān)的~~~
    @Override
    @Nullable
    public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
    
        // 拿到ModelKey名稱~~~(注解里有寫就以注解的為準(zhǔn))
        String name = ModelFactory.getNameForParameter(parameter);
        // 拿到參數(shù)的注解本身
        ModelAttribute ann = parameter.getParameterAnnotation(ModelAttribute.class);
        if (ann != null) {
            mavContainer.setBinding(name, ann.binding());
        }

        Object attribute = null;
        BindingResult bindingResult = null;

        // 如果model里有這個(gè)屬性,那就好說,直接拿出來完事~
        if (mavContainer.containsAttribute(name)) {
            attribute = mavContainer.getModel().get(name);
        } else { // 若不存在,也不能讓是null呀
            // Create attribute instance
            // 這是一個(gè)復(fù)雜的創(chuàng)建邏輯:
            // 1、如果是空構(gòu)造,直接new一個(gè)實(shí)例出來
            // 2、若不是空構(gòu)造,支持@ConstructorProperties解析給構(gòu)造賦值
            //   注意:這里就支持fieldDefaultPrefix前綴、fieldMarkerPrefix分隔符等能力了 最終完成獲取一個(gè)屬性
            // 調(diào)用BeanUtils.instantiateClass(ctor, args)來創(chuàng)建實(shí)例
            // 注意:但若是非空構(gòu)造出來,是立馬會(huì)執(zhí)行valid校驗(yàn)的,此步驟若是空構(gòu)造生成的實(shí)例,此步不會(huì)進(jìn)行valid的,但是下一步會(huì)哦~
            try {
                attribute = createAttribute(name, parameter, binderFactory, webRequest);
            } catch (BindException ex) {
                if (isBindExceptionRequired(parameter)) {
                    // No BindingResult parameter -> fail with BindException
                    throw ex;
                }
                // Otherwise, expose null/empty value and associated BindingResult
                if (parameter.getParameterType() == Optional.class) {
                    attribute = Optional.empty();
                }
                bindingResult = ex.getBindingResult();
            }
        }

        // 若是空構(gòu)造創(chuàng)建出來的實(shí)例,這里會(huì)進(jìn)行數(shù)據(jù)校驗(yàn)  此處使用到了((WebRequestDataBinder) binder).bind(request);  bind()方法  唯一一處
        if (bindingResult == null) {
            // Bean property binding and validation;
            // skipped in case of binding failure on construction.
            WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
            if (binder.getTarget() != null) {
                // 綁定request請(qǐng)求數(shù)據(jù)
                if (!mavContainer.isBindingDisabled(name)) {
                    bindRequestParameters(binder, webRequest);
                }
                // 執(zhí)行valid校驗(yàn)~~~~
                validateIfApplicable(binder, parameter);
                //注意:此處拋出的異常是BindException
                //RequestResponseBodyMethodProcessor拋出的異常是:MethodArgumentNotValidException
                if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
                    throw new BindException(binder.getBindingResult());
                }
            }
            // Value type adaptation, also covering java.util.Optional
            if (!parameter.getParameterType().isInstance(attribute)) {
                attribute = binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);
            }
            bindingResult = binder.getBindingResult();
        }

        // Add resolved attribute and BindingResult at the end of the model
        // at the end of the model  把解決好的屬性放到Model的末尾~~~
        // 可以即使是標(biāo)注在入?yún)⑸系腀ModelAtrribute的屬性值,最終也都是會(huì)放進(jìn)Model里的~~~可怕吧
        Map bindingResultModel = bindingResult.getModel();
        mavContainer.removeAttributes(bindingResultModel);
        mavContainer.addAllAttributes(bindingResultModel);

        return attribute;
    }

    // 此方法`ServletModelAttributeMethodProcessor`子類是有復(fù)寫的哦~~~~
    // 使用了更強(qiáng)大的:ServletRequestDataBinder.bind(ServletRequest request)方法
    protected void bindRequestParameters(WebDataBinder binder, NativeWebRequest request) {
        ((WebRequestDataBinder) binder).bind(request);
    }
}

模型屬性首先從Model中獲取,若沒有獲取到,就使用默認(rèn)構(gòu)造函數(shù)(可能是有無參,也可能是有參)創(chuàng)建,然后會(huì)把ServletRequest請(qǐng)求的數(shù)據(jù)綁定上來, 然后進(jìn)行@Valid校驗(yàn)(若添加有校驗(yàn)注解的話),最后會(huì)把屬性添加到Model里面

最后加進(jìn)去的代碼是:mavContainer.addAllAttributes(bindingResultModel);這里我貼出參考值:

如下示例,它會(huì)正常打印person的值,而不是null(因?yàn)镸odel內(nèi)有person了~)
請(qǐng)求鏈接是:/testModelAttr?name=wo&age=10

    @GetMapping("/testModelAttr")
    public void testModelAttr(@Valid Person person, ModelMap modelMap) {
        Object personAttr = modelMap.get("person");
        System.out.println(personAttr); //Person(name=wo, age=10)
    }

注意:雖然person上沒有標(biāo)注@ModelAtrribute,但是modelMap.get("person")依然是能夠獲取到值的哦,至于為什么,原因上面已經(jīng)分析了,可自行思考。

下例中:

    @GetMapping("/testModelAttr")
    public void testModelAttr(Integer age, Person person, ModelMap modelMap) {
        System.out.println(age); // 直接封裝的值
        System.out.println("-------------------------------");
        System.out.println(modelMap.get("age"));
        System.out.println(modelMap.get("person"));
    }

請(qǐng)求:/testModelAttr?name=wo&age=10 輸入為:

10
-------------------------------
null
Person(name=wo, age=10)

可以看到普通類型(注意理解這個(gè)普通類型)若不標(biāo)注@ModelAtrribute,它是不會(huì)自動(dòng)識(shí)別為Model而放進(jìn)來的喲~~~若你這么寫:

    @GetMapping("/testModelAttr")
    public void testModelAttr(@ModelAttribute("age") Integer age, Person person, ModelMap modelMap) {
        System.out.println(age); // 直接封裝的值
        System.out.println("-------------------------------");
        System.out.println(modelMap.get("age"));
        System.out.println(modelMap.get("person"));
    }

打印如下:

10
-------------------------------
10
Person(name=wo, age=10)

請(qǐng)務(wù)必注意以上case的區(qū)別,加深記憶。使用的時(shí)候可別踩坑了~

==再看它對(duì)方法(返回值)的處理(很簡(jiǎn)單):==

public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResolver, HandlerMethodReturnValueHandler {

    // 方法返回值上標(biāo)注有@ModelAttribute注解(或者非簡(jiǎn)單類型)  默認(rèn)都會(huì)放進(jìn)Model內(nèi)哦~~
    @Override
    public boolean supportsReturnType(MethodParameter returnType) {
        return (returnType.hasMethodAnnotation(ModelAttribute.class) ||
                (this.annotationNotRequired && !BeanUtils.isSimpleProperty(returnType.getParameterType())));
    }

    // 這個(gè)處理就非常非常的簡(jiǎn)單了,注意:null值是不放的哦~~~~
    // 注意:void的話  returnValue也是null
    @Override
    public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
            ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {

        if (returnValue != null) {
            String name = ModelFactory.getNameForReturnValue(returnValue, returnType);
            mavContainer.addAttribute(name, returnValue);
        }
    }
}

它對(duì)方法返回值的處理非常簡(jiǎn)單,只要不是null(當(dāng)然不能是void)就都會(huì)放進(jìn)Model里面,供以使用

總結(jié)

本文介紹的是@ModelAttribute的核心原理,他對(duì)我們實(shí)際使用有重要的理論支撐。下面系列文章主要在原理的基礎(chǔ)上,展示各種各樣場(chǎng)景下的使用Demo,敬請(qǐng)關(guān)注~

相關(guān)閱讀

從原理層面掌握@SessionAttributes的使用【一起學(xué)Spring MVC】
從原理層面掌握@RequestAttribute、@SessionAttribute的使用【一起學(xué)Spring MVC】
從原理層面掌握@ModelAttribute的使用(使用篇)【一起學(xué)Spring MVC】

知識(shí)交流

==The last:如果覺得本文對(duì)你有幫助,不妨點(diǎn)個(gè)贊唄。當(dāng)然分享到你的朋友圈讓更多小伙伴看到也是被作者本人許可的~==

**若對(duì)技術(shù)內(nèi)容感興趣可以加入wx群交流:Java高工、架構(gòu)師3群。
若群二維碼失效,請(qǐng)加wx號(hào):fsx641385712(或者掃描下方wx二維碼)。并且備注:"java入群" 字樣,會(huì)手動(dòng)邀請(qǐng)入群**

若文章格式混亂或者圖片裂開,請(qǐng)點(diǎn)擊`:原文鏈接-原文鏈接-原文鏈接

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/76199.html

相關(guān)文章

  • 原理層面掌握@ModelAttribute使用使用)【一起學(xué)Spring MVC

    摘要:和一起使用參照博文從原理層面掌握的使用一起學(xué)。至于具體原因,可以移步這里輔助理解從原理層面掌握的使用核心原理篇一起學(xué)再看下面的變種例子重要訪問。 每篇一句 每個(gè)人都應(yīng)該想清楚這個(gè)問題:你是祖師爺賞飯吃的,還是靠老天爺賞飯吃的 前言 上篇文章 描繪了@ModelAttribute的核心原理,這篇聚焦在場(chǎng)景使用上,演示@ModelAttribute在不同場(chǎng)景下的使用,以及注意事項(xiàng)(當(dāng)然有些...

    BenCHou 評(píng)論0 收藏0
  • 原理層面掌握@RequestAttribute、@SessionAttribute使用一起學(xué)S

    摘要:同時(shí)另外一個(gè)目的是希望完全屏蔽掉源生,增加它的擴(kuò)展性。本文我以為例進(jìn)行講解,因?yàn)橐彩呛笸瞥龅淖⒔獠还軓氖褂煤驮砩隙际且荒R粯拥?。作用從中取?duì)應(yīng)的屬性值。 每篇一句 改我們就改得:取其精華,去其糟粕。否則木有意義 前言 如果說知道@SessionAttributes這個(gè)注解的人已經(jīng)很少了,那么不需要統(tǒng)計(jì)我就可以確定的說:知道@RequestAttribute注解的更是少之又少。我覺得主...

    why_rookie 評(píng)論0 收藏0
  • 原理層面掌握@SessionAttribute使用一起學(xué)Spring MVC

    摘要:見名之意,它是處理器,也就是解析這個(gè)注解的核心。管理通過標(biāo)注了的特定會(huì)話屬性,存儲(chǔ)最終是委托了來實(shí)現(xiàn)。只會(huì)清楚注解放進(jìn)去的,并不清除放進(jìn)去的它的唯一實(shí)現(xiàn)類實(shí)現(xiàn)也簡(jiǎn)單。在更新時(shí),模型屬性與會(huì)話同步,如果缺少,還將添加屬性。 每篇一句 不是你當(dāng)上了火影大家就認(rèn)可你,而是大家都認(rèn)可你才能當(dāng)上火影 前言 該注解顧名思義,作用是將Model中的屬性同步到session會(huì)話當(dāng)中,方便在下一次請(qǐng)求中...

    ARGUS 評(píng)論0 收藏0
  • 原理層面掌握HandlerMethod、InvocableHandlerMethod使用一起學(xué)

    摘要:并且,并且如果或者不為空不為且不為,將中斷處理直接返回不再渲染頁(yè)面對(duì)返回值的處理對(duì)返回值的處理是使用完成的對(duì)異步處理結(jié)果的處理使用示例文首說了,作為一個(gè)非公開,如果你要直接使用起來,還是稍微要費(fèi)點(diǎn)勁的。 每篇一句 想當(dāng)火影的人沒有近道可尋,當(dāng)上火影的人同樣無路可退 前言 HandlerMethod它作為Spring MVC的非公開API,可能絕大多數(shù)小伙伴都對(duì)它比較陌生,但我相信你對(duì)它...

    wawor4827 評(píng)論0 收藏0
  • 原理層面掌握HandlerMethod、InvocableHandlerMethod使用一起學(xué)

    摘要:并且,并且如果或者不為空不為且不為,將中斷處理直接返回不再渲染頁(yè)面對(duì)返回值的處理對(duì)返回值的處理是使用完成的對(duì)異步處理結(jié)果的處理使用示例文首說了,作為一個(gè)非公開,如果你要直接使用起來,還是稍微要費(fèi)點(diǎn)勁的。 每篇一句 想當(dāng)火影的人沒有近道可尋,當(dāng)上火影的人同樣無路可退 前言 HandlerMethod它作為Spring MVC的非公開API,可能絕大多數(shù)小伙伴都對(duì)它比較陌生,但我相信你對(duì)它...

    miya 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<