samedi 30 décembre 2017

Spring Data: Sécuriser le trie

Spring Data permet de simplifier différentes opérations telles que les requêtes, les tries et la pagination.

L'objet Pageable contient tous le nécessaire pour supporter un grid html. Les champs à trier, l'ordre du trie, le nombre de donnée maximale à afficher...

Spring Data n'est que pour la partie serveur. Si aucune vérification n'est effectuée du côté du serveur et que le champs est inexistant ou si vous utilisez un dto avec une structure différente de votre bean, une exception sera lancée.

@GetMapping(value = "/members")
public Page<MemberDto> getPagingMembers(String search, Pageable pageRequest) {
    return memberService.getMembers(search, pageRequest);
}

@GetMapping(value = "/members")
public Page<MemberDto> getPagingMembers(String search, Pageable pageRequest) {
    Pageable newPageRequest = BindingPageRequestHelpler.binding(BindingPageRequestHelpler.memberPageRequestSort(), pageRequest);
    return memberService.getMembers(search, newPageRequest);
}
 
Un moyen simple est decréer une classe qui remplacera le nom du champsreçu du côté web avec celui qui lui est lié du côté serveur.

Un dto nommé memberDto pourrait avoir un champ id et un champ name.
Le bean aura un champs memberId et un champ name;

public class BindingPageRequestHelpler {

    public static Map<String, String> memberPageRequestSort() {
        return Collections.unmodifiableMap(Stream.of(
            new SimpleEntry<>("Id", "memberId"),
            new SimpleEntry<>("name", "name"))
            .collect(Collectors.toMap((e) -> e.getKey(), (e) -> e.getValue())));
    }

    public static Pageable binding(Map<String, String> pageRequestSort, Pageable pageRequest) {

        Sort sort = pageRequest.getSort();
        PageRequest newPageRequest = null;
        List<Order> newOrders = new ArrayList<>();

        for (Iterator<Order> orderIterator = sort.iterator(); orderIterator.hasNext();) {
            Order order = orderIterator.next();
            String column = pageRequestSort.get(order.getProperty());
            if (column != null) {
                Order newOrder = new Order(order.getDirection(), column);
                newOrders.add(newOrder);
            }
            Sort newSorts = new Sort(newOrders);
            newPageRequest = new PageRequest(pageRequest.getPageNumber(), pageRequest.getPageSize(), newSorts);
        }
        return newPageRequest;
    }
}
Cette classe permet rapidement d'éviter de se rendre jusqu'à la couche DAO pour avoir une erreur.

Spring Microservices in Action

Spring Microservices in Action est un livre qui s'adresse aux gens désirant se lancer dans le développement de microservice à l'aide des technologies de Spring. Il couvre les différentes sujets reliés au microservice: sécurité, load balancing, circuit breaker, log... Lorsque plus d'une librairie est utilisable au sein du framework Spring, l'auteur explique les avantages et inconvénients de chacune.

Le framework spring cloud utilise des librarie déjà éprouvé tel que celle de netflix. Peu de configuration est nécessaire.

L'auteur utilise l'exemple du passage d'une application monolithique à une architecture microsrevice tout au long du livre.

J'ai trouvé que le livre se lisait assez bien. L'auteur tout le sujet des microservice en général et il permet de se lancer en la création d'un système avec les bases apprises. Énormément d'annotations sont employés au sein de Spring. Une fois les concepts bien compris, il est possible de créer une application rapidement.

L'auteur utilise des images docker, il est donc possible de passer aisément d'un chapitre à un autre si on maitrise déjà la matière.

Je recommende fortement ce livre à tous ceux désirant se lancer dans les microservices à l'ade du framework Spring.

jeudi 19 octobre 2017

Utilisation d'annoation @Value dans Spring

Lorsque vous utilisez un fichier properties par exemple

message.text=bonjour
display.message=true

il est possible d'accéder à ces valeurs en utilisant l'annotation @Value

@Value("${message.text:default value}") 
private String messageText;


@Value("${display.message:true}") 
private boolean displayMessage;

lundi 5 décembre 2016

Télécharger un fichier sécurisé avec spring

Nous allons montrer comment accéder à un document sécurisé.

Lorsque l'utilisateur cliquera sur un bouton, il y aura appel sur le serveur qui génèrera un PDF.
Le fichier ouvrira dans un autre onglet.

   $("#memberContractPrintReport").on('click', function (e) {
        openDocument(getHostName() + "/report/document/contracts");
    });


   function openDocument(urlServer) {
        var win = window.open('_blank');
        downloadFile(urlServer, function (blob) {
            var url = URL.createObjectURL(blob);
            win.location = url;
        });
    }

    function downloadFile(url, success) {
        var xhr = new XMLHttpRequest();
        xhr.open('GET', url, true);
        xhr.setRequestHeader("Authorization", "Basic " + $.cookie('norcoption-authorization'));
        xhr.responseType = "blob";
        xhr.onreadystatechange = function () {
            if (xhr.readyState == 4) {
                if (success)
                    success(xhr.response);
            }
        };
        xhr.send(null);
    }

Maintenant la partie Java

   @GetMapping(value = "/report/document/contracts", produces = "application/pdf")
    public ResponseEntity<byte[]> getContractReport() throws IOException {
        byte[] content = reportService.generateContractReport();
        return prepareReport(content);
    }

    private ResponseEntity<byte[]> prepareReport(byte[] content) throws IOException {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.parseMediaType("application/pdf"));
        String filename = "report.pdf";
        headers.setContentDispositionFormData(filename, filename);
        headers.setCacheControl("must-revalidate, post-check=0, pre-check=0");
        ResponseEntity<byte[]> response = new ResponseEntity<byte[]>(content, headers, HttpStatus.OK);
        return response;
    }

Bootstrap-Table et le paging avec spring.

Nous allons voir comment mettre en place un bootstrap table avec le paging de spring data.
La pagination se fait du côté serveur

La première partie consiste à créer le tableau

  <table id="memberReportTableResult"
               style="min-height:100"
               data-search="true"
               data-classes="table table-no-bordered"
               data-height="600"
               data-pagination="true"
               data-side-pagination="server"
               data-sort-name="memberId"
               data-sort-order="desc">
        <thead>
            <tr>
                <th data-field="memberId" data-sortable="true">#</th>
                <th data-field="name" data-sortable="true">Nom</th>
                <th data-field="birthdate" data-formatter="localDateFormatter">Date de naissance</th>
                <th data-field="address" >Adresse</th>
                <th data-field="cityId" data-formatter="cityFormatter">Ville</th>
                <th data-field="postalCode" >Code postal</th>
                <th data-field="man" data-formatter="sexeFormatter" data-width="50px">Sexe</th>
                <th data-field="email">Courriel</th>
                <th data-field="phone1">Tél</th>
            </tr>
        </thead>
    </table>

Ensuite il faut effectuer l'initialisation en Javascript. C'est dans les fonctions de responseHandler et de queryParams qu'on lie les valeurs du composants table à ceux du paging.

$("#memberReportTableResult").bootstrapTable({
url: "http://localhost:8080/members",
queryParamsType: "",
ajaxOptions: {headers: {"Authorization": "Basic " + $.cookie('authorization')}},
responseHandler: function (res) {
return {
rows: res.content,
total: res.totalElements,
pageNumber: res.number,
pageSize: res.size
};
},
queryParams: function (params) {
return {
search: params.searchText,
page: params.pageNumber - 1,
size: params.pageSize,
sort: params.sortName + "," + params.sortOrder
};
}

});

Maintenant voyons la partie java

  @GetMapping(value = "/members")
    public Page<MemberDto> getPagingMembers(String search, Pageable pageRequest) {
        return memberService.getMembers(search, pageRequest);
    }

Nous avons pu voir rapidement comment faire le pont entre le paging de spring et le bootstrap table. Il suffit de relier les noms adéquats entre eux.

mardi 9 août 2016

Utilisez des ressources avec spring

Afin d'utiliser les ressources dans une application Spring, il faut créer un répertoire i18n dans le répertoire ressources.

Créer un fichier pour la langue par défaut et ensuite un par langue qui sera supporté.

messages.properties
messages_fr.properties

Le contenu du premier fichier serait

paymentMode.CASH=Cash
paymentMode.DEBIT=Debit
paymentMode.CHECK=Check
paymentMode.CREDITCARD=Credit card
paymentMode.GIFTCARD=Gift card

et celui du deuxième

paymentMode.CASH=Comptant
paymentMode.DEBIT=D\u00e9bit
paymentMode.CHECK=Ch\u00c3\u00a8que
paymentMode.CREDITCARD=Carte de cr\u00e9dit
paymentMode.GIFTCARD=Carte cadeaux

J'avais mis directement les accents, mais il semble qu'il y est eu une conversion à l'unicode.

Dans la classe où vous désirer accéder la valeur, il faut ajouter une propriété

@Autowired
private MessageSource messageSource;

Ensuite pour accéder au message vous pouvez utiliser une de ces deux méthodes

getMessage(String code, Object[] args, Locale locale);
getMessage(String code, Object[] args, String defaultMessage, Locale locale);

Dans notre cas, pour avoir la valeur de CASH en français.
messageSource.getMessage("paymentMode." + CASH, null, Locale.FRENCH);

lundi 8 août 2016

Accélération du développement avec Spring Boot

Spring Boot est un framework créé pour simplifier le développement d'application java.Il permet d'utiliser les différentes briques Spring. Il est possible de l'utiliser via un serveur JEE ou même un serveur tomcat ou jetty directement embarqué.

La configuration est minimal et peut se faire via les annotations, programmation ou par des fichiers de propriété ou yml.

Par exemple, en ajoutant un fichier schema.sql, la base de donnée peut être créé, avec un fichier nommé data.sql des données peut être inséré dans la bd. Une panoplie de petite chose comme ça est mis en place pour accroître la productivité.

Une page web existe pour créer le squelette d'une application. Ce site est https://start.spring.io/. Après avoir spécifié le nom de nom application, module désiré, version de java... un projet compressé peut être téléchargé et être ouvert dans un EDI tel que Netbeans.

Il est possible de créer un projet via maven ou bien gradle. Nous utiliserons ce derniers pour cet article.

En moins de 2 minute, il est possible d'avoir un serveur web fonctionnel.

Première application

Spring Initializer est utilisé pour créer la base de l'application.



Nous allons utiliser les paramètres par défaut, il y aucune dépendance pour le moment. Cliquer sur Generate Project et télécharger le fichier. Le fichier généré est aussi disponible ici. J'ai opté pour gradle au lieu de maven.

Par défaut, il y a qu'un fichier servant à démarrer l’application et un fichier application.propertie vide.

L'exécution de l'application donnera cette trace

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.4.0.RELEASE)

2016-08-08 18:41:17.065  INFO 9267 --- [           main] com.example.DemoApplication              : Starting DemoApplication with PID 9267 (/home/collinm/Development/code/demo/build/classes/main started by collinm in /home/collinm/Development/code/demo)
2016-08-08 18:41:17.068  INFO 9267 --- [           main] com.example.DemoApplication              : No active profile set, falling back to default profiles: default
2016-08-08 18:41:17.159  INFO 9267 --- [           main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@727803de: startup date [Mon Aug 08 18:41:17 EDT 2016]; root of context hierarchy
2016-08-08 18:41:18.067  INFO 9267 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2016-08-08 18:41:18.083  INFO 9267 --- [           main] com.example.DemoApplication              : Started DemoApplication in 1.421 seconds (JVM running for 1.796)
2016-08-08 18:41:18.093  INFO 9267 --- [       Thread-1] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@727803de: startup date [Mon Aug 08 18:41:17 EDT 2016]; root of context hierarchy
2016-08-08 18:41:18.108  INFO 9267 --- [       Thread-1] o.s.j.e.a.AnnotationMBeanExporter        : Unregistering JMX-exposed beans on shutdown

L'application ne fait rien. Nous allons maintenant ajouter des modules pour que l'application supporte Rest. Le service retournera un nombre aléatoire.

Dans le fichier build.gradle, nous allons renommer le module starter par starter-web ce qui donne.

dependencies {
        compile("org.springframework.boot:spring-boot-starter-web")
testCompile('org.springframework.boot:spring-boot-starter-test')
}

Nous allons créer un controleur

@RequestMapping(value="/rest")
@RestController
public class DemoController {
    private final DemoService demoService;
    
    @Autowired
    public DemoController(final DemoService demoService){
        this.demoService = demoService;
    }

    @GetMapping(value = "/random")
    public Integer getRandomNumber() {
        return demoService.getRandomNumber();
    }
    
    @GetMapping(value = "/random/{maxnumber}")
    public Integer getLimitRandomNumber(@PathVariable("maxnumber") int maxNumber) {
        return demoService.getLimitRandomNumber(maxNumber);
    }
    
}

Cette commande @RequestMapping(value="/rest") au niveau de la classe évite de devoir entrer rest dans chaque des méthodes.

La commande @RestController évite de devoir mettre ResponseBody avant chaque type de retour de fonction.

La commande @GetMapping est une nouveauté de Spring 4.3. C'est un raccourci pour

@RequestMapping(value = "/random", method = RequestMethod.GET)

L'équivalent existe pour post, put, delete et patch.

L'annotation @PathVariable indique que la variable fait partie de l'url.

Tomcat est embedded, pas besoin dans avoir un. Tomcat utlise par défaut le port 8080, il faudra donc l'ajouter à l'url appelé.

La première méthode pourra être appelé via l'ur http://localhost:8080/rest/random
alors qu'il que pour la seconde méthode il devra spécifier un nombre
http://localhost:8080/rest/random/20.

La couche de service retourne un nombre. Je m'attarderais pas dessus, vérifié les sources pour plus de détail.

L'application complète peut-être télécharger ici.

Si vous désirez démarrer l'application en dehors de environnement de travail. Générer une build. Un jar sera créé. Dans notre cas il se nommera: demo-0.0.1-SNAPSHOT.jar.

Pour lancer l'application: java -jar demo-0.0.1-SNAPSHOT.jar

Prenez note qu'il est possible d'utiliser d'autres serveurs tel que jetty, websphere et même le cloud.
Nous avons fait rapidement nos balbutiements avec Spring Boot.