Spring MVCにおけるいくつかの常用注釈の使い方とパラメータ分析

29232 ワード

SpringMVCを勉強している時に、これらの注釈のパラメータについてはよく分かりませんでした.今直します.
  • @Request Attributeは@Session Attributeのように、注釈@Request Attributeは、フィルタまたはブロックによって作成され、予め存在する要求属性にアクセスするために使用されてもよい.ソースコード:
    @Target({ElementType.PARAMETER})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface RequestAttribute {
        @AliasFor("name")//  name   
        String value() default "";
    
        @AliasFor("value")//  value   
    
        //The default name is inferred from the method parameter name.
        String name() default "";
    
        boolean required() default true;
    }
    ソースからは、nameの属性とvalueの属性は同じですが、互いに別名です.属性name(またはvalue)のデフォルト値は、イメージ名です.nameとvalueを同時に設定したら、結果はどうなりますか?controller層の部分コード:
    @RequestMapping(value = "/register", method = RequestMethod.GET)
    public ModelAndView register(@RequestParam(name = "info1", value = "info2")String info){
        System.out.println("info = " + info);
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("register");
        return modelAndView;
    }
    エラー情報:
    org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.core.annotation.AnnotationConfigurationException: In annotation [org.springframework.web.bind.annotation.RequestParam] declared on public org.springframework.web.servlet.ModelAndView com.ths.demo3.controller.UserController.register(java.lang.String) and synthesized from [@org.springframework.web.bind.annotation.RequestParam(name=info1, value=info2, defaultValue=
        , required=true)], attribute 'name' and its alias 'value' are present with values of [info1] and [info2], but only one is permitted.
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:982)
    org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:635)
    org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    attribute 'name' and its alias 'value' are present with values of [info1] and [info2], but only one is permittedの行が見られます.nameとvalueは本当に結合されています.同時に異なる値に設定できません.
  • @Request Param@Request Paramは、要求パラメータデータを機能処理方法のパラメータにマッピングするために使用される.より分かりやすいのは、要求されたパラメータを方法のイメージに入れることで、より使いやすいということです.ソース:
    @Target({ElementType.PARAMETER})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface RequestParam {
        @AliasFor("name")
        String value() default "";
    
        @AliasFor("value")
        String name() default "";
    
        //Defaults to true, leading to an exception being thrown if the parameter is missing in the request. Switch this to false if you prefer a null value if the parameter is not present in the request.
        //Alternatively, provide a defaultValue(), which implicitly sets this flag to false.
        boolean required() default true;
    
        //The default value to use as a fallback when the request parameter is not provided or has an empty value.
        //Supplying a default value implicitly sets required() to false.
        String defaultValue() default "
    \t\t
    \t\t
    \ue000\ue001\ue002
    \t\t\t\t
    "
    ; }
    nameとvalueの関係は@Request Attributeですでに言及しました.ここも同じです.もう説明しません.なお、defaultValueの値が設定されている場合には、requird=trueが設定されていても、パラメータが入力されていないことは許容され、値だけがデフォルトとなり、具体的な状況は検証されなくなります.defaultValueのデフォルト値
    \t\t
    \t\t
    \ue000\ue001\ue002
    \t\t\t\t
    について、なぜこのような文字列をデフォルトとして設定したのかが気になりました.今日やっと原因が分かりました.defaultValueのデフォルト値はValueConstants.DEFAULT_NONEの値と同じです.ValueConstantsのソースコードを見てください.
    package org.springframework.web.bind.annotation;
    public interface ValueConstants {
        /*
        * Constant defining a value for no default - as a replacement for
        * {@code null} which we cannot use in annotation attributes.
        * 

    This is an artificial arrangement of 16 unicode characters, * with its sole purpose being to never match user-declared values. */ String DEFAULT_NONE = "
    \t\t
    \t\t
    \ue000\ue001\ue002
    \t\t\t\t
    "; }

    は、注釈の属性にnullを使用して空の値を表現できないので、この16桁のUnicodeの文字列で空の値を表します.この文字列はユーザー定義の値と同じではないということです.ユーザから与えられた値が空の値として扱われることは避けられている.このような状況が発生する可能性があると思いますが、この値を故意に与えない限り、発生確率は非常に小さく、小さな確率のイベントです.
  • @ModelAttribute@ModelAttributeは次のような位置に置くことができます.
  • は、controlerの方法においてある.
  • は、方法のパラメータ上に配置される.
  • は方法の上に置いて、同時にこの方法の上にも@Request Mappingの注釈があります.
  • は、controllerの方法において、例:
    @Controller
    @RequestMapping("/test")
    public class TestController {
    
        @ModelAttribute
        public void test2(ModelAndView model){//     ModelAndView
            System.out.println("   @ModelAttribute     test2");
            model.addObject("name","parker");
        }
    
        @RequestMapping("/index")
        public ModelAndView test1(ModelAndView model){//     ModelAndView
            System.out.println("  test1  ");
            System.out.println("model.getModel().get(\"name\") = " + model.getModel().get("name"));
            System.out.println("model.getModel().get(\"string\") = " + model.getModel().get("string"));
            System.out.println("model.getModel().get(\"num\") = " + model.getModel().get("int"));
            return model;
        }
    
        @ModelAttribute
        public String test3(){
            System.out.println("   @ModelAttribute     test3");
            return "it's test3 test";
        }
    
        @ModelAttribute(value = "num")
        public int test4(@RequestAttribute("num") int num){
            System.out.println("   @ModelAttribute     test4");
            System.out.println("num = [" + num + "]");
            return num;
        }
    }
  • http://localhost:8080/test/index.action?num=6379にアクセスすると、コンソールの出力:
       @ModelAttribute     test2
       @ModelAttribute     test3
       @ModelAttribute     test4
    num = [6379]
      test1  
    model.getModel().get("name") = parker
    model.getModel().get("string") = null
    model.getModel().get("num") = null
    は以下の例を見ます.
    @Controller
    @RequestMapping("/test")
    public class TestController {
    
        @ModelAttribute
        public int test2(){
            System.out.println("   @ModelAttribute     test2");
            return 3306;
        }
    
        @RequestMapping("/index")
        public String test1(Model model){//     Model
            System.out.println("  test1  ");
            Map map = model.asMap();
            System.out.println("test2    :"+map.get("int"));
            System.out.println("test3    :"+map.get("string"));
            System.out.println("test4    :"+map.get("num"));
            return "index";
        }
    
        @ModelAttribute
        public String test3(){
            System.out.println("   @ModelAttribute     test3");
            return "it's test3 test";
        }
    
        @ModelAttribute(value = "num")
        public int test4(@RequestAttribute("num") int num){
            System.out.println("   @ModelAttribute     test4");
            System.out.println("num = [" + num + "]");
            return num;
        }
    }
    http://localhost:8080/test/index.action?num=6379にアクセスすると、コンソールの出力:
       @ModelAttribute     test2
       @ModelAttribute     test3
       @ModelAttribute     test4
    num = [6379]
      test1  
    test2    :3306
    test3    :it's test3 test
    test4    :6379
    は、まとめました.まず@ModelAttributeにマークされた方法を実行します.同一のcontrollerに複数の方法が@ModelAttributeに注釈されている場合、@ModelAttributeにマークされたすべての方法が実行され、クラスに出現した順序で実行され、最後にマッピングの方法が実行されます.また、@ModelAttributeで返却値を注釈する方法を使うと、戻り値の対象は暗黙的なModelにデフォルトで置かれ、Modelでのkeyは「戻り値の最初の文字小文字」(intタイプなどであれば、それ自体、intなど)であり、valueは戻り値であることを記事で見ました.前のテストのこの例では、ModelではなくModelAndViewを使っています.私たちの後のテストの例の出力を見て、状況が合っていることが分かりました.全体的には、@ModelAttributeはModelではなくModel AndViewで使用するのに適しています.
  • は、方法のパラメータ上に配置される.
    @Controller
    @RequestMapping("/test")
    public class TestController {
    
        @RequestMapping("/index")
        public String test1(@ModelAttribute("name")String s){
            System.out.println("  test1  ");
            System.out.println("s = [" + s + "]");
            return "index";
        }
    
        @ModelAttribute()
        public void test5(Model model){//     Model   ModelAndView
            System.out.println("  test5  ");
            model.addAttribute("name", "parker");
        }
    }
  • http://localhost:8080/test/index.actionにアクセスすると、コンソールの出力:
      test5  
      test1  
    s = [parker]
    総括:@ModelAttributeで注釈したパラメータを使って、前のModelから対応する名前の属性を抽出することができます.
  • は方法の上に置いて、同時にこの方法の上にも@Request Mappingの注釈の例があります:
    @Controller
    @RequestMapping("/test")
    public class TestController {
        @RequestMapping("/test")
        @ModelAttribute
        public String test6(){
            return "index";
        }
    }
  • このとき、test 6関数の戻り値indexは、ビューとしてではなく、valueとしてModelに入れられる.ビューは、ビュー名の一部として@RequestMapping("/test")の値testを使用する.ソース:
    @Target({ElementType.PARAMETER, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface ModelAttribute {
    /*
    Annotation that binds a method parameter or method return value to a named model attribute, exposed to a web view. Supported for controller classes with @RequestMapping methods.
    
    Can be used to expose command objects to a web view, using specific attribute names, through annotating corresponding parameters of an @RequestMapping method.
    
    Can also be used to expose reference data to a web view through annotating accessor methods in a controller class with @RequestMapping methods. Such accessor methods are allowed to have any arguments that @RequestMapping methods support, returning the model attribute value to expose.
    
    Note however that reference data and all other model content is not available to web views when request processing results in an Exception since the exception could be raised at any time making the content of the model unreliable. For this reason @ExceptionHandler methods do not provide access to a Model argument.
    */
    
        @AliasFor("name")
        String value() default "";
    
        @AliasFor("value")
        String name() default "";
    
        //Allows declaring data binding disabled directly on an @ModelAttribute method parameter or on the attribute returned from an @ModelAttribute method, both of which would prevent data binding for that attribute.
        boolean binding() default true;
    
    }
    nameとvalueの関係は@Request Attributeですでに言及しました.ここも同じです.もう説明しません.参考資料:
  • https://blog.csdn.net/harry_zhwang/articale/detail/57329613
  • https://blog.csdn.net/lovesomnus/article/details/78873089
  • @Session Attributeと@Session Attributesの違いは、役割…あとで補充します.nameとvalueの関係は@Request Attributeですでに言及しました.ここも同じです.もう説明しません.
  • @PathVarableのソースコード:
    @Target({ElementType.PARAMETER})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface PathVariable {
        @AliasFor("name")
        String value() default "";
    
        @AliasFor("value")
        String name() default "";
    
        //Defaults to true, leading to an exception being thrown if the path variable is missing in the incoming request. 
        //Switch this to false if you prefer a null or Java 8 java.util.Optional in this case. e.g. on a ModelAttribute method which serves for different requests.
        boolean required() default true;
    }
    nameとvalueの関係は@Request Attributeですでに言及しました.ここも同じです.もう説明しません.しかし、中のrequiredパラメータは探究する価値があります.requiredの値がtrueであろうとfalseであろうと、対応するパラメータが空であることは分かりません.
  • @Request Body@Request Bodyコメントは、HTTP要求本文を挿入する方法であり、適切なHttpMessage Coverterを使用して、要求体をあるオブジェクトに書き込みます.そして、@Resonsebodyは、この方法の戻りの結果を表して直接HTTP応答本文(ResonseBody)に書き込み、非同期でデータを取得する際に使用するのが一般的である.注意点:@Request Bodyは、HttpEntityから送られてきたデータを処理して、一般的には非Content-Type:appplication/x-wn-form-urlencoded符号化フォーマットのデータを処理します.
  • GET要求には、HttpEntityがないので、@Request Bodyは適用されません.
  • POST要求では、HttpEntityによって伝達されるパラメータは、要求ヘッダにデータのタイプContent-Typeを宣言しなければならず、SprigMVCは、HandlerAdapter構成のHttpMessage Covertersを使用して、HttpEntityにおけるデータを解析し、対応するbeanに結び付ける.
  • まとめ:
  • は、GET要求において、@Request Bodyを使用することができず、@Request Paramを使用することができる.
  • POSTで要求された場合、@Request Bodyと@Request Paramは使用できますが、@Request Bodyを使用すると、パラメータ変換の構成は統一されなければなりません.
  • ソース:
    @Target(ElementType.PARAMETER)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface RequestBody {
    
        /**
        * Whether body content is required.
        * 

    Default is {@code true}, leading to an exception thrown in case * there is no body content. Switch this to {@code false} if you prefer * {@code null} to be passed when the body content is {@code null}. * @since 3.2 */ boolean required() default true; }

    nameとvalueの関係は@Request Attributeですでに言及しました.ここも同じです.もう説明しません.
  • @Request Mappingのソースコード:
    @Target({ElementType.METHOD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Mapping
    public @interface RequestMapping {
    
        //Assign a name to this mapping.
        String name() default "";
    
        //The primary mapping expressed by this annotation.
        //This is an alias for path(). For example @RequestMapping("/foo") is equivalent to @RequestMapping(path="/foo").
        @AliasFor("path")
        String[] value() default {};
    
        //The path mapping URIs (e.g. "/myPath.do"). Ant-style path patterns are also supported (e.g. "/myPath/*.do"). At the method level, relative paths (e.g. "edit.do") are supported within the primary mapping expressed at the type level. Path mapping URIs may contain placeholders (e.g. "/${connect}").
        @AliasFor("value")
        String[] path() default {};
    
        RequestMethod[] method() default {};
    
        String[] params() default {};
    
        String[] headers() default {};
    
        String[] consumes() default {};
    
        String[] produces() default {};
    }
    ここで@Request Mappingを提出する理由は、属性nameとvalueの表現の意味が違っています.私たちの前提の3つの例とは違います.@Request Mappingでは、valueとpathは等価であり、いずれも経路マッピングを表すものである.nameはこのマッピングの名前を表していますが、実際の役割はありません.このマッピングのコメントとして考えられます.
  • @Cookie Valueを追加します.
  • @Request Headerは後で補充します.