Spring boot series of tutorials: custom request matching conditionrequestcondition

Time:2020-6-3

Spring boot series of tutorials: custom request matching conditionrequestcondition

191222 spring boot series of tutorials: custom request matching conditionrequestcondition

In spring MVC, we know that user initiated requests can be matched by URL to our@RequestMappingOn the defined service endpoint; I don’t know if there are any questions you have thought about

Can there be exactly the same URL in a project?

Students who know HTTP protocol may be able to give the answer soon. Of course, the URL is the same, and the request method is different. Can there be the same URL and the request method l?

This article will show you how to useRequestConditioncombinationRequestMappingHandlerMappingTo implement the extension of URL matching rules, so as to support the case proposed above

<!– more –>

1. Environment related

The content of this article and the actual case will be based onspring-boot-2.2.1.RELEASEVersion. If you find that some places cannot be compatible during testing, please confirm the version

1. Project construction

First of all, we need to build a web project to facilitate the demonstration of the following servelt registration examples. You can create a project through the spring boot official website, or you can build a maven project pom.xml In the following configuration

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.1.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.8</java.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </pluginManagement>
</build>
<repositories>
    <repository>
        <id>spring-snapshots</id>
        <name>Spring Snapshots</name>
        <url>https://repo.spring.io/libs-snapshot-local</url>
        <snapshots>
            <enabled>true</enabled>
        </snapshots>
    </repository>
    <repository>
        <id>spring-milestones</id>
        <name>Spring Milestones</name>
        <url>https://repo.spring.io/libs-milestone-local</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
    <repository>
        <id>spring-releases</id>
        <name>Spring Releases</name>
        <url>https://repo.spring.io/libs-release-local</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
</repositories>

2. Introduction to requestcondition

In spring MVC, throughDispatchServletAfter receiving a request from the client, the corresponding request processor will be obtained through handermapping. How can handermapping find the processor that can handle the request? This needs to be determined by the requestcondition

The interface is defined as follows. There are three main methods,

public interface RequestCondition<T> {

    //Used for merging when there are multiple conditional rules on an HTTP interface
    T combine(T other);

    //This is the key point, which is used to judge whether the current matching condition and the request match; if not, null is returned
    //If matching, a new request matching condition is generated, which is the clipping of the current request matching condition to the specified request request
    //For example, if the current request matching condition is a path matching condition, including multiple path matching templates,
    //If some of the templates match the specified request, the returned new request matching criteria will only
    //Contains those path templates that match the specified request request.
    @Nullable
    T getMatchingCondition(HttpServletRequest request);

    //For the specified request object request, it is found that there are multiple satisfied conditions, which are used to sort the specified priority and use the best to respond
    int compareTo(T other, HttpServletRequest request);

}

In short, the function of the three interfaces

  • combine: when an interface has multiple rules, merge them – for example, specified on the class@RequestMappingThe URL of isroot-And the@RequestMappingThe URL of ismethod-In order to obtain the URL matching rules of this interface, scan once on the class and once on the method. At this time, you need to merge the two into one to indicate the interface matchingroot/method
  • getMatchingCondition: – judge whether it is successful or not, and return null in case of failure; otherwise, return the condition of matching success
  • compareTo: – when multiple conditions are met, it is used to specify which one to select

In spring MVC, the following are provided by default

class explain
PatternsRequestCondition Path matching, i.e. URL
RequestMethodsRequestCondition Request method. Note that it refers to HTTP request method
ParamsRequestCondition Request parameter condition match
HeadersRequestCondition Request header match
ConsumesRequestCondition Consumable mime matching criteria
ProducesRequestCondition Mime matching criteria can be generated

2. Example description

It may not be easy to understand how to use it simply by looking at the description. Next, we will demonstrate the use of posture through a practical case

1. Scene description

We have a service for three platforms: APP / WAP / PC. we want to specify some interfaces to only provide services for specific platforms

2. Implementation

First, we define thex-platformTo distinguish platforms, the user needs to carry the request header in the request

Define platform enumeration class

public enum PlatformEnum {
    PC("pc", 1), APP("app", 1), WAP("wap", 1), ALL("all", 0);

    @Getter
    private String name;

    @Getter
    private int order;

    PlatformEnum(String name, int order) {
        this.name = name;
        this.order = order;
    }

    public static PlatformEnum nameOf(String name) {
        if (name == null) {
            return ALL;
        }

        name = name.toLowerCase().trim();
        for (PlatformEnum sub : values()) {
            if (sub.name.equals(name)) {
                return sub;
            }
        }
        return ALL;
    }
}

Then define an annotation@PlatformIf an interface needs to specify a platform, add this annotation

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Platform {
    PlatformEnum value() default PlatformEnum.ALL;
}

Define matching rulesPlatformRequestConditionInherited fromRequestCondition, implements three interfaces, obtains the platform from the request header, and determines whether the request can be supported according to whether the platforms are the same

public class PlatformRequestCondition implements RequestCondition<PlatformRequestCondition> {
    @Getter
    @Setter
    private PlatformEnum platform;

    public PlatformRequestCondition(PlatformEnum platform) {
        this.platform = platform;
    }

    @Override
    public PlatformRequestCondition combine(PlatformRequestCondition other) {
        return new PlatformRequestCondition(other.platform);
    }

    @Override
    public PlatformRequestCondition getMatchingCondition(HttpServletRequest request) {
        PlatformEnum platform = this.getPlatform(request);
        if (this.platform.equals(platform)) {
            return this;
        }

        return null;
    }

    /**
     *Priority
     *
     * @param other
     * @param request
     * @return
     */
    @Override
    public int compareTo(PlatformRequestCondition other, HttpServletRequest request) {
        int thisOrder = this.platform.getOrder();
        int otherOrder = other.platform.getOrder();
        return otherOrder - thisOrder;
    }

    private PlatformEnum getPlatform(HttpServletRequest request) {
        String platform = request.getHeader("x-platform");
        return PlatformEnum.nameOf(platform);
    }
}

After the matching rules are specified, they need to be registered on handlermapping to take effect. Here we customize aPlatformHandlerMapping

public class PlatformHandlerMapping extends RequestMappingHandlerMapping {
    @Override
    protected RequestCondition<?> getCustomTypeCondition(Class<?> handlerType) {
        return buildFrom(AnnotationUtils.findAnnotation(handlerType, Platform.class));
    }

    @Override
    protected RequestCondition<?> getCustomMethodCondition(Method method) {
        return buildFrom(AnnotationUtils.findAnnotation(method, Platform.class));
    }

    private PlatformRequestCondition buildFrom(Platform platform) {
        return platform == null ? null : new PlatformRequestCondition(platform.value());
    }
}

Finally, we need to register our handlermapping to the spring MVC container. Here we use theWebMvcConfigurationSupportTo register manually (note that the following methods may be different for different versions)

@Configuration
public class Config extends WebMvcConfigurationSupport {
    @Override
    public RequestMappingHandlerMapping requestMappingHandlerMapping(
            @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
            @Qualifier("mvcConversionService") FormattingConversionService conversionService,
            @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
        PlatformHandlerMapping handlerMapping = new PlatformHandlerMapping();
        handlerMapping.setOrder(0);
        handlerMapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));
        return handlerMapping;
    }
}

3. Test

Next, enter the measurement phase, define several interfaces, and specify different platforms respectively

@RestController
@RequestMapping(path = "method")
public class DemoMethodRest {
    @Platform
    @GetMapping(path = "index")
    public String allIndex() {
        return "default index";
    }

    @Platform(PlatformEnum.PC)
    @GetMapping(path = "index")
    public String pcIndex() {
        return "pc index";
    }


    @Platform(PlatformEnum.APP)
    @GetMapping(path = "index")
    public String appIndex() {
        return "app index";
    }

    @Platform(PlatformEnum.WAP)
    @GetMapping(path = "index")
    public String wapIndex() {
        return "wap index";
    }
}

If our rules can take effect normally, different rules are set in the request headerx-platform, the returned results should be different. The measured results are as follows

Spring boot series of tutorials: custom request matching conditionrequestcondition

Note that the last two, one is to specify a request header that does not match our platform, and the other is that there is no corresponding request header, all of which follow the default matching rules. This is because we havePlatformRequestConditionWhen the platform cannot be matched, it is assigned to the defaultPlatform.ALL

Then there’s a little question. If there’s a service that doesn’t differentiate between platforms, don’t add@PlatformIs annotation OK?

@GetMapping(path = "hello")
public String hello() {
    return "hello";
}

Of course, the measured results are as follows:

Spring boot series of tutorials: custom request matching conditionrequestcondition

Without adding@PlatformWhen annotating, it should be noted that multiple URLs and the same request method cannot appear at this time. Exceptions will be thrown directly at startup

Spring boot series of tutorials: custom request matching conditionrequestcondition

3. Others

Web series blog

  • Four kinds of registration postures of listener in web part of 191206 spring boot series
  • Four postures of servlet registration in 191122 spring boot series
  • Open gzip data compression in web part of 191120 spring boot series
  • 191018 spring boot series of tutorials web chapter filter user guide extension
  • 191016 spring boot series tutorials filter guide in Web
  • Handlerexceptionresolver for custom exception handling in the web part of the 191012 spring boot series
  • Global exception handling in the web part of the 191010 spring boot series
  • The 404 and 500 abnormal page configuration of the 190930 spring boot series
  • Redirection of web part of 190929 spring boot series
  • 190913 spring boot series of tutorials: return text, web page, picture operation posture
  • 190905 spring boot series of tutorials: how to solve the problem of Chinese scrambling
  • How to customize parameter resolver in the web part of 190831 spring boot series
  • Post request parameter parsing posture summary of 190828 spring boot series Web
  • Get request parameter parsing posture summary of 190824 spring boot series Web
  • 190822 spring boot series of tutorials: building the Beetl environment in the web chapter
  • Building the thymeleaf environment in the web part of the 190820 spring boot series
  • 190816 spring boot series of tutorials: freemaker environment construction in Web chapter
  • Instructions for using websocket in 190421 spring boot advanced web
  • 190327 spring resttemplate’s URLEncode parameter parsing exception full process analysis
  • 190317 spring MVC web application construction based on Java config without XML configuration
  • 190316 spring MVC web application construction based on XML configuration
  • The temporary upload location XXX is not valid

Project source code

  • Project: https://github.com/liuyueyi/spring-boot-demo
  • Project: https://github.com/liuyueyi/spring-boot-demo/blob/master/spring-boot/208-web-mapping

1. A grey blog

The best letter is not as good as the above. It’s just a one-of-a-kind remark. Due to the limited personal ability, there are inevitably omissions and mistakes. If you find a bug or have better suggestions, you are welcome to criticize and correct. Thank you very much

Here is a grey personal blog, recording all the blogs in study and work. Welcome to visit

  • A grey blog personal blog https://blog.hhui.top
  • A grey blog spring special blog http://spring.hhui.top

Spring boot series of tutorials: custom request matching conditionrequestcondition

Recommended Today

The use of springboot Ajax

Ajax overview What is Ajax? data Ajax application scenarios? project Commodity system. Evaluation system. Map system. ….. Ajax can only send and retrieve the necessary data to the server, and use JavaScript to process the response from the server on the client side. data But Ajax technology also has disadvantages, the biggest disadvantage is that […]