portaldacalheta.pt
  • Põhiline
  • Tulud Ja Kasv
  • Tehnoloogia
  • Planeerimine Ja Prognoosimine
  • Projekti Juht
Andmeteadus Ja Andmebaasid

Mikroteenustega alustamine: Dropwizardi õpetus



Me kõik oleme tunnistajaks mikroteenuste arhitektuuride populaarsuse suurenemisele. Mikroteenuste arhitektuuris on Dropwizard väga oluline koht. See on raamistik RESTful veebiteenuste või täpsemalt öeldes tööriistade ja raamistikud RESTful veebiteenuste loomiseks.

See võimaldab arendajatel projekti kiiremini käivitada. See aitab teil oma rakendusi pakendada nii, et neid saaks hõlpsasti tootmiskeskkonnas eraldiseisvate teenustena juurutada. Kui teil on kunagi olnud olukorda, kus peate projektis alustama raamistiku kevad Näiteks teate ilmselt, kui valus see võib olla.



kuidas saada discord bot

Illustratsioon: näide mikroteenustest Dropwizardi õpetuses



Dropwizardi puhul on küsimus vaid Maveni sõltuvuse lisamises.



Selles blogis tutvustan teid kogu Dropwizardi RESTful teenuse kirjutamise protsessi. Kui oleme lõpetanud, on meil teenus CRUD-i põhitoimingute jaoks 'osades'. Pole tegelikult vahet, mis on “osa”; See võib olla ükskõik mis, aga see tuli mulle esimesena pähe.

Salvestame andmed MySQL-i andmebaasi, kasutades selleks tutvumiseks JDBI-d ja kasutame järgmist lõpp-punktid :



  • GET /parts - kõigi osade hankimiseks DB-st
  • GET /part/{id} konkreetse osa saamiseks DB-st
  • POST /parts - uue osa loomiseks
  • PUT /parts/{id} - olemasoleva osa redigeerimiseks
  • DELETE /parts/{id} -osa kustutada andmebaasist

Kasutame teenuse autentimiseks OAuthi ja lisame sellele seejärel mõned üksuste testid

Vaikimisi Dropwizardi teegid

Selle asemel, et lisada kõik teegid, mis on vajalikud eraldi REST-teenuse loomiseks ja nende konfigureerimiseks, teeb Dropwizard seda meie eest. Siin on Dropwizardi vaikimisi varustatud teekide loend:



  • Kai: Veebirakenduse käitamiseks vajate HTTP-d. Dropwizard sisaldab konteinerit servlet Jett veebirakenduste käitamiseks. Rakenduste rakendusserverisse või veebiserverisse paigutamise asemel määratleb Dropwizard peamise meetodi, mis kutsub Jetty serveri iseseisva protsessina. Nüüdsest soovitab Dropwizard rakendust käivitada ainult koos Jetty; muid veebiteenuseid, nagu Tomcat, ametlikult ei toetata.
  • Jersey: Jersey on üks parimaid REST API juurutusi turul. Lisaks järgib see JAX-RS standardspetsifikatsioone ja on JAX-RS spetsifikatsiooni võrdlusrakendus. Dropwizard kasutab RESTfuli veebirakenduste loomisel vaikeraamistikuna Jersey.
  • Jackson: Jackson on JSON-vormingu käsitlemisel de facto standard. See on üks parimaid JSON-vormingu objektide kaardistamise API-sid.
  • Mõõdikud: Dropwizardil on oma mõõdikute moodul, mille kaudu rakenduse mõõdikuid kuvada lõpp-punktid HTTP.
  • Guava: Lisaks ülimalt optimeeritud ja muutumatutele andmestruktuuridele pakub Guava järjest kiiremat arvu klasse Java arendamine .
  • Sisselogimine ja Slf4j: Neid kahte kasutatakse registreerimismehhanismide täiustamiseks.
  • Vabamarker ja vuntsid: Rakenduse mallimootorite valimine on üks peamisi otsuseid. Paremate skriptide kirjutamiseks peab valitud mallimootor olema paindlikum. Dropwizard kasutab kasutajaliideste loomiseks nii tuntud kui ka populaarseid Freemarkeri ja Vuntside mallimootoreid.

Peale ülaltoodud loendi on Dropwizardi poolt REST-teenuste loomiseks palju muid teeke, nagu Joda Time, Liquibase, Apache HTTP Client ja Hibernate Validator.

Maven konfiguratsioon

Dropwizard toetab ametlikult Maven . Isegi kui saate kasutada muid ehitustööriistu, kasutab enamik juhendeid ja dokumentatsiooni Mavenit, nii et me kasutame seda ka siin. Kui te pole Maveniga tuttav, võite sellele viidata Maven õpetus .



See on teie Dropwizardi rakenduse loomise esimene samm. Lisage faili järgmine kirje pom.xml Mavenist:

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

Enne eelmise kirje lisamist võite lisada dropwizard.versión nagu see on näidatud järgmises:



1.1.0

See on kõik. Olete lõpetanud Maveni konfiguratsiooni kirjutamise. See laadib alla kõik teie projekti jaoks vajalikud sõltuvused. Teenuse praegune versioon Dropwizard on 1.1.0 , nii et kasutame seda selles juhendis.

Nüüd saame edasi liikuda oma esimese päris Dropwizardi rakenduse kirjutamise juurde.



Määrake konfiguratsiooniklass

Dropwizard salvestab seaded failidesse YAML . Te vajate faili configuration.yml rakenduse juurkaustas. See fail deserialiseeritakse teie rakenduse konfiguratsiooniklassi eksemplariks ja valideeritakse. Teie rakenduse konfiguratsioonifail on Dropwizardi seadistusklassi (io.dropwizard.Configuration) alaklass.

Loome lihtsa seadistusklassi:

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-i konfiguratsioonifail näeks välja selline:

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

Ülaltoodud klass deserialiseerub YAML-failist ja paneb YAML-faili väärtused sellesse objekti.

Määrake rakenduse klass

Nüüd peame minema ja looma peamise rakendusklassi. See klass kogub kõik paketid kokku, võtab rakenduse ja paneb selle teie kasutusse.

Siin on näide Dropwizardi rakendusklassi kohta:

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))); } }

See, mida me varem tegime, on Dropwizardi käivitamismeetodi alistamine. Selle meetodi abil ühendame ühenduse DB (Andmebaas), meie kohandatud tervisekontrolli registreerimine (sellest räägime hiljem), meie teenuse OAuthi autentimise lähtestamine ja lõpuks Dropwizardi ressursi registreerimine.

Seda kõike selgitatakse hiljem.

Määratlege esindusklass

Nüüd peame hakkama mõtlema oma REST API-le ja sellele, mis on meie ressursi esitusviis. Peame kujundama JSON-vormingu ja vastava renderdusklassi, mis teisendatakse soovitud JSON-vorminguks.

Vaatame selle lihtsa renderdamisklassi näite JSON-vormingu näidist:

{ 'code': 200, 'data': { 'id': 1, 'name': 'Part 1', 'code': 'PART_1_CODE' } }

Ülaltoodud JSON-vormingu jaoks loome renderdusklassi järgmiselt:

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; } }

See on POJO väga lihtsal viisil.

Ressursiklassi määratlus

Ressurss on see, millel REST-teenused põhinevad. See pole midagi muud kui URI lõpp-punkt serveris olevale ressursile juurdepääsemiseks. Selles näites on meil ressursiklassi, kus on vähe märkmeid päringu URI kaardistamiseks. Kuna Dropwizard kasutab JAX-RS juurutamist, määratleme URI tee märkuse @Path abil.

Siin on meie Dropwizardi näite ressursside klass:

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)); } }

Näete, kuidas kõik lõpp-punktid need on tegelikult selles klassis määratletud.

Ressursi salvestamine

Naasen nüüd põhirakendusklassi. Selle klassi lõpus näete, et oleme registreerinud oma ressursi, mis lähtestatakse teenuse täitmisega. Peame seda tegema kõigi ressurssidega, mis meie rakenduses võivad olla. Selle eest vastutab koodilõik:

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

Teenuse kiht

Erandite nõuetekohaseks käitlemiseks ja andmesalvestusmootorist sõltumatuse tagamiseks tutvustame 'keskastme' teenindusklassi. See on klass, millele helistame oma ressursikihilt, olenemata sellest, mis selle aluseks on. Sellepärast on meil see konkreetne kiht ressursikihtide ja DAO vahel. See on meie teenus:

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(); } } }

Selle viimane osa on tegelikult tervisekontrolli rakendamine, millest me räägime hiljem.

DAO, JDBI ja Mapperi kiht

Dropwizard ühildub JDBI ja talveunerežiimiga. See on eraldi Maveni moodul, nii et lisame selle kõigepealt sõltuvusse ja ka MySQL-pistiku

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

Lihtsa CRUD-teenuse jaoks eelistan isiklikult JDBI-d, kuna seda on lihtsam ja palju kiiremini rakendada. Olen loonud lihtsa MySQL-i skeemi koos tabeliga, et seda lihtsalt meie näites kasutada. Skripti leiate selles päritolus oleva skeemi jaoks. JDBI pakub lihtsat küsimuste kirjutamist, kasutades märkuste jaoks näiteks @SqlQuery lugemiseks ja @SqlUpdate andmete kirjutamiseks. Siin on meie DAO liides:

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(); }

Nagu näete, on see üsna lihtne. Siiski peame oma SQL-i tulemuste komplektid kaardistama mudeli järgi, mis toimub klassi registreerimisega kaardistaja . Siin on meie klass kaardistaja :

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)); } }

Ja meie mudel:

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; } }

Dropwizardi tervisekontroll

Dropwizard pakub tervisekontrolliks kohalikku tuge. Meie juhul kontrollime tõenäoliselt andmebaasi toimimist, enne kui ütleme, et meie teenus on tervislik. Mida me teeme, on mõned lihtsad andmebaasitoimingud, näiteks andmebaasi osade hankimine ja võimalike tulemuste (õnnestumised või erandid) käsitlemine.

Siin on meie tervisekontrolli rakendamine Dropwizardis:

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); } } }

Autentimise lisamine

Dropwizard toetab põhilist autentimist ja OAuth . Siin ma näitan teile, kuidas kaitsta teie teenust OAuthi abil. Keerukuse tõttu olen aga andmebaasi aluseks oleva struktuuri välja jätnud ja näitan ainult selle arengut. Täismahus kasutuselevõtt ei tohiks siit probleem olla. Dropwizardil on kaks olulist liidest, mida peame rakendama.

Esimene on Autentija . Meie klass peab kasutama meetodit authenticate, mis peab kontrollima, kas antud juurdepääsuidentifikaator on kehtiv. Nii et ma nimetaksin seda rakenduse esimese uksena. Kui see õnnestub, peaks selle tulemuseks olema printsipaal. See printsipaal on oma rolliga meie tegelik kasutaja. See on oluline teise Dropwizardi liidese jaoks, mille peame rakendama. See on Volitaja ja see vastutab selle eest, et kontrollida, kas kasutajal on teatud ressursile juurdepääsemiseks piisavalt õigusi. Nii et kui lähete tagasi ja uurite meie ressursiklassi, näete, et selle juurde pääsemiseks on vaja administraatori rolli lõpp-punktid . Need märkused võivad olla ka meetodi järgi. Dropwizardi autoriseerimistugi on eraldi Maveni moodul, seega peame selle lisama sõltuvustesse:

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

Siin on meie näite klassid, mis tegelikult ei tee midagi nutikat, kuid on suuremahulise OAuthi volituse skelett:

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; } }

Üksuse testid DropWizardis

Lisame oma rakendusele mõned ühikutestid. Jään Dropwizardi koodi konkreetsete osade testimisele, meie puhul: Esindus ja ressurss. Peame oma Maveni faili lisama järgmised sõltuvused:

mittetulunduslikud jätkuva hooldusega pensionäride kogukonnad
io.dropwizard dropwizard-testing ${dropwizard.version} org.mockito mockito-core ${mockito.version} test

Renderduse testimiseks vajame testimiseks ka JSON-faili näidist. Nii et loome fixtures/part.json all src/test/resources:

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

Ja siin on JUniti testiklass:

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()); } }

Ressursside testimise osas on Dropwizardi testimise põhipunkt see, et see tegelikult käitub nagu HTTP klient, saates ressursside vastu HTTP taotlusi. Nii et te ei testi meetodeid nagu tavaliselt tavalisel juhul. Siin on meie klassi näide 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 { } }

Ehitage oma Dropwizardi rakendus

Parim tava on luua üks fail FAR JAR, mis sisaldab kõiki rakenduse käitamiseks vajalikke .class-faile. Sama JAR-faili saab testimisest kuni tootmiseni juurutada erinevas keskkonnas, sõltuvusraamatukogudesse muudatusi tegemata. Et hakata meie näidisrakendust a paks JAR, peame konfigureerima Maveni pistikprogrammi nimega maven-vari . Peate oma pom.xml-faili jaotisse Pluginad lisama järgmised kirjed.

Siin on Maveni konfiguratsiooni näide JAR-faili loomiseks.

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

Rakenduse käitamine

Nüüd peaksime saama teenust käitada. Kui olete oma JAR-faili edukalt üles ehitanud, peate avama käsurea ja käivitama JAR-faili käivitamiseks järgmise käsu:

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

Kui kõik sujus, peaksite nägema midagi sellist:

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

Teil on nüüd oma Dropwizardi rakendus, mis kuulab porte 8080 rakendustaotlusi ja 8081 haldustaotlusi.

Pange tähele, et server configuration.yml Seda kasutatakse HTTP-serveri käivitamiseks ja YAML-i konfiguratsioonifaili asukoha edastamiseks serverile.

Suurepärane! Lõpuks oleme rakendanud mikroteenuse, kasutades raamistik Dropwizard. Nüüd teeme pausi ja võtame tassi teed. Sa tegid head tööd.

Juurdepääs ressurssidele

Võite kasutada mis tahes HTTP-klienti, nagu POSTMAN või mõnda muud. Oma serverile peaksite pääsema, vajutades http://localhost:8080/parts. Peaksite saama teate, mis kinnitab, et teenusele juurdepääsemiseks on vaja mandaati. Autentimiseks lisage päis Authorization väärtusega support_test_token. Edu korral peaksite nägema midagi sellist:

{ 'code': 200, 'data': [] }

Mis tähendab, et teie andmebaas on tühi. Looge oma esimene osa, muutes HTTP-meetodi GET-st POST-i ja edastage see kasulik koormus:

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

Kõik teised lõpp-punktid Nad töötavad samamoodi, nii et jätkake mängimist ja nautige.

Kuidas muuta kontekstiteed

Rakendus Dropwizard käivitub ja töötab vaikimisi / Näiteks kui te ei maini vaikimisi rakenduse kontekstitee kohta midagi, pääseb rakendusele juurde URL-ist http://localhost: 8080/. Kui soovite oma rakenduse jaoks oma kontekstitee konfigureerida, lisage oma YAML-faili järgmised kirjed. ~~~ server: applicationContextPath: / rakendus ~~~

Meie Dropwizardi õpetuse lõpetamine

Kui olete Dropwizardi REST-teenuse installinud, on aeg kokku võtta Dropwizardi kasutamise mõned peamised eelised või puudused, näiteks raamistik Puhkus. Sellest postitusest on täiesti ilmne, et Dropwizard pakub a bootstrap oma projekti ülikiire. Ja see on ilmselt Dropwizardi kasutamise suurim eelis.

See sisaldab ka kõiki tipptasemel teeke / tööriistu, mida vajate oma teenuse arendamiseks. Nii et te ei pea selle pärast kindlasti muretsema. See annab teile ka väga kena konfiguratsioonihalduse. Muidugi on Dropwizardil ka mõned varjuküljed. Dropwizardi kasutamine on piiratud sellega, mida Dropwizard pakub või toetab. Sa kaotad osa vabadusest, millega võid arenemisel harjuda. Kuid isegi nii ei nimetaks ma seda isegi puuduseks, sest just see muudab Dropwizardi selliseks, nagu see on - lihtne konfigureerida, hõlpsasti arendatav, kuid siiski väga vastupidav ja suure jõudlusega REST-i raamistik.

Minu arvates lisab programmile keerukust raamistik toetades üha uusi kolmandate osapoolte raamatukogusid, tooks see ka arendustöösse tarbetut keerukust.

Pythoni kujundusmustrid: klanitud ja moes koodi jaoks

Tagumine Ots

Pythoni kujundusmustrid: klanitud ja moes koodi jaoks
Masinkeel - Chatboti terminoloogia juhend (koos infograafikaga)

Masinkeel - Chatboti terminoloogia juhend (koos infograafikaga)

Ux Disain

Lemmik Postitused
Näpunäited ja kaalutlused kirjatüübi valimisel (koos infograafikaga)
Näpunäited ja kaalutlused kirjatüübi valimisel (koos infograafikaga)
Juhtumianalüüs: miks ma oma toodete jaoks AWS-i pilvinfrastruktuuri kasutan
Juhtumianalüüs: miks ma oma toodete jaoks AWS-i pilvinfrastruktuuri kasutan
Briifing: andmeladu
Briifing: andmeladu
Surm traatraamile. Otse kõrgele truudusele!
Surm traatraamile. Otse kõrgele truudusele!
ApeeScape käivitas vabakutselistele mõeldud vaba aja jälgimise rakenduse TopTracker
ApeeScape käivitas vabakutselistele mõeldud vaba aja jälgimise rakenduse TopTracker
 
Arendajate ja disainerite vahe on kadumas
Arendajate ja disainerite vahe on kadumas
API-d sotsiaalsetes võrgustikes: Interneti-portaal reaalsesse maailma
API-d sotsiaalsetes võrgustikes: Interneti-portaal reaalsesse maailma
Null kangelaseni: Kolvitootmise retseptid
Null kangelaseni: Kolvitootmise retseptid
Projekti- ja tootehalduse direktor
Projekti- ja tootehalduse direktor
Ameerika arendaja Rachell Calhoun võidab viienda ApeeScape'i stipendiumi
Ameerika arendaja Rachell Calhoun võidab viienda ApeeScape'i stipendiumi
Lemmik Postitused
  • parimate tavade kontoplaani koostamine
  • millised on disaini elemendid
  • mis on jõudluse häälestamine SQL-is
  • Raspberry pi kasutamine serverina
  • kus kasutatakse node js-i
Kategooriad
  • Tulud Ja Kasv
  • Tehnoloogia
  • Planeerimine Ja Prognoosimine
  • Projekti Juht
  • © 2022 | Kõik Õigused Kaitstud

    portaldacalheta.pt