Vraag Howto schrijf aangepaste checks / validatie voor het speel-framework


Ik probeer cheques te schrijven voor de play-framework en zie twee verschillende mogelijkheden. Ik heb beide beschreven en wil weten of mijn begrip klopt (dus het is meer een tutorial dan een vraag, vooral omdat ik geen reactie kreeg dat ik iets miste). Dus welke mogelijkheden zijn er.

  1. De eenvoudige manier: de klas uitbreiden Check:
    Voordelen: gemakkelijker te schrijven, gemakkelijker te lezen
    Nadelen: u kunt de controle niet parametreren, u kunt alleen het bericht definiëren.
  2. De geavanceerde manier: een cheque schrijven op basis van OVal AbstractAnnotationCheck.
    Voordelen: u kunt de controle parametreren en een eenvoudigere annotatie gebruiken
    Nadelen: een beetje ingewikkelder.

Voordat we de implementatie bekijken, wil ik de berichten uitleggen. U kunt het bericht altijd rechtstreeks instellen of een toets gebruiken om het bericht door te verwijzen in een berichteigenschap. De laatste is de schonere en aanbevolen manier. Elke validatie krijgt ten minste 1 parameter: de naam van de eigenschap die niet geldig is. Dus validatie of check specifieke parameters worden altijd doorverwezen %i$s waar ik> 1. Het formaat van de berichtstring moet de regels volgen van formatter maar ik weet niet of alle functies worden ondersteund. Voor zover ik weet, worden alleen% s,% d en% f ondersteund met positionering. Zo %[argument_index$][flags]conversion waar conversie alleen s, d of f kon zijn.

Laten we twee voorbeelden bekijken: De eenvoudige manier die ik in mijn module heb gebruikt voor een optimistische vergrendeling:

/**
 * Check with proof if the version of the current edited object is lesser
 * than the version in db.
 * Messagecode: optimisticLocking.modelHasChanged
 * Parameter: 1 the request URL.
 * Example-Message: The object was changed. <a href="%2$s">Reload</a> and do your changes again.
 *
 */
static class OptimisticLockingCheck extends Check {

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean isSatisfied(Object model, Object optimisiticLockingViolatedValue) {
        //The comparision of version was made in the setter. Here
        //we only have to check the flag.
        if (((VersionedModel) model).optimisiticLockingViolated) {
            final Request request = Request.current();
            //The following doesn't work in 1.0 but in 1.1 see https://bugs.launchpad.net/play/+bug/634719
            //http://play.lighthouseapp.com/projects/57987-play-framework/tickets/116
            //setMessage(checkWithCheck.getMessage(), request != null ? request.url : "");
            setMessage("optimisticLocking.modelHasChanged", request != null ? request.url : ""); 

        }
        return !((VersionedModel) model).optimisiticLockingViolated;
    }
}

U gebruikt deze controle met de annotatie @CheckWith(value=OptimisticLockingCheck.class, message="optimisticLocking.modelHasChanged")

Dus laten we eens kijken hoe het werkt. Het enige dat we moeten doen is de klasse play.data.validation uitbreiden. Controleer en overschrijf de isSatisfied-methode. Daar krijg je je model en de waarde van de eigenschappen. Het enige wat je hoeft te doen is om waar terug te geven als alles in orde is of anderszins fout. In ons geval willen we de huidige URL als parameter instellen. Deze kan eenvoudig worden gedaan door setMessage () aan te roepen. We geven het bericht of de berichtsleutel die is gedefinieerd in de berichteigenschappen en de parameters. Onthoud dat we slechts 1 parameter opgeven, maar verwezen als met% 2 $ s, omdat de eerste parameter altijd de naam van de eigenschap is.

Nu de complexe manier op basis van de bereikcontrole van het spel: Eerst moeten we een annotatie definiëren

/**
 * This field must be lower than and greater than.
 * Message key: validation.range
 * $1: field name
 * $2: min reference value
 * $3: max reference value
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Constraint(checkWith = RangeCheck.class)
public @interface Range {

    String message() default RangeCheck.mes;
    double min() default Double.MIN_VALUE;
    double max() default Double.MAX_VALUE;
}

en dan de cheque

@SuppressWarnings("serial")
public class RangeCheck extends AbstractAnnotationCheck<Range> {

    final static String mes = "validation.range";

    double min;
    double max;

    @Override
    public void configure(Range range) {
        this.min = range.min();
        this.max = range.max();
        setMessage(range.message());
    }

    public boolean isSatisfied(Object validatedObject, Object value, OValContext context, Validator validator) {
        requireMessageVariablesRecreation();
        if (value == null) {
            return true;
        }
        if (value instanceof String) {
            try {
                double v = Double.parseDouble(value.toString());
                return v >= min && v <= max;
            } catch (Exception e) {
                return false;
            }
        }
        if (value instanceof Number) {
            try {
                return ((Number) value).doubleValue() >= min && ((Number) value).doubleValue() <= max;
            } catch (Exception e) {
                return false;
            }
        }
        return false;
    }

    @Override
    public Map<String, String> createMessageVariables() {
        Map<String, String> messageVariables = new TreeMap<String, String>();
        messageVariables.put("2-min", Double.toString(min));
        messageVariables.put("3-max", Double.toString(max));
        return messageVariables;
    }

}

OK, ik denk dat de annotatie niet moet worden uitgelegd. Laten we kijken naar de cheque. In dit geval gaat het verder net.sf.oval.configuration.annotation.AbstractAnnotationCheck. We moeten een configure-methode schrijven waarin we de annotatie krijgen en de parameters kunnen kopiëren. Vervolgens moeten we onze cheque definiëren. Dat is analoog aan de implementatie van de andere cheque. Dus we schrijven alleen onze conditie en geven waar of niet waar terug, behalve één speciale regel! Als we een geparametriseerd bericht gebruiken, moeten we bellen requireMessageVariablesRecreation(); in onze methode. We moeten tenminste de methode negeren createMessageVariables. Hier moeten we een klein beetje spel-kennis krijgen (alle andere dingen worden beschreven hier). Je plaatst je berichten in een kaart met een sleutel en waarde, maar spelen neemt alleen de waarden aan (zie ValidCheck.javain kadercode). Dus wordt er naar positie verwezen. Dit is de reden dat ik de implementatie van de. Heb gewijzigd RangeCheck gebruik makend van TreeMap in plaats van HashMap. Verder laat ik de toetsen beginnen met de index waarnaar ze kunnen verwijzen.

Dus ik hoop dat dit het duidelijker maakt om aangepaste validaties / cheques voor het spel te schrijven. Ik hoop dat de beschrijving correct is. Daarom is de vraag of mijn begrip juist is?


19
2017-09-11 09:30


oorsprong


antwoorden:


Je eerste voorbeeld lijkt tenminste op het juiste pad te zijn. Je kunt het vergelijken met de onderstaande documentatie, maar ik neem aan dat je voorbeeld zo ingewikkeld is dat je er al naar hebt verwezen.

http://www.playframework.org/documentation/1.1/validation#custom

Ik weet niet genoeg over het speelraamwerk om commentaar te geven op het tweede voorbeeld.


1
2017-11-04 16:13