portaldacalheta.pt
  • Κύριος
  • Σχεδιασμός Για Κινητά
  • Ευκίνητο Ταλέντο
  • Τεχνολογία
  • Διεπαφή Ιστού
Επιστήμη Δεδομένων Και Βάσεις Δεδομένων

Ξεκινώντας με Μικροσυσκευές: Ένας Οδηγός Dropwizard



Όλοι παρατηρούμε μια αύξηση στη δημοτικότητα των αρχιτεκτονικών μικροϋπηρεσιών. Σε μια αρχιτεκτονική μικροϋπηρεσιών, το Dropwizard κατέχει ένα πολύ σημαντικό μέρος. Είναι ένα πλαίσιο για τη δημιουργία υπηρεσιών RESTful web ή, για να είμαστε πιο συγκεκριμένοι, ένα σύνολο εργαλείων και πλαίσια για τη δημιουργία διαδικτυακών υπηρεσιών RESTful.

Επιτρέπει στους προγραμματιστές μια ταχύτερη εκκίνηση του έργου. Αυτό σας βοηθά να συσκευάσετε τις εφαρμογές σας, ώστε να μπορούν να αναπτυχθούν εύκολα σε περιβάλλον παραγωγής ως ξεχωριστές υπηρεσίες. Εάν έχετε βρεθεί ποτέ σε μια κατάσταση όπου πρέπει να ξεκινήσετε ένα έργο στο πλαίσιο άνοιξη Για παράδειγμα, ίσως γνωρίζετε πόσο επώδυνο μπορεί να είναι.



Εικόνα: Παράδειγμα μικροσυσκευών στο εκπαιδευτικό πρόγραμμα Dropwizard



Με το Dropwizard, είναι απλώς θέμα προσθήκης εξάρτησης από το Maven.



Σε αυτό το blog, θα σας καθοδηγήσω σε όλη τη διαδικασία σύνταξης μιας απλής υπηρεσίας Dropwizard RESTful. Όταν τελειώσουμε, θα έχουμε μια υπηρεσία για βασικές λειτουργίες CRUD σε 'ανταλλακτικά'. Δεν έχει σημασία τι είναι το 'μέρος'. Μπορεί να είναι οτιδήποτε, αλλά ήταν το πρώτο πράγμα που μου συνέβη.

Θα αποθηκεύσουμε τα δεδομένα σε μια βάση δεδομένων MySQL, χρησιμοποιώντας το JDBI για να το συμβουλευτούμε και θα χρησιμοποιήσουμε τα ακόλουθα τελικά σημεία :



  • GET /parts -για να ανακτήσετε όλα τα μέρη από το DB
  • GET /part/{id} για να λάβετε ένα συγκεκριμένο μέρος από το DB
  • POST /parts -για να δημιουργήσετε νέο μέρος
  • PUT /parts/{id} -για να επεξεργαστείτε ένα υπάρχον μέρος
  • DELETE /parts/{id} -για να διαγράψετε το τμήμα από ένα DB

Θα χρησιμοποιήσουμε το OAuth για έλεγχο ταυτότητας της υπηρεσίας μας και στη συνέχεια θα προσθέσουμε ορισμένες δοκιμές μονάδας σε αυτήν

Προεπιλεγμένες βιβλιοθήκες Dropwizard

Αντί να περιλαμβάνει όλες τις βιβλιοθήκες που χρειάζονται για να δημιουργήσει μια ξεχωριστή υπηρεσία REST και να διαμορφώσει κάθε μία, το Dropwizard το κάνει για εμάς. Ακολουθεί η λίστα των βιβλιοθηκών που είναι προεπιλεγμένες με το Dropwizard:



  • Προβλήτα: Θα χρειαστείτε HTTP για να εκτελέσετε μια εφαρμογή ιστού. Το Dropwizard ενσωματώνει το δοχείο servlet Προβλήτα για την εκτέλεση εφαρμογών ιστού. Αντί να αναπτύξει τις εφαρμογές σας σε διακομιστή εφαρμογών ή διακομιστή ιστού, το Dropwizard καθορίζει μια κύρια μέθοδο που καλεί τον διακομιστή Jetty ως αυτόνομη διαδικασία. Από τώρα και στο εξής, το Dropwizard συνιστά την εκτέλεση της εφαρμογής μόνο με το Jetty. άλλες υπηρεσίες Ιστού όπως το Tomcat δεν υποστηρίζονται επίσημα.
  • Φανέλα: Το Jersey είναι μια από τις καλύτερες εφαρμογές REST API στην αγορά. Επιπλέον, ακολουθεί την τυπική προδιαγραφή JAX-RS και είναι η εφαρμογή αναφοράς για τις προδιαγραφές JAX-RS. Το Dropwizard χρησιμοποιεί το Jersey ως το προεπιλεγμένο πλαίσιο για τη δημιουργία εφαρμογών ιστού RESTful.
  • Τζάκσον: Το Jackson είναι το de facto πρότυπο για το χειρισμό της μορφής JSON. Είναι ένα από τα καλύτερα API αντιστοίχισης αντικειμένων για τη μορφή JSON.
  • Μετρήσεις: Το Dropwizard έχει τη δική του μονάδα μετρήσεων για να εκθέσει τις μετρήσεις εφαρμογών τελικά σημεία HTTP.
  • Γκουάβα: Εκτός από τις εξαιρετικά βελτιστοποιημένες και αμετάβλητες δομές δεδομένων, το Guava παρέχει έναν αυξανόμενο αριθμό κλάσεων για την επιτάχυνση του Ανάπτυξη Java .
  • Αποσύνδεση και Slf4j: Αυτά τα δύο χρησιμοποιούνται για τη βελτίωση των μηχανισμών εγγραφής.
  • Freemarker και μουστάκι: Η επιλογή μηχανών προτύπου για την εφαρμογή σας είναι μία από τις βασικές αποφάσεις. Η επιλεγμένη μηχανή προτύπου πρέπει να είναι πιο ευέλικτη για να γράφει καλύτερα σενάρια. Το Dropwizard χρησιμοποιεί τους γνωστούς και δημοφιλείς κινητήρες προτύπων Freemarker και Mustache για τη δημιουργία διεπαφών χρήστη.

Εκτός από την παραπάνω λίστα, υπάρχουν πολλές άλλες βιβλιοθήκες όπως Joda Time, Liquibase, Apache HTTP Client και Hibernate Validator που χρησιμοποιούνται από το Dropwizard για τη δημιουργία υπηρεσιών REST.

Διαμόρφωση Maven

Το Dropwizard υποστηρίζει επίσημα Μέβεν . Ακόμα κι αν μπορείτε να χρησιμοποιήσετε άλλα εργαλεία κατασκευής, οι περισσότεροι οδηγοί και τεκμηρίωση χρησιμοποιούν το Maven, οπότε θα το χρησιμοποιήσουμε και εδώ. Εάν δεν είστε εξοικειωμένοι με το Maven, μπορείτε να ανατρέξετε σε αυτό Σεμινάριο Maven .



μάθετε c++ με τον δύσκολο τρόπο

Αυτό είναι το πρώτο βήμα για τη δημιουργία της εφαρμογής Dropwizard. Προσθέστε την ακόλουθη καταχώριση στο αρχείο pom.xml από Maven:

io.dropwizard dropwizard-core ${dropwizard.version}

Πριν προσθέσετε την προηγούμενη καταχώριση, μπορείτε να προσθέσετε dropwizard.versión όπως φαίνεται στα ακόλουθα:



1.1.0

Αυτό είναι όλο. Ολοκληρώσατε τη σύνταξη του Maven. Αυτό θα κατεβάσει όλες τις απαραίτητες εξαρτήσεις για το έργο σας. Η τρέχουσα έκδοση του Το Dropwizard είναι 1.1.0 , έτσι θα το χρησιμοποιήσουμε σε αυτόν τον οδηγό.

Τώρα μπορούμε να προχωρήσουμε στη σύνταξη της πρώτης πραγματικής εφαρμογής Dropwizard.



Ορισμός κλάσης διαμόρφωσης

Το Dropwizard αποθηκεύει τις ρυθμίσεις σε αρχεία ΓΙΑΜΛ . Θα χρειαστείτε το αρχείο configuration.yml στο ριζικό φάκελο της εφαρμογής. Αυτό το αρχείο θα αποστρατειοποιηθεί σε μια παρουσία της κλάσης διαμόρφωσης της εφαρμογής σας και θα επικυρωθεί. Το αρχείο διαμόρφωσης της εφαρμογής σας είναι η υποκατηγορία της κλάσης διαμόρφωσης Dropwizard (io.dropwizard.Configuration).

Ας δημιουργήσουμε μια απλή κλάση διαμόρφωσης:

import javax.validation.Valid; import javax.validation.constraints.NotNull; import com.fasterxml.jackson.annotation.JsonProperty; import io.dropwizard.Configuration; import io.dropwizard.db.DataSourceFactory; public class DropwizardBlogConfiguration extends Configuration { private static final String DATABASE = 'database'; @Valid @NotNull private DataSourceFactory dataSourceFactory = new DataSourceFactory(); @JsonProperty(DATABASE) public DataSourceFactory getDataSourceFactory() { return dataSourceFactory; } @JsonProperty(DATABASE) public void setDataSourceFactory(final DataSourceFactory dataSourceFactory) { this.dataSourceFactory = dataSourceFactory; } }

Το αρχείο διαμόρφωσης YAML θα μοιάζει με αυτό:

database: driverClass: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost/dropwizard_blog user: dropwizard_blog password: dropwizard_blog maxWaitForConnection: 1s validationQuery: 'SELECT 1' validationQueryTimeout: 3s minSize: 8 maxSize: 32 checkConnectionWhileIdle: false evictionInterval: 10s minIdleTime: 1 minute checkConnectionOnBorrow: true

Η παραπάνω κλάση θα αφαιρεθεί από το αρχείο YAML και θα τοποθετήσει τις τιμές από το αρχείο YAML σε αυτό το αντικείμενο.

Ορίστε μια κλάση εφαρμογών

Τώρα πρέπει να πάμε και να δημιουργήσουμε την κύρια κατηγορία εφαρμογών. Αυτό το μάθημα θα συγκεντρώσει όλα τα πακέτα, θα λάβει την εφαρμογή και θα το θέσει σε λειτουργία για να το χρησιμοποιήσετε.

Ακολουθεί ένα παράδειγμα κλάσης εφαρμογών στο Dropwizard:

import io.dropwizard.Application; import io.dropwizard.auth.AuthDynamicFeature; import io.dropwizard.auth.oauth.OAuthCredentialAuthFilter; import io.dropwizard.setup.Environment; import javax.sql.DataSource; import org.glassfish.jersey.server.filter.RolesAllowedDynamicFeature; import org.skife.jdbi.v2.DBI; import com.toptal.blog.auth.DropwizardBlogAuthenticator; import com.toptal.blog.auth.DropwizardBlogAuthorizer; import com.toptal.blog.auth.User; import com.toptal.blog.config.DropwizardBlogConfiguration; import com.toptal.blog.health.DropwizardBlogApplicationHealthCheck; import com.toptal.blog.resource.PartsResource; import com.toptal.blog.service.PartsService; public class DropwizardBlogApplication extends Application { private static final String SQL = 'sql'; private static final String DROPWIZARD_BLOG_SERVICE = 'Dropwizard blog service'; private static final String BEARER = 'Bearer'; public static void main(String[] args) throws Exception { new DropwizardBlogApplication().run(args); } @Override public void run(DropwizardBlogConfiguration configuration, Environment environment) { // Datasource configuration final DataSource dataSource = configuration.getDataSourceFactory().build(environment.metrics(), SQL); DBI dbi = new DBI(dataSource); // Register Health Check DropwizardBlogApplicationHealthCheck healthCheck = new DropwizardBlogApplicationHealthCheck(dbi.onDemand(PartsService.class)); environment.healthChecks().register(DROPWIZARD_BLOG_SERVICE, healthCheck); // Register OAuth authentication environment.jersey() .register(new AuthDynamicFeature(new OAuthCredentialAuthFilter.Builder() .setAuthenticator(new DropwizardBlogAuthenticator()) .setAuthorizer(new DropwizardBlogAuthorizer()).setPrefix(BEARER).buildAuthFilter())); environment.jersey().register(RolesAllowedDynamicFeature.class); // Register resources environment.jersey().register(new PartsResource(dbi.onDemand(PartsService.class))); } }

Αυτό που κάναμε νωρίτερα είναι η παράκαμψη της μεθόδου εκτέλεσης του Dropwizard. Σε αυτήν τη μέθοδο, δημιουργούμε μια σύνδεση από DB (Βάση δεδομένων), καταχωρίζοντας τον προσαρμοσμένο μας έλεγχο υγείας (θα το συζητήσουμε αργότερα), αρχικοποιώντας τον έλεγχο ταυτότητας OAuth για την υπηρεσία μας, και τέλος καταχώριση ενός πόρου Dropwizard.

πώς να προσλάβετε έναν προγραμματιστή λογισμικού

Όλα αυτά θα εξηγηθούν αργότερα.

Ορίστε μια κατηγορία εκπροσώπησης

Τώρα πρέπει να αρχίσουμε να σκεφτόμαστε το REST API και ποια θα είναι η αναπαράσταση του πόρου μας. Πρέπει να σχεδιάσουμε τη μορφή JSON και την αντίστοιχη κλάση απόδοσης που μετατρέπεται στην επιθυμητή μορφή JSON.

Ας δούμε το δείγμα μορφής JSON για αυτό το απλό παράδειγμα κλάσης αναπαράστασης:

ο καλύτερος τρόπος μάθησης γ
{ 'code': 200, 'data': { 'id': 1, 'name': 'Part 1', 'code': 'PART_1_CODE' } }

Για την παραπάνω μορφή JSON, θα δημιουργήσουμε την τάξη απόδοσης ως εξής:

import org.hibernate.validator.constraints.Length; import com.fasterxml.jackson.annotation.JsonProperty; public class Representation { private long code; @Length(max = 3) private T data; public Representation() { // Jackson deserialization } public Representation(long code, T data) { this.code = code; this.data = data; } @JsonProperty public long getCode() { return code; } @JsonProperty public T getData() { return data; } }

Αυτό είναι το POJO με πολύ απλό τρόπο.

Ορισμός τάξης πόρων

Ένας πόρος βασίζεται στις υπηρεσίες REST. Δεν είναι τίποτα περισσότερο από ένα URI του τελικό σημείο για πρόσβαση στον πόρο στο διακομιστή. Σε αυτό το παράδειγμα, θα έχουμε μια κλάση πόρων με λίγους σχολιασμούς για την αντιστοίχιση URI αιτήματος. Δεδομένου ότι το Dropwizard χρησιμοποιεί την εφαρμογή JAX-RS, θα καθορίσουμε τη διαδρομή URI χρησιμοποιώντας τον σχολιασμό @Path.

Εδώ σας δείχνω μια κλάση πόρων για το παράδειγμα του Dropwizard:

import java.util.List; import javax.annotation.security.RolesAllowed; import javax.validation.Valid; import javax.validation.constraints.NotNull; import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import org.eclipse.jetty.http.HttpStatus; import com.codahale.metrics.annotation.Timed; import com.toptal.blog.model.Part; import com.toptal.blog.representation.Representation; import com.toptal.blog.service.PartsService; @Path('/parts') @Produces(MediaType.APPLICATION_JSON) @RolesAllowed('ADMIN') public class PartsResource { private final PartsService partsService;; public PartsResource(PartsService partsService) { this.partsService = partsService; } @GET @Timed public Representation getParts() { return new Representation(HttpStatus.OK_200, partsService.getParts()); } @GET @Timed @Path('{id}') public Representation getPart(@PathParam('id') final int id) { return new Representation(HttpStatus.OK_200, partsService.getPart(id)); } @POST @Timed public Representation createPart(@NotNull @Valid final Part part) { return new Representation(HttpStatus.OK_200, partsService.createPart(part)); } @PUT @Timed @Path('{id}') public Representation editPart(@NotNull @Valid final Part part, @PathParam('id') final int id) { part.setId(id); return new Representation(HttpStatus.OK_200, partsService.editPart(part)); } @DELETE @Timed @Path('{id}') public Representation deletePart(@PathParam('id') final int id) { return new Representation(HttpStatus.OK_200, partsService.deletePart(id)); } }

Μπορείτε να δείτε πώς όλα τελικά σημεία ορίζονται στην κατηγορία αυτή.

Καταγραφή ενός πόρου

Θα επιστρέψω τώρα στην κύρια κατηγορία εφαρμογών. Μπορείτε να δείτε στο τέλος αυτής της τάξης ότι έχουμε καταχωρίσει τον πόρο μας για να αρχικοποιηθεί με την εκτέλεση της υπηρεσίας. Πρέπει να το κάνουμε με όλους τους πόρους που μπορούμε να έχουμε στην εφαρμογή μας. Αυτό είναι το απόσπασμα κώδικα που είναι υπεύθυνο για αυτό:

// Register resources environment.jersey().register(new PartsResource(dbi.onDemand(PartsService.class)));

Επίπεδο υπηρεσίας

Για σωστό χειρισμό εξαιρέσεων και δυνατότητα ανεξαρτησίας από τη μηχανή αποθήκευσης δεδομένων, θα παρουσιάσουμε μια κατηγορία υπηρεσιών 'μεσαίου επιπέδου'. Αυτή είναι η τάξη που θα καλέσουμε από το επίπεδο πόρων μας, ανεξάρτητα από το τι είναι το υποκείμενο. Γι 'αυτό έχουμε αυτό το συγκεκριμένο επίπεδο μεταξύ των επιπέδων πόρων και του DAO. Αυτό είναι το είδος της υπηρεσίας μας:

import java.util.List; import java.util.Objects; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Response.Status; import org.skife.jdbi.v2.exceptions.UnableToExecuteStatementException; import org.skife.jdbi.v2.exceptions.UnableToObtainConnectionException; import org.skife.jdbi.v2.sqlobject.CreateSqlObject; import com.toptal.blog.dao.PartsDao; import com.toptal.blog.model.Part; public abstract class PartsService { private static final String PART_NOT_FOUND = 'Part id %s not found.'; private static final String DATABASE_REACH_ERROR = 'Could not reach the MySQL database. The database may be down or there may be network connectivity issues. Details: '; private static final String DATABASE_CONNECTION_ERROR = 'Could not create a connection to the MySQL database. The database configurations are likely incorrect. Details: '; private static final String DATABASE_UNEXPECTED_ERROR = 'Unexpected error occurred while attempting to reach the database. Details: '; private static final String SUCCESS = 'Success...'; private static final String UNEXPECTED_ERROR = 'An unexpected error occurred while deleting part.'; @CreateSqlObject abstract PartsDao partsDao(); public List getParts() { return partsDao().getParts(); } public Part getPart(int id) { Part part = partsDao().getPart(id); if (Objects.isNull(part)) { throw new WebApplicationException(String.format(PART_NOT_FOUND, id), Status.NOT_FOUND); } return part; } public Part createPart(Part part) { partsDao().createPart(part); return partsDao().getPart(partsDao().lastInsertId()); } public Part editPart(Part part) { if (Objects.isNull(partsDao().getPart(part.getId()))) { throw new WebApplicationException(String.format(PART_NOT_FOUND, part.getId()), Status.NOT_FOUND); } partsDao().editPart(part); return partsDao().getPart(part.getId()); } public String deletePart(final int id) { int result = partsDao().deletePart(id); switch (result) { case 1: return SUCCESS; case 0: throw new WebApplicationException(String.format(PART_NOT_FOUND, id), Status.NOT_FOUND); default: throw new WebApplicationException(UNEXPECTED_ERROR, Status.INTERNAL_SERVER_ERROR); } } public String performHealthCheck() { try { partsDao().getParts(); } catch (UnableToObtainConnectionException ex) { return checkUnableToObtainConnectionException(ex); } catch (UnableToExecuteStatementException ex) { return checkUnableToExecuteStatementException(ex); } catch (Exception ex) { return DATABASE_UNEXPECTED_ERROR + ex.getCause().getLocalizedMessage(); } return null; } private String checkUnableToObtainConnectionException(UnableToObtainConnectionException ex) { if (ex.getCause() instanceof java.sql.SQLNonTransientConnectionException) { return DATABASE_REACH_ERROR + ex.getCause().getLocalizedMessage(); } else if (ex.getCause() instanceof java.sql.SQLException) { return DATABASE_CONNECTION_ERROR + ex.getCause().getLocalizedMessage(); } else { return DATABASE_UNEXPECTED_ERROR + ex.getCause().getLocalizedMessage(); } } private String checkUnableToExecuteStatementException(UnableToExecuteStatementException ex) { if (ex.getCause() instanceof java.sql.SQLSyntaxErrorException) { return DATABASE_CONNECTION_ERROR + ex.getCause().getLocalizedMessage(); } else { return DATABASE_UNEXPECTED_ERROR + ex.getCause().getLocalizedMessage(); } } }

Το τελευταίο μέρος αυτού είναι στην πραγματικότητα μια εφαρμογή ελέγχου υγείας, για την οποία θα μιλήσουμε αργότερα.

Επίπεδο DAO, JDBI και Mapper

Το Dropwizard είναι συμβατό με το JDBI και το Hibernate. Είναι μια ξεχωριστή μονάδα Maven, οπότε πρόκειται να την προσθέσουμε πρώτα ως εξάρτηση, καθώς και τη σύνδεση MySQL

io.dropwizard dropwizard-jdbi ${dropwizard.version} mysql mysql-connector-java ${mysql.connector.version}

Για μια απλή υπηρεσία CRUD, προτιμώ προσωπικά το JDBI, καθώς είναι πιο απλό και πολύ πιο γρήγορο στην εφαρμογή. Έχω δημιουργήσει ένα απλό σχήμα MySQL με έναν πίνακα για να χρησιμοποιηθούν στο παράδειγμά μας. Μπορείτε να βρείτε το σενάριο μέσα σε αυτό για το σχήμα εντός της προέλευσης. Το JDBI προσφέρει απλή συγγραφή ερωτήσεων, χρησιμοποιώντας σχολιασμούς όπως το @SqlQuery για ανάγνωση και το @SqlUpdate για τη σύνταξη δεδομένων. Εδώ είναι η διεπαφή DAO μας:

import java.util.List; import org.skife.jdbi.v2.sqlobject.Bind; import org.skife.jdbi.v2.sqlobject.BindBean; import org.skife.jdbi.v2.sqlobject.SqlQuery; import org.skife.jdbi.v2.sqlobject.SqlUpdate; import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapper; import com.toptal.blog.mapper.PartsMapper; import com.toptal.blog.model.Part; @RegisterMapper(PartsMapper.class) public interface PartsDao { @SqlQuery('select * from parts;') public List getParts(); @SqlQuery('select * from parts where id = :id') public Part getPart(@Bind('id') final int id); @SqlUpdate('insert into parts(name, code) values(:name, :code)') void createPart(@BindBean final Part part); @SqlUpdate('update parts set name = coalesce(:name, name), code = coalesce(:code, code) where id = :id') void editPart(@BindBean final Part part); @SqlUpdate('delete from parts where id = :id') int deletePart(@Bind('id') final int id); @SqlQuery('select last_insert_id();') public int lastInsertId(); }

Όπως μπορείτε να δείτε, είναι αρκετά απλό. Ωστόσο, πρέπει να χαρτογραφήσουμε τα σύνολα αποτελεσμάτων SQL σε ένα μοντέλο, το οποίο γίνεται με την εγγραφή μιας τάξης χάρτης . Εδώ είναι η τάξη μας χάρτης :

import java.sql.ResultSet; import java.sql.SQLException; import org.skife.jdbi.v2.StatementContext; import org.skife.jdbi.v2.tweak.ResultSetMapper; import com.toptal.blog.model.Part; public class PartsMapper implements ResultSetMapper { private static final String ID = 'id'; private static final String NAME = 'name'; private static final String CODE = 'code'; public Part map(int i, ResultSet resultSet, StatementContext statementContext) throws SQLException { return new Part(resultSet.getInt(ID), resultSet.getString(NAME), resultSet.getString(CODE)); } }

Και το μοντέλο μας:

import org.hibernate.validator.constraints.NotEmpty; public class Part { private int id; @NotEmpty private String name; @NotEmpty private String code; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public Part() { super(); } public Part(int id, String name, String code) { super(); this.id = id; this.name = name; this.code = code; } }

Έλεγχος υγείας Dropwizard

Το Dropwizard προσφέρει εγγενή υποστήριξη για τον έλεγχο της υγείας. Στην περίπτωσή μας, πιθανότατα θα ελέγξουμε εάν η βάση δεδομένων λειτουργεί πριν πούμε ότι η υπηρεσία μας είναι υγιής. Αυτό που κάνουμε είναι να εκτελέσουμε κάποια απλή ενέργεια βάσης δεδομένων, όπως η λήψη τμημάτων της βάσης δεδομένων και ο χειρισμός των πιθανών αποτελεσμάτων (επιτυχίες ή εξαιρέσεις).

ποιο από αυτά δεν είναι ένας τρόπος για να βοηθήσετε τον εαυτό σας να κατανοήσει το μεγαλύτερο εύρος της ροής εργασίας;

Εδώ είναι η εφαρμογή ελέγχου υγείας στο Dropwizard:

import com.codahale.metrics.health.HealthCheck; import com.toptal.blog.service.PartsService; public class DropwizardBlogApplicationHealthCheck extends HealthCheck { private static final String HEALTHY = 'The Dropwizard blog Service is healthy for read and write'; private static final String UNHEALTHY = 'The Dropwizard blog Service is not healthy. '; private static final String MESSAGE_PLACEHOLDER = '{}'; private final PartsService partsService; public DropwizardBlogApplicationHealthCheck(PartsService partsService) { this.partsService = partsService; } @Override public Result check() throws Exception { String mySqlHealthStatus = partsService.performHealthCheck(); if (mySqlHealthStatus == null) { return Result.healthy(HEALTHY); } else { return Result.unhealthy(UNHEALTHY + MESSAGE_PLACEHOLDER, mySqlHealthStatus); } } }

Προσθήκη ελέγχου ταυτότητας

Το Dropwizard υποστηρίζει βασικό έλεγχο ταυτότητας και OAuth . Εδώ, θα σας δείξω πώς να προστατεύσετε την υπηρεσία σας με το OAuth. Ωστόσο, λόγω της πολυπλοκότητας, παρέλειψα μια υποκείμενη δομή βάσης δεδομένων και θα δείξω μόνο πώς αναπτύσσεται. Η ανάπτυξη σε πλήρη κλίμακα δεν πρέπει να αποτελεί πρόβλημα από εδώ. Το Dropwizard έχει δύο σημαντικές διεπαφές που πρέπει να εφαρμόσουμε.

Το πρώτο είναι Επαληθευτής . Η τάξη μας πρέπει να εφαρμόσει τη μέθοδο authenticate, η οποία πρέπει να ελέγξει εάν το δεδομένο αναγνωριστικό πρόσβασης είναι έγκυρο. Έτσι θα το αποκαλούσα ως πρώτη πόρτα στην εφαρμογή. Εάν είναι επιτυχής, θα πρέπει να έχει ως αποτέλεσμα έναν κύριο. Αυτός ο κύριος είναι ο πραγματικός μας χρήστης με το ρόλο του. Αυτό είναι σημαντικό για μια άλλη διεπαφή Dropwizard που πρέπει να εφαρμόσουμε. Αυτό είναι το Συντάκτης και είναι υπεύθυνο για τον έλεγχο εάν ο χρήστης έχει επαρκή δικαιώματα πρόσβασης σε έναν συγκεκριμένο πόρο. Επομένως, αν επιστρέψετε και ελέγξετε την κλάση πόρων, θα δείτε ότι απαιτείται ο ρόλος του διαχειριστή για πρόσβαση σε αυτήν τελικά σημεία . Αυτοί οι σχολιασμοί μπορούν επίσης να είναι με μέθοδο. Η υποστήριξη εξουσιοδότησης Dropwizard είναι μια ξεχωριστή μονάδα Maven, οπότε πρέπει να την προσθέσουμε σε εξαρτήσεις:

io.dropwizard dropwizard-auth ${dropwizard.version}

Ακολουθούν τα μαθήματα στο παράδειγμά μας που δεν κάνουν πραγματικά τίποτα έξυπνο, αλλά αποτελούν σκελετό για εξουσιοδότηση OAuth μεγάλης κλίμακας:

import java.util.Optional; import io.dropwizard.auth.AuthenticationException; import io.dropwizard.auth.Authenticator; public class DropwizardBlogAuthenticator implements Authenticator { @Override public Optional authenticate(String token) throws AuthenticationException { if ('test_token'.equals(token)) { return Optional.of(new User()); } return Optional.empty(); } } import java.util.Objects; import io.dropwizard.auth.Authorizer; public class DropwizardBlogAuthorizer implements Authorizer { @Override public boolean authorize(User principal, String role) { // Allow any logged in user. if (Objects.nonNull(principal)) { return true; } return false; } } import java.security.Principal; public class User implements Principal { private int id; private String username; private String password; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String getName() { return username; } }

Δοκιμές μονάδας στο DropWizard

Πρόκειται να προσθέσουμε μερικές δοκιμές μονάδας στην εφαρμογή μας. Εμμένω να δοκιμάσω συγκεκριμένα μέρη του κώδικα Dropwizard, στην περίπτωσή μας: Εκπροσώπηση και πόρος. Θα χρειαστεί να προσθέσουμε τις ακόλουθες εξαρτήσεις στο αρχείο Maven:

io.dropwizard dropwizard-testing ${dropwizard.version} org.mockito mockito-core ${mockito.version} test

Για να δοκιμάσουμε την απόδοση, θα χρειαστεί επίσης ένα δείγμα αρχείου JSON για να το δοκιμάσουμε. Ας δημιουργήσουμε λοιπόν fixtures/part.json κάτω src/test/resources:

{ 'id': 1, 'name': 'testPartName', 'code': 'testPartCode' }

Και εδώ είναι η τάξη δοκιμής JUnit:

import static io.dropwizard.testing.FixtureHelpers.fixture; import static org.assertj.core.api.Assertions.assertThat; import org.junit.Test; import com.fasterxml.jackson.databind.ObjectMapper; import com.toptal.blog.model.Part; import io.dropwizard.jackson.Jackson; public class RepresentationTest { private static final ObjectMapper MAPPER = Jackson.newObjectMapper(); private static final String PART_JSON = 'fixtures/part.json'; private static final String TEST_PART_NAME = 'testPartName'; private static final String TEST_PART_CODE = 'testPartCode'; @Test public void serializesToJSON() throws Exception { final Part part = new Part(1, TEST_PART_NAME, TEST_PART_CODE); final String expected = MAPPER.writeValueAsString(MAPPER.readValue(fixture(PART_JSON), Part.class)); assertThat(MAPPER.writeValueAsString(part)).isEqualTo(expected); } @Test public void deserializesFromJSON() throws Exception { final Part part = new Part(1, TEST_PART_NAME, TEST_PART_CODE); assertThat(MAPPER.readValue(fixture(PART_JSON), Part.class).getId()).isEqualTo(part.getId()); assertThat(MAPPER.readValue(fixture(PART_JSON), Part.class).getName()) .isEqualTo(part.getName()); assertThat(MAPPER.readValue(fixture(PART_JSON), Part.class).getCode()) .isEqualTo(part.getCode()); } }

Όσον αφορά τη δοκιμή πόρων, το κύριο σημείο των δοκιμών του Dropwizard είναι ότι συμπεριφέρεται στην πραγματικότητα σαν πελάτης HTTP, στέλνοντας αιτήματα HTTP έναντι πόρων. Επομένως, δεν δοκιμάζετε μεθόδους όπως θα κάνατε συνήθως σε μια κοινή περίπτωση. Εδώ είναι το παράδειγμα της τάξης μας PartsResource:

public class PartsResourceTest { private static final String SUCCESS = 'Success...'; private static final String TEST_PART_NAME = 'testPartName'; private static final String TEST_PART_CODE = 'testPartCode'; private static final String PARTS_ENDPOINT = '/parts'; private static final PartsService partsService = mock(PartsService.class); @ClassRule public static final ResourceTestRule resources = ResourceTestRule.builder().addResource(new PartsResource(partsService)).build(); private final Part part = new Part(1, TEST_PART_NAME, TEST_PART_CODE); @Before public void setup() { when(partsService.getPart(eq(1))).thenReturn(part); List parts = new ArrayList(); parts.add(part); when(partsService.getParts()).thenReturn(parts); when(partsService.createPart(any(Part.class))).thenReturn(part); when(partsService.editPart(any(Part.class))).thenReturn(part); when(partsService.deletePart(eq(1))).thenReturn(SUCCESS); } @After public void tearDown() { reset(partsService); } @Test public void testGetPart() { Part partResponse = resources.target(PARTS_ENDPOINT + '/1').request() .get(TestPartRepresentation.class).getData(); assertThat(partResponse.getId()).isEqualTo(part.getId()); assertThat(partResponse.getName()).isEqualTo(part.getName()); assertThat(partResponse.getCode()).isEqualTo(part.getCode()); verify(partsService).getPart(1); } @Test public void testGetParts() { List parts = resources.target(PARTS_ENDPOINT).request().get(TestPartsRepresentation.class).getData(); assertThat(parts.size()).isEqualTo(1); assertThat(parts.get(0).getId()).isEqualTo(part.getId()); assertThat(parts.get(0).getName()).isEqualTo(part.getName()); assertThat(parts.get(0).getCode()).isEqualTo(part.getCode()); verify(partsService).getParts(); } @Test public void testCreatePart() { Part newPart = resources.target(PARTS_ENDPOINT).request() .post(Entity.entity(part, MediaType.APPLICATION_JSON_TYPE), TestPartRepresentation.class) .getData(); assertNotNull(newPart); assertThat(newPart.getId()).isEqualTo(part.getId()); assertThat(newPart.getName()).isEqualTo(part.getName()); assertThat(newPart.getCode()).isEqualTo(part.getCode()); verify(partsService).createPart(any(Part.class)); } @Test public void testEditPart() { Part editedPart = resources.target(PARTS_ENDPOINT + '/1').request() .put(Entity.entity(part, MediaType.APPLICATION_JSON_TYPE), TestPartRepresentation.class) .getData(); assertNotNull(editedPart); assertThat(editedPart.getId()).isEqualTo(part.getId()); assertThat(editedPart.getName()).isEqualTo(part.getName()); assertThat(editedPart.getCode()).isEqualTo(part.getCode()); verify(partsService).editPart(any(Part.class)); } @Test public void testDeletePart() { assertThat(resources.target(PARTS_ENDPOINT + '/1').request() .delete(TestDeleteRepresentation.class).getData()).isEqualTo(SUCCESS); verify(partsService).deletePart(1); } private static class TestPartRepresentation extends Representation { } private static class TestPartsRepresentation extends Representation { } private static class TestDeleteRepresentation extends Representation { } }

Δημιουργήστε την εφαρμογή Dropwizard

Η βέλτιστη πρακτική είναι να δημιουργήσετε το μεμονωμένο αρχείο FAR JAR που περιέχει όλα τα αρχεία .class που απαιτούνται για την εκτέλεση της εφαρμογής. Το ίδιο αρχείο JAR μπορεί να αναπτυχθεί σε διαφορετικό περιβάλλον από δοκιμή σε παραγωγή, χωρίς αλλαγές στις βιβλιοθήκες εξάρτησης. Για να ξεκινήσετε να δημιουργείτε το δείγμα της εφαρμογής μας ως Λίπος JAR, πρέπει να διαμορφώσουμε ένα Maven plugin που ονομάζεται μακέν σκιά . Πρέπει να προσθέσετε τις ακόλουθες καταχωρίσεις στην ενότητα προσθηκών του αρχείου pom.xml.

Ακολουθεί το παράδειγμα της διαμόρφωσης Maven για τη δημιουργία του αρχείου JAR.

4.0.0 com.endava dropwizard-blog 0.0.1-SNAPSHOT Dropwizard Blog example 1.1.0 2.7.12 6.0.6 1.8 1.8 io.dropwizard dropwizard-core ${dropwizard.version} io.dropwizard dropwizard-jdbi ${dropwizard.version} io.dropwizard dropwizard-auth ${dropwizard.version} io.dropwizard dropwizard-testing ${dropwizard.version} org.mockito mockito-core ${mockito.version} test mysql mysql-connector-java ${mysql.connector.version} org.apache.maven.plugins maven-shade-plugin 2.3 true *:* META-INF/*.SF META-INF/*.DSA META-INF/*.RSA package shade com.endava.blog.DropwizardBlogApplication

Εκτέλεση της εφαρμογής

Τώρα πρέπει να είμαστε σε θέση να εκτελέσουμε την υπηρεσία. Εάν δημιουργήσατε σωστά το αρχείο JAR, αυτό που πρέπει να κάνετε είναι να ανοίξετε τη γραμμή εντολών και να εκτελέσετε την ακόλουθη εντολή για να εκτελέσετε το αρχείο JAR:

java -jar target/dropwizard-blog-1.0.0.jar server configuration.yml

Εάν όλα πήγαν καλά, θα πρέπει να δείτε κάτι τέτοιο:

INFO [2017-04-23 22:51:14,471] org.eclipse.jetty.util.log: Logging initialized @962ms to org.eclipse.jetty.util.log.Slf4jLog INFO [2017-04-23 22:51:14,537] io.dropwizard.server.DefaultServerFactory: Registering jersey handler with root path prefix: / INFO [2017-04-23 22:51:14,538] io.dropwizard.server.DefaultServerFactory: Registering admin handler with root path prefix: / INFO [2017-04-23 22:51:14,681] io.dropwizard.server.DefaultServerFactory: Registering jersey handler with root path prefix: / INFO [2017-04-23 22:51:14,681] io.dropwizard.server.DefaultServerFactory: Registering admin handler with root path prefix: / INFO [2017-04-23 22:51:14,682] io.dropwizard.server.ServerFactory: Starting DropwizardBlogApplication INFO [2017-04-23 22:51:14,752] org.eclipse.jetty.setuid.SetUIDListener: Opened [email protected] {HTTP/1.1,[http/1.1]}{0.0.0.0:8080} INFO [2017-04-23 22:51:14,752] org.eclipse.jetty.setuid.SetUIDListener: Opened [email protected] {HTTP/1.1,[http/1.1]}{0.0.0.0:8081} INFO [2017-04-23 22:51:14,753] org.eclipse.jetty.server.Server: jetty-9.4.2.v20170220 INFO [2017-04-23 22:51:15,153] io.dropwizard.jersey.DropwizardResourceConfig: The following paths were found for the configured resources: GET /parts (com.toptal.blog.resource.PartsResource) POST /parts (com.toptal.blog.resource.PartsResource) DELETE /parts/{id} (com.toptal.blog.resource.PartsResource) GET /parts/{id} (com.toptal.blog.resource.PartsResource) PUT /parts/{id} (com.toptal.blog.resource.PartsResource) INFO [2017-04-23 22:51:15,154] org.eclipse.jetty.server.handler.ContextHandler: Started [email protected] {/,null,AVAILABLE} INFO [2017-04-23 22:51:15,158] io.dropwizard.setup.AdminEnvironment: tasks = POST /tasks/log-level (io.dropwizard.servlets.tasks.LogConfigurationTask) POST /tasks/gc (io.dropwizard.servlets.tasks.GarbageCollectionTask) INFO [2017-04-23 22:51:15,162] org.eclipse.jetty.server.handler.ContextHandler: Started [email protected] {/,null,AVAILABLE} INFO [2017-04-23 22:51:15,176] org.eclipse.jetty.server.AbstractConnector: Started [email protected] {HTTP/1.1,[http/1.1]}{0.0.0.0:8080} INFO [2017-04-23 22:51:15,177] org.eclipse.jetty.server.AbstractConnector: Started [email protected] {HTTP/1.1,[http/1.1]}{0.0.0.0:8081} INFO [2017-04-23 22:51:15,177] org.eclipse.jetty.server.Server: Started @1670ms

Έχετε πλέον τη δική σας εφαρμογή Dropwizard που ακούει στις θύρες 8080 για αιτήματα εφαρμογών και 8081 για αιτήματα διαχείρισης.

Σημειώστε ότι server configuration.yml Χρησιμοποιείται για την εκκίνηση του διακομιστή HTTP και τη μεταφορά της θέσης του αρχείου διαμόρφωσης YAML στον διακομιστή.

Εξοχος! Τέλος, έχουμε εφαρμόσει μια μικροϋπηρεσία χρησιμοποιώντας το δομή Dropwizard. Τώρα ας κάνουμε ένα διάλειμμα και να πάρουμε ένα φλιτζάνι τσάι. Εκανες καλή δουλειά.

Πρόσβαση στους πόρους

Μπορείτε να χρησιμοποιήσετε οποιονδήποτε πελάτη HTTP όπως το POSTMAN ή οποιοδήποτε άλλο. Θα πρέπει να έχετε πρόσβαση στον διακομιστή σας πατώντας http://localhost:8080/parts. Θα πρέπει να λάβετε ένα μήνυμα που δηλώνει ότι απαιτούνται τα διαπιστευτήρια για την πρόσβαση στην υπηρεσία. Για έλεγχο ταυτότητας, προσθέστε την κεφαλίδα Authorization με την τιμή support_test_token. Εάν είναι επιτυχής, θα πρέπει να δείτε κάτι σαν:

ιοντικό 2 και γωνιακό 2
{ 'code': 200, 'data': [] }

Αυτό σημαίνει ότι η βάση δεδομένων σας είναι κενή. Δημιουργήστε το πρώτο σας μέρος αλλάζοντας τη μέθοδο HTTP από GET σε POST και παρέχετε αυτό το ωφέλιμο φορτίο:

{ 'name':'My first part', 'code':'code_of_my_first_part' }

Ολοι οι άλλοι τελικά σημεία Λειτουργούν με τον ίδιο τρόπο, οπότε συνεχίστε να παίζετε και να απολαμβάνετε.

Πώς να αλλάξετε τη διαδρομή περιβάλλοντος

Η εφαρμογή Dropwizard, από προεπιλογή, θα ξεκινήσει και θα εκτελεστεί σε /. Για παράδειγμα, εάν δεν αναφέρετε τίποτα σχετικά με τη διαδρομή περιβάλλοντος εφαρμογής από προεπιλογή, μπορείτε να αποκτήσετε πρόσβαση στην εφαρμογή από τη διεύθυνση URL http://localhost: 8080/. Εάν θέλετε να διαμορφώσετε τη δική σας διαδρομή περιβάλλοντος για την εφαρμογή σας, προσθέστε τις ακόλουθες καταχωρίσεις στο αρχείο YAML σας. διακομιστής ~~~: applicationContextPath: / application ~~~

Ολοκλήρωση του οδηγού Dropwizard

Τώρα, όταν έχετε εγκαταστήσει την υπηρεσία Dropwizard REST, ήρθε η ώρα να συνοψίσετε μερικά από τα βασικά πλεονεκτήματα ή μειονεκτήματα της χρήσης του Dropwizard όπως δομή ΥΠΟΛΟΙΠΟ. Είναι απολύτως προφανές από αυτήν την ανάρτηση που προσφέρει το Dropwizard μποτάκι εξαιρετικά γρήγορα του έργου σας. Και αυτό είναι πιθανώς το μεγαλύτερο πλεονέκτημα της χρήσης του Dropwizard.

Θα περιλαμβάνει επίσης όλες τις αιχμές βιβλιοθήκες / εργαλεία που θα χρειαστείτε για να αναπτύξετε την υπηρεσία σας. Οπότε σίγουρα δεν χρειάζεται να ανησυχείτε για αυτό. Σας δίνει επίσης πολύ ωραία διαχείριση διαμόρφωσης. Φυσικά, το Dropwizard έχει και κάποια μειονεκτήματα. Χρησιμοποιώντας το Dropwizard περιορίζεστε στη χρήση όσων προσφέρει ή υποστηρίζει το Dropwizard. Χάνετε μέρος της ελευθερίας που μπορεί να συνηθίσετε κατά την ανάπτυξή σας. Αλλά ακόμα δεν θα το αποκαλούσα μειονέκτημα, καθώς αυτό ακριβώς κάνει το Dropwizard αυτό που είναι - εύκολο στη διαμόρφωση, εύκολο στην ανάπτυξη, αλλά εξακολουθεί να είναι ένα πολύ ισχυρό και υψηλής απόδοσης πλαίσιο REST.

Κατά τη γνώμη μου, προσθέτοντας πολυπλοκότητα στο δομή Υποστηρίζοντας όλο και περισσότερες βιβλιοθήκες τρίτων, θα εισαγάγει επίσης περιττή πολυπλοκότητα στην ανάπτυξη.

Μετά από όλα αυτά τα χρόνια, ο κόσμος εξακολουθεί να τροφοδοτείται από τον προγραμματισμό C

Πίσω Μέρος

Μετά από όλα αυτά τα χρόνια, ο κόσμος εξακολουθεί να τροφοδοτείται από τον προγραμματισμό C
Διευθυντής Υπηρεσιών Πελατών Επιχειρήσεων, Επικοινωνιών, Μέσων, Ψυχαγωγίας και Τεχνολογίας

Διευθυντής Υπηρεσιών Πελατών Επιχειρήσεων, Επικοινωνιών, Μέσων, Ψυχαγωγίας και Τεχνολογίας

Αλλα

Δημοφιλείς Αναρτήσεις
Κοιτάζοντας τα αποτυχημένα IPO στην εποχή του μονόκερου
Κοιτάζοντας τα αποτυχημένα IPO στην εποχή του μονόκερου
Top 10 UX Παραδοτέα Χρήση κορυφαίων σχεδιαστών
Top 10 UX Παραδοτέα Χρήση κορυφαίων σχεδιαστών
Evolving Emoji: Σχεδιασμός για το νέο πρόσωπο των μηνυμάτων
Evolving Emoji: Σχεδιασμός για το νέο πρόσωπο των μηνυμάτων
Διευθυντής Υπηρεσιών Πελατών Επιχειρήσεων, Επικοινωνιών, Μέσων, Ψυχαγωγίας και Τεχνολογίας
Διευθυντής Υπηρεσιών Πελατών Επιχειρήσεων, Επικοινωνιών, Μέσων, Ψυχαγωγίας και Τεχνολογίας
Τεχνικές έρευνας UX και οι εφαρμογές τους
Τεχνικές έρευνας UX και οι εφαρμογές τους
 
Power Pivot for Excel Tutorial: Κορυφαίες περιπτώσεις και παραδείγματα χρήσης
Power Pivot for Excel Tutorial: Κορυφαίες περιπτώσεις και παραδείγματα χρήσης
Οι δοκιμασμένοι και αληθινοί νόμοι του UX (με Infographic)
Οι δοκιμασμένοι και αληθινοί νόμοι του UX (με Infographic)
Εργασία με React Hooks και TypeScript
Εργασία με React Hooks και TypeScript
Κοιτάζοντας το μέλλον - Τάσεις σχεδιασμού του 2020
Κοιτάζοντας το μέλλον - Τάσεις σχεδιασμού του 2020
Ας επανασχεδιάσουμε το Facebook: 10 παραδείγματα για να εμπνεύσετε και να σας βοηθήσουμε να ξεκινήσετε
Ας επανασχεδιάσουμε το Facebook: 10 παραδείγματα για να εμπνεύσετε και να σας βοηθήσουμε να ξεκινήσετε
Δημοφιλείς Αναρτήσεις
  • διαφορά μεταξύ ac και s corp
  • αριθμός πιστωτικής κάρτας κάποιου που μπορώ να χρησιμοποιήσω
  • βέλτιστες πρακτικές σχεδίασης web api
  • δημιουργήστε τη δική σας γλώσσα προγραμματισμού
  • όταν γίνει σωστά η διαδικασία δέουσας επιμέλειας θα
  • η γνώση της ελαστικότητας τιμής ενός προϊόντος επιτρέπει στους οικονομολόγους να
  • s corp εναντίον c corp
Κατηγορίες
  • Σχεδιασμός Για Κινητά
  • Ευκίνητο Ταλέντο
  • Τεχνολογία
  • Διεπαφή Ιστού
  • © 2022 | Ολα Τα Δικαιώματα Διατηρούνται

    portaldacalheta.pt