portaldacalheta.pt
  • Основен
  • Управление На Проекти
  • Дизайн На Марката
  • Процес На Проектиране
  • Начин На Живот
Наука За Данни И Бази Данни

Първи стъпки с микроуслуги: Урок за Dropwizard



Всички сме свидетели на увеличаване на популярността на архитектурите на микроуслуги. В архитектурата на микроуслугите Dropwizard заема много важно място. Това е рамка за създаване на RESTful уеб услуги или, по-конкретно, набор от инструменти и рамки за създаване на RESTful уеб услуги.

Това позволява на разработчиците по-бързо стартиране на проекта. Това ви помага да опаковате приложенията си, така че да могат лесно да бъдат внедрени в производствена среда като самостоятелни услуги. Ако някога сте били в ситуация, в която трябва да стартирате проект в рамка Пролет Например сигурно знаете колко болезнено може да бъде.



Илюстрация: Пример за микроуслуги в урока за Dropwizard



елементи и принципи на дизайна

С Dropwizard става въпрос само за добавяне на зависимост на Maven.



В този блог ще ви преведа през целия процес на писане на проста услуга 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 включва контейнера сървлет Jetty за стартиране на уеб приложения. Вместо да разположи вашите приложения на сървър на приложения или уеб сървър, Dropwizard дефинира основен метод, който извиква Jetty сървъра като самостоятелен процес. Отсега нататък Dropwizard препоръчва приложението да се стартира само с Jetty; други уеб услуги като Tomcat не се поддържат официално.
  • Джърси: Джърси е едно от най-добрите внедрения на REST API на пазара. Освен това той следва стандартната спецификация на JAX-RS и е референтното изпълнение за спецификацията на JAX-RS. Dropwizard използва Джърси като рамка по подразбиране за изграждане на RESTful уеб приложения.
  • Джаксън: Jackson е де факто стандартът за работа с формата 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 .



Това е първата стъпка в създаването на вашето приложение 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 файла в този обект.

Определете клас на приложение

Сега трябва да създадем основния клас на приложението. Този клас ще събере всички пакети, ще вземе приложението и ще го пусне и работи за вас.

Най-добри практики за мобилен уеб дизайн 2018 г

Ето пример за клас на приложение в 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 файл може да бъде разположен в различна среда от тестова до производствена, без никакви промени в библиотеките на зависимостите. За да започнем да изграждаме нашето примерно приложение като a дебел JAR, трябва да конфигурираме Maven плъгин, наречен maven-сянка . Трябва да добавите следните записи в раздела за приставки на вашия файл 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 за заявки за администрация.

C++ уроци по програмиране

Имайте предвид, че server configuration.yml Използва се за стартиране на HTTP сървъра и предаване на местоположението на YAML конфигурационния файл на сървъра.

Отлично! Накрая внедрихме микроуслуга, използвайки рамка Dropwizard. Сега ще си вземем почивка и ще изпием чаша чай. Свърши добра работа.

Достъп до ресурси

Можете да използвате всеки HTTP клиент като POSTMAN или друг. Трябва да имате достъп до вашия сървър, като натиснете http://localhost:8080/parts. Трябва да получите съобщение, в което се посочва, че идентификационните данни са необходими за достъп до услугата. За удостоверяване добавете заглавката Authorization със стойността support_test_token. Ако успеете, трябва да видите нещо като:

{ '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 предлага bootstrap изключително бързо на вашия проект. И това е може би най-голямото предимство на използването на Dropwizard.

Той също така ще включва всички модерни библиотеки / инструменти, които ще са ви необходими, за да развиете вашата услуга. Така че определено не е нужно да се притеснявате за това. Освен това ви дава много хубаво управление на конфигурацията. Разбира се, Dropwizard има и някои недостатъци. Използването на Dropwizard е ограничено до използването на това, което Dropwizard предлага или поддържа. Губите част от свободата, с която може да сте свикнали, когато се развиете. Но въпреки това дори не бих го нарекъл недостатък, тъй като точно това прави Dropwizard това, което е - лесна за конфигуриране, лесна за разработване, но все пак много здрава и високопроизводителна REST рамка.

Според мен добавянето на сложност към рамка като подкрепя все повече и повече библиотеки на трети страни, това също би внесло ненужна сложност в развитието.

Дизайн на телевизионния потребителски интерфейс: Работа с бяло пространство

Ui Design

Дизайн на телевизионния потребителски интерфейс: Работа с бяло пространство
Android 7.0 за разработчици: Нови функции, надстройки на производителността и други неща, за които няма да ви е грижа

Android 7.0 за разработчици: Нови функции, надстройки на производителността и други неща, за които няма да ви е грижа

Подвижен

Популярни Публикации
Изцеление на скъсани вериги за доставки: производство извън Китай
Изцеление на скъсани вериги за доставки: производство извън Китай
Включете Angular 2: Надстройка от 1.5
Включете Angular 2: Надстройка от 1.5
Урок за работен поток за проектиране за разработчици: Осигурете по-добър UI / UX навреме
Урок за работен поток за проектиране за разработчици: Осигурете по-добър UI / UX навреме
PHP Frameworks: Избор между Symfony и Laravel
PHP Frameworks: Избор между Symfony и Laravel
Шевморфизъм, плосък дизайн и възходът на типографския дизайн
Шевморфизъм, плосък дизайн и възходът на типографския дизайн
 
.NET Core - да станем диви и с отворен код. Microsoft, какво ти отне толкова време ?!
.NET Core - да станем диви и с отворен код. Microsoft, какво ти отне толкова време ?!
Крайно ръководство за езика за обработка, част I: Основите
Крайно ръководство за езика за обработка, част I: Основите
Ractive.js - Уеб приложения, направени лесно
Ractive.js - Уеб приложения, направени лесно
Защо има толкова много Pythons?
Защо има толкова много Pythons?
Съвети и инструменти за оптимизиране на приложения за Android
Съвети и инструменти за оптимизиране на приложения за Android
Популярни Публикации
  • добрият дизайн на база данни не включва:
  • rest api в node js
  • принципите на дизайна в дефиниция на изкуството
  • джира срещу трело срещу асана
  • принципите на дизайна в изкуството
  • как се рисува в обработка
  • Учебно ръководство за архитект за решение на aws
Категории
  • Управление На Проекти
  • Дизайн На Марката
  • Процес На Проектиране
  • Начин На Живот
  • © 2022 | Всички Права Запазени

    portaldacalheta.pt