Självstudie: Använda variantfunktionsflaggor i ett Spring Boot-program

I den här självstudien använder du en variantfunktionsflagga för att hantera upplevelser för olika användarsegment i ett exempelprogram, Quote of the Day. Du använder den variantfunktionsflagga som skapats i Använd variantfunktionsflaggor. Innan du fortsätter måste du skapa variantfunktionsflaggan Greeting i din App Configuration-butiken.

Förutsättningar

Konfigurera en Spring Boot-webbapp

Om du redan har en Spring Boot-webbapp med autentisering kan du gå vidare till avsnittet Använd variantfunktionsflaggan .

  1. Bläddra till Spring Initializr och skapa ett nytt projekt med följande alternativ:

    • Generera ett Maven--projekt med Java-.
    • Ange en Spring Boot-version som är 3.0 eller senare.
    • Ange Gruppen till com.example och Artefakt till quoteoftheday.
    • Lägg till Spring Web- och Thymeleaf-beroenden .
  2. När du har angett alternativen väljer du Generera för att ladda ned projektet. Extrahera filerna till ditt lokala system.

Skapa appen Citat för dagen

  1. Skapa en ny fil med namnet Quote.java i src/main/java/com/example/quoteoftheday mappen med följande innehåll. Den definierar en dataklass för citattecken.

    package com.example.quoteoftheday;
    
    public record Quote(String message, String author) {
    }
    
  2. Skapa en ny fil med namnet HomeController.java med följande innehåll. Den hanterar startsidans visning med ett slumpmässigt citat.

    package com.example.quoteoftheday;
    
    import java.util.List;
    import java.util.Random;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.GetMapping;
    
    @Controller
    public class HomeController {
    
        private final List<Quote> quotes = List.of(
                new Quote("You cannot change what you are, only what you do.", "Philip Pullman"));
    
        private final Random random = new Random();
    
        @GetMapping("/")
        public String index(Model model) {
            String greetingMessage = "Hi";
            model.addAttribute("greetingMessage", greetingMessage);
            model.addAttribute("quote", quotes.get(random.nextInt(quotes.size())));
    
            return "index";
        }
    }
    
  3. Skapa mallkatalogensrc/main/resources/templates och lägg till en ny fil med namnet index.html med följande innehåll:

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>QuoteOfTheDay</title>
        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
            integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
        <link rel="stylesheet" th:href="@{/css/site.css}">
        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css">
    </head>
    <body>
        <header>
            <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
                <div class="container">
                    <a class="navbar-brand" href="/">QuoteOfTheDay</a>
                    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse"
                        aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
                        <span class="navbar-toggler-icon"></span>
                    </button>
                </div>
            </nav>
        </header>
        <div class="container">
            <main role="main" class="pb-3">
                <div class="quote-container">
                    <div class="quote-content">
                        <h3 class="greeting-content" th:if="${greetingMessage}" th:text="${greetingMessage}"></h3>
                        <br />
                        <p class="quote">"<span th:text="${quote.message}"></span>"</p>
                        <p>- <b th:text="${quote.author}"></b></p>
                    </div>
    
                    <div class="vote-container">
                        <button class="btn btn-primary" onclick="heartClicked(this)">
                            <i class="far fa-heart"></i>
                        </button>
                    </div>
                </div>
            </main>
        </div>
        <footer class="border-top footer text-muted">
            <div class="container">
                &copy; 2024 - QuoteOfTheDay
            </div>
        </footer>
        <script src="https://code.jquery.com/jquery-3.7.1.min.js"
            integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script>
        <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"
            integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz"
            crossorigin="anonymous"></script>
        <script>
            function heartClicked(button) {
                var icon = button.querySelector('i');
                icon.classList.toggle('far');
                icon.classList.toggle('fas');
            }
        </script>
    </body>
    </html>
    
  4. Skapa katalogen static/csssrc/main/resources/static/css och lägg till en ny fil med namnet site.css med följande innehåll:

    html {
        font-size: 14px;
    }
    
    @media (min-width: 768px) {
        html {
            font-size: 16px;
        }
    }
    
    .btn:focus,
    .btn:active:focus,
    .btn-link.nav-link:focus,
    .form-control:focus,
    .form-check-input:focus {
        box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
    }
    
    html {
        position: relative;
        min-height: 100%;
    }
    
    body {
        margin-bottom: 60px;
    }
    
    body {
        font-family: Arial, sans-serif;
        background-color: #f4f4f4;
        color: #333;
    }
    
    .quote-container {
        background-color: #fff;
        margin: 2em auto;
        padding: 2em;
        border-radius: 8px;
        max-width: 750px;
        box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.2);
        display: flex;
        justify-content: space-between;
        align-items: start;
        position: relative;
    }
    
    .vote-container {
        position: absolute;
        top: 10px;
        right: 10px;
        display: flex;
        gap: 0em;
    }
    
    .vote-container .btn {
        background-color: #ffffff;
        border-color: #ffffff;
        color: #333
    }
    
    .vote-container .btn:focus {
        outline: none;
        box-shadow: none;
    }
    
    .vote-container .btn:hover {
        background-color: #F0F0F0;
    }
    
    .greeting-content {
        font-family: 'Georgia', serif;
    }
    
    .quote-content p.quote {
        font-size: 2em;
        font-family: 'Georgia', serif;
        font-style: italic;
        color: #4EC2F7;
    }
    
  5. Uppdatera filen application.propertiessrc/main/resources/application.properties med följande innehåll:

    spring.application.name=quoteoftheday
    

Använd variantfunktionsflaggan

  1. Öppna filenpom.xml och lägg till följande beroenden för Azure App Configuration och funktionshantering:

    <dependency>
        <groupId>com.azure.spring</groupId>
        <artifactId>spring-cloud-azure-starter-appconfiguration-config</artifactId>
    </dependency>
    
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.azure.spring</groupId>
                <artifactId>spring-cloud-azure-dependencies</artifactId>
                <version>7.0.0</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    
  2. Uppdatera filen application.propertiessrc/main/resources/application.properties för att lägga till Inställningar för Azure App Configuration:

    Du kan ansluta till din App Configuration-butik med hjälp av Microsoft Entra-ID (rekommenderas) eller en anslutningssträng.

    spring.config.import=azureAppConfiguration
    spring.cloud.azure.appconfiguration.stores[0].endpoint=${APP_CONFIGURATION_ENDPOINT}
    spring.cloud.azure.appconfiguration.stores[0].feature-flags.enabled=true
    

    Du använder DefaultAzureCredential för att autentisera mot din App Configuration-butik. Följ anvisningarna för att tilldela dina autentiseringsuppgifter rollen App Configuration Data Reader . Se till att ge tillräckligt med tid för att behörigheten ska spridas innan du kör programmet.

  3. Skapa en ny fil med namnet QueryStringTargetingContextAccessor.java för att ange målkontexten för den aktuella användaren:

    package com.example.quoteoftheday;
    
    import org.springframework.stereotype.Component;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;
    
    import com.azure.spring.cloud.feature.management.targeting.TargetingContext;
    import com.azure.spring.cloud.feature.management.targeting.TargetingContextAccessor;
    
    @Component
    public class QueryStringTargetingContextAccessor implements TargetingContextAccessor {
    
        @Override
        public void configureTargetingContext(TargetingContext context) {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
                    .getRequestAttributes();
            if (attributes != null) {
                String userId = attributes.getRequest().getParameter("userId");
                if (userId != null) {
                    context.setUserId(userId);
                }
            }
        }
    }
    
  4. Uppdatera HomeController.java för att använda variantfunktionsflaggan:

    package com.example.quoteoftheday;
    
    import java.util.List;
    import java.util.Random;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.GetMapping;
    
    import com.azure.spring.cloud.feature.management.FeatureManager;
    import com.azure.spring.cloud.feature.management.models.Variant;
    
    @Controller
    public class HomeController {
    
        private static final Logger LOGGER = LoggerFactory.getLogger(HomeController.class);
    
        private final FeatureManager featureManager;
    
        private final List<Quote> quotes = List.of(
                new Quote("You cannot change what you are, only what you do.", "Philip Pullman"));
    
        private final Random random = new Random();
    
        public HomeController(FeatureManager featureManager) {
            this.featureManager = featureManager;
        }
    
        @GetMapping("/")
        public String index(Model model) {
            // Get the variant for the Greeting feature flag
            String greetingMessage = "";
            Variant variant = featureManager.getVariant("Greeting");
            if (variant != null) {
                Object value = variant.getValue();
                if (value != null) {
                    greetingMessage = value.toString();
                }
            } else {
                LOGGER.warn(
                        "No variant given. Either the feature flag named 'Greeting' is not defined or the variants are not defined properly.");
            }
    
            model.addAttribute("greetingMessage", greetingMessage);
            model.addAttribute("quote", quotes.get(random.nextInt(quotes.size())));
    
            return "index";
            }
    }
    

Skapa och köra appen

  1. Ange en miljövariabel.

    Ange miljövariabeln med namnet APP_CONFIGURATION_ENDPOINT till slutpunkten för din App Configuration-lagring som finns under Översikt i Azure-portalen.

    Om du använder Windows-kommandotolken kör du följande kommando och startar om kommandotolken så att ändringen börjar gälla:

    setx APP_CONFIGURATION_ENDPOINT "<endpoint-of-your-app-configuration-store>"
    

    Om du använder PowerShell kör du följande kommando:

    $Env:APP_CONFIGURATION_ENDPOINT = "<endpoint-of-your-app-configuration-store>"
    

    Om du använder macOS eller Linux kör du följande kommando:

    export APP_CONFIGURATION_ENDPOINT='<endpoint-of-your-app-configuration-store>'
    
  2. Skapa och kör ditt Spring Boot-program med Maven:

    mvn clean package
    mvn spring-boot:run
    
  3. Vänta tills appen startas och öppna sedan en webbläsare och navigera till http://localhost:8080/. Du bör se standardvyn för appen som inte har något hälsningsmeddelande.

    Skärmbild av appen Offert för dagen som inte visar något hälsningsmeddelande för användaren.

  4. Du kan använda userId frågeparametern i URL:en för att ange användar-ID:t. Besök localhost:8080/?userId=UserA och du ser ett långt hälsningsmeddelande.

    Skärmbild av appen Citat för dagen som visar ett långt hälsningsmeddelande till användaren.

  5. Prova olika användar-ID:er för att se hur variantfunktionsflaggan ändrar hälsningsmeddelandet för olika användarsegment. Besök localhost:8080/?userId=UserB och du ser ett kortare hälsningsmeddelande.

    Skärmbild av appen Offert för dagen som visar ett enkelt hälsningsmeddelande för användaren.

Nästa steg

Den fullständiga funktionskörningen av Spring Boot-funktionshanteringsbiblioteket finns i följande dokument.