JavaRush /Java блогы /Random-KK /Біз мақалалар тобына жазылу мүмкіндігін қосамыз. (1-бөлім...
Roman Beekeeper
Деңгей

Біз мақалалар тобына жазылу мүмкіндігін қосамыз. (1-бөлім) - «Java жобасы А-дан Я-ға дейін»

Топта жарияланған
Сәлеметсіз бе! Бүгін біз JavaRush-тегі мақалалар тобына жазылуды қосамыз. Бұл GitHub сайтындағы JRTB-5 шығарылымына сәйкес келеді. Түсіндіруге рұқсат етіңіз: JavaRush-те Мақалалар деп аталатын бөлім бар және онда Мақалалар топтары бар. Идея – бір немесе бірнеше топтан жаңа мақала туралы хабарландыруларды телеграм боты арқылы алу.«А-дан Я-ға Java жобасы»: мақалалар тобына жазылу мүмкіндігін қосу.  1 - 1 бөлім

JRTB-5 қосыңыз

Мені «Жетістік тарихы» тобының мақалалары қызықтырады делік . Сондықтан мен осы топтың жаңартуларына жазылғым келеді және әр уақытта жаңа басылымға сілтеме алғым келеді. Осы тапсырманың бөлігі ретінде JavaRush-те топтармен жұмыс істеу үшін ашық API пайдалануды үйренуіміз керек. Дәл осы сәтте осындай нәрсе келді. Мұнда ашық API сипаттамасына сілтеме берілген .
Достар! Жобаның жаңа codeын немесе жаңа мақаланың қашан шыққанын бірден білгіңіз келе ме? Менің tg каналыма қосылыңыз . Онда мен мақалаларымды, ойларымды және ашық дереккөзді әзірлеуді бірге жинаймын.

Свеггер дегеніміз не? Енді анықтап көрейік

Біз әзірге сыпайылық туралы айтқан жоқпыз. Білмейтіндер үшін мен қысқаша түсіндіремін: бұл serverдің API интерфейсін ашық қарап, оған кейбір сұраулар жасауға тырысатын орын. Әдетте, свеггер ықтимал сұрауларды топтайды. Біздің жағдайда үш топ бар: форум-сұрақ , топ , пост . Әрбір топта осы сұранысты құру үшін барлық қажетті деректерді көрсететін бір немесе бірнеше сұраулар болады (яғни, қандай қосымша параметрлерді беруге болады, олармен не істеу керек, қандай http әдісі және т.б.). Мен сізге осы тақырыпты көбірек оқуға және көруге кеңес беремін, өйткені бұл әрқайсыңыз дерлік кездесетін дамудың бір бөлігі. Оны анықтау үшін JavaRush-те қанша топ бар екенін білейік. Ол үшін топ-контроллер тобын кеңейтіп, сұрауды алу /api/1.0/rest/groups/count таңдаңыз . Ол бізге JavaRush ішіндегі топтардың санын қайтарады. Қарап көрейік: «А-дан Я-ға Java жобасы»: мақалалар тобына жазылу мүмкіндігін қосу.  1-2 бөлімСуретте бұл сұрау бірнеше параметрлерді (сұрау, түр, сүзгі) қолдайтынын көрсетеді. Бұл сұрауды орындау үшін, "Байқап көру" түймесін табу керек , содан кейін осы параметрлерді конфигурациялауға болады: «А-дан Я-ға Java жобасы»: мақалалар тобына жазылу мүмкіндігін қосу.  1 - 3 бөлімТүрді, сүзгіні және сұрауды сол жерде конфигурациялауға болады (бұл жерде шынымен қызықты: бұл мәтіндік іздеу болады. топ). Бірақ әзірге оны шектеусіз іске қосып, JavaRush-те қанша топ бар екенін көрейік. Ол үшін «Орындау» түймесін басыңыз. Төменде осы сұрауға жауап (Сервер жауабы бөлімінде) болады: Біз барлығы 30«А-дан Я-ға Java жобасы»: мақалалар тобына жазылу мүмкіндігін қосу.  1-4 бөлім топ бар екенін көреміз , бұл сұрау 95 мс орындалды және жауапта кейбір тақырыптар жиынтығы бар. Әрі қарай, кейбір параметрлерді конфигурациялауға тырысайық. КОМПАНИЯ мәніне тең тип параметрін таңдап, нәтиженің қалай өзгеретінін көрейік: Олардың 4-уі бар.Мұны қалай тексеруге болады? Бұл оңай: сіз веб-сайтқа өтіп, мақала бөлімін таба аласыз, барлық топтарды таңдап, сол жерге сәйкес сүзгіні қоса аласыз ( https://javarush.com/groups/all?type=COMPANY ). Және иә, шынында да, олардың тек 4-і бар.Шын мәнінде үшеуі болса да :D Әзірге ол сәйкес келеді. Айтпақшы, университеттерді тексерсек, әлі жоқ. Тек көңіл көтеру үшін Javarush жүйесіне кіріп, жүйеге кірмеген браузерде filter = MY параметрін орнатсаңыз, не болатынын қараңыз. Свеггер туралы толығырақ - Хабредегі осы мақалада .«А-дан Я-ға Java жобасы»: мақалалар тобына жазылу мүмкіндігін қосу.  1 - 5 бөлім«А-дан Я-ға Java жобасы»: мақалалар тобына жазылу мүмкіндігін қосу.  1-6 бөлім

Топтарға арналған Javarush API үшін клиентті жазу

Енді ашық API негізінде біз сұраулар жасай алатын, жауап ала алатын және қандай нысандар келетінін нақты білетін Java клиентін жазамыз. Сондай-ақ біз нысандарды «Модельдер» бөлімінен (беттің төменгі жағында) аламыз . Жаңа бума жасап, оны сервис, репозиторий жанындағы javarushclient деп атаймыз. Болашақта біз оны Javarush қауымдастығы ұйымындағы бөлек кітапханаға көшіреміз және оны тек тәуелділік ретінде пайдаланамыз. Ең алдымен JavaRush API жүйесіне http сұрауларын жасауға арналған кітапхана Unitrest қосу керек:
<dependency>
  <groupId>com.konghq</groupId>
  <artifactId>unirest-java</artifactId>
  <version>${unirest.version}</version>
</dependency>
Нұсқаны сипаттар блогына қойыңыз:
<unirest.version>3.11.01</unirest.version>
Бізде тәуелділік болғаннан кейін codeты қосуды бастай аламыз. JavaRushGroupClient топтары үшін клиентті және JavaRushGroupClientImpl сыныбында іске асыруды жасайық. Бірақ алдымен DTO (деректерді тасымалдау an objectілері) жасау керек, яғни an objectілер клиентке қажетті барлық деректерді тасымалдайтын сыныптар. Барлық модельдерді свеггерде көруге болады.Төменгі жағында Модельдер бөлімі бар , онда сіз оларды санай аласыз. GroupDiscussionInfo свеггерде осылай көрінеді: javarushclient бумасында біз dto«А-дан Я-ға Java жобасы»: мақалалар тобына жазылу мүмкіндігін қосу.  1-7 бөлім бумасын жасаймыз , оған сваггер деректері негізінде келесі сыныптарды қосамыз:
  • MeGroupInfoStatus :

    package com.github.javarushcommunity.jrtb.javarushclient.dto;
    
    /**
    * Member group status.
    */
    public enum MeGroupInfoStatus {
       UNKNOWN, CANDIDATE, INVITEE, MEMBER, EDITOR, MODERATOR, ADMINISTRATOR, BANNED
    }

  • MeGroupInfo :

    package com.github.javarushcommunity.jrtb.javarushclient.dto;
    
    import lombok.Data;
    
    /**
    * Group information related to authorized user. If there is no user - will be null.
    */
    @Data
    public class MeGroupInfo {
       private MeGroupInfoStatus status;
       private Integer userGroupId;
    }

  • GroupInfoType :

    package com.github.javarushcommunity.jrtb.javarushclient.dto;
    
    /**
    * Group Info type;
    */
    public enum GroupInfoType {
       UNKNOWN, CITY, COMPANY, COLLEGE, TECH, SPECIAL, COUNTRY
    }

  • UserDiscussionInfo :

    package com.github.javarushcommunity.jrtb.javarushclient.dto;
    
    import lombok.Data;
    
    /**
    * DTO for User discussion info.
    */
    @Data
    public class UserDiscussionInfo {
    
       private Boolean isBookmarked;
       private Integer lastTime;
       private Integer newCommentsCount;
    }

  • GroupVisibilitysd күйі :

    package com.github.javarushcommunity.jrtb.javarushclient.dto;
    
    /**
    * Group Visibility status.
    */
    public enum GroupVisibilityStatus {
       UNKNOWN, RESTRICTED, PUBLIC, PROTECTED, PRIVATE, DISABLED, DELETED
    }

  • Содан кейін - GroupInfo :

    package com.github.javarushcommunity.jrtb.javarushclient.dto;
    
    import lombok.Data;
    import lombok.ToString;
    
    /**
    * Group Info DTO class.
    */
    @Data
    @ToString
    public class GroupInfo {
    
       private Integer id;
       private String avatarUrl;
       private String createTime;
       private String description;
       private String key;
       private Integer levelToEditor;
       private MeGroupInfo meGroupInfo;
       private String pictureUrl;
       private String title;
       private GroupInfoType type;
       private Integer userCount;
       private GroupVisibilityStatus visibilityStatus;
    }

GroupInfo және GroupDiscussionInfo дерлік бірдей болғандықтан , оларды мұраға байланыстырайық - GroupDiscusionInfo :
package com.github.javarushcommunity.jrtb.javarushclient.dto;

import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;

/**
* Group discussion info class.
*/
@EqualsAndHashCode(callSuper = true)
@Data
@ToString(callSuper = true)
public class GroupDiscussionInfo extends GroupInfo {

   private UserDiscussionInfo userDiscussionInfo;
   private Integer commentsCount;
}
Бізге GroupFilter сұрауы үшін сүзгі қажет болады :
package com.github.javarushcommunity.jrtb.javarushclient.dto;

/**
* Filters for group requests.
*/
public enum GroupFilter {

   UNKNOWN, MY, ALL
}
Идентификатор бойынша алу сұрауында ол GroupDiscussionInfo қайтарады және топтар жинағына сұрауда GroupInfo және GroupDiscussionInfo екеуін де ала аласыз. Сұраныстардың түрі, сұрауы, сүзгісі, ығысуы және шегі болуы мүмкін болғандықтан, жеке GroupRequestArgs сыныбын жасап , оны құрастырушы сыныбына айналдырайық (құрастырушы үлгісінің не екенін оқыңыз):
package com.github.javarushcommunity.jrtb.javarushclient.dto;

import lombok.*;

import java.util.HashMap;
import java.util.Map;

import static java.util.Objects.nonNull;

/**
* Request arguments for group requests.
*/
@Builder
@Getter
public class GroupRequestArgs {

   private final String query;
   private final GroupInfoType type;
   private final GroupFilter filter;

   /**
    * specified where to start getting groups
    */
   private final Integer offset;
   /**
    * Limited number of groups.
    */
   private final Integer limit;

   public Map populateQueries() {
       Map queries = new HashMap<>();
       if(nonNull(query)) {
           queries.put("query", query);
       }
       if(nonNull(type)) {
           queries.put("type", type);
       }
       if(nonNull(filter)) {
           queries.put("filter", filter);
       }
       if(nonNull(offset)) {
           queries.put("offset", offset);
       }
       if(nonNull(limit)) {
           queries.put("limit", limit);
       }
       return queries;
   }
}
Топтардың санын іздеу үшін ол сәл өзгеше. Онда тек сұрау, түр және сүзгі бар. Сіз codeты қайталағыңыз келмейтін сияқты. Сонымен қатар, егер сіз оларды біріктіре бастасаңыз, құрылысшылармен жұмыс істегенде шіркін болып шығады. Сондықтан мен оларды бөліп, codeты қайталауды шештім. GroupCountRequestArgs келесідей көрінеді :
package com.github.javarushcommunity.jrtb.javarushclient.dto;

import lombok.Builder;
import lombok.Getter;

import java.util.HashMap;
import java.util.Map;

import static java.util.Objects.nonNull;

/**
* Request arguments for group count requests.
*/
@Builder
@Getter
public class GroupsCountRequestArgs {
   private final String query;
   private final GroupInfoType type;
   private final GroupFilter filter;

   public Map populateQueries() {
       Map queries = new HashMap<>();
       if (nonNull(query)) {
           queries.put("query", query);
       }
       if (nonNull(type)) {
           queries.put("type", type);
       }
       if (nonNull(filter)) {
           queries.put("filter", filter);
       }
       return queries;
   }
}
Иә, мен соңғы екі сыныпта картаны сұрауды жасауға дайындайтын populateQueries әдісі бар екенін айтқан жоқпын (оны кейінірек көресіз). Жоғарыда сипатталған сыныптарға сүйене отырып, JavaRushGroupClient интерфейсін жасайық :
package com.github.javarushcommunity.jrtb.javarushclient;

import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupDiscussionInfo;
import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupInfo;
import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupRequestArgs;
import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupsCountRequestArgs;

import java.util.List;

/**
 * Client for Javarush Open API corresponds to Groups.
 */
public interface JavaRushGroupClient {

    /**
     * Get all the {@link GroupInfo} filtered by provided {@link GroupRequestArgs}.
     *
     * @param requestArgs provided {@link GroupRequestArgs}.
     * @return the collection of the {@link GroupInfo} objects.
     */
    List<GroupInfo> getGroupList(GroupRequestArgs requestArgs);

    /**
     * Get all the {@link GroupDiscussionInfo} filtered by provided {@link GroupRequestArgs}.
     *
     * @param requestArgs provided {@link GroupRequestArgs}
     * @return the collection of the {@link GroupDiscussionInfo} objects.
     */
    List<GroupDiscussionInfo> getGroupDiscussionList(GroupRequestArgs requestArgs);

    /**
     * Get count of groups filtered by provided {@link GroupRequestArgs}.
     *
     * @param countRequestArgs provided {@link GroupsCountRequestArgs}.
     * @return the count of the groups.
     */
    Integer getGroupCount(GroupsCountRequestArgs countRequestArgs);

    /**
     * Get {@link GroupDiscussionInfo} by provided ID.
     *
     * @param id provided ID.
     * @return {@link GroupDiscussionInfo} object.
     */
    GroupDiscussionInfo getGroupById(Integer id);
}
GroupInfo немесе GroupDiscussionInfo ақпаратын алғымыз келген жағдайда екі түрлі сұрау. Әйтпесе, бұл сұраулар бірдей және жалғыз айырмашылық біреуінде includeDiscussion жалаушасы ақиқат, ал екіншісінде ол жалған болады. Сондықтан үш емес, 4 әдіс болды. Енді іске асыруды бастайық:
package com.github.javarushcommunity.jrtb.javarushclient;

import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupDiscussionInfo;
import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupInfo;
import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupRequestArgs;
import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupsCountRequestArgs;
import kong.unirest.GenericType;
import kong.unirest.Unirest;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.List;

/**
* Implementation of the {@link JavaRushGroupClient} interface.
*/
@Component
public class JavaRushGroupClientImpl implements JavaRushGroupClient {

   private final String javarushApiGroupPath;

   public JavaRushGroupClientImpl(@Value("${javarush.api.path}") String javarushApi) {
       this.javarushApiGroupPath = javarushApi + "/groups";
   }

   @Override
   public List<GroupInfo> getGroupList(GroupRequestArgs requestArgs) {
       return Unirest.get(javarushApiGroupPath)
               .queryString(requestArgs.populateQueries())
               .asObject(new GenericType<list<GroupInfo>>() {
               })
               .getBody();
   }

   @Override
   public List<GroupDiscussionInfo> getGroupDiscussionList(GroupRequestArgs requestArgs) {
       return Unirest.get(javarushApiGroupPath)
               .queryString(requestArgs.populateQueries())
               .asObject(new GenericType<list<GroupDiscussionInfo>>() {
               })
               .getBody();
   }

   @Override
   public Integer getGroupCount(GroupsCountRequestArgs countRequestArgs) {
       return Integer.valueOf(
               Unirest.get(String.format("%s/count", javarushApiGroupPath))
                       .queryString(countRequestArgs.populateQueries())
                       .asString()
                       .getBody()
       );
   }

   @Override
   public GroupDiscussionInfo getGroupById(Integer id) {
       return Unirest.get(String.format("%s/group%s", javarushApiGroupPath, id.toString()))
               .asObject(GroupDiscussionInfo.class)
               .getBody();
   }


}
Мен бұрыннан таныс Value annotationсын пайдаланып конструктордағы API жолын қосамын. Бұл annotation ішіндегі мән сипаттар файлындағы өріске сәйкес келетінін білдіреді. Сондықтан application.properties файлына жаңа жолды қосамыз:
javarush.api.path=https://javarush.com/api/1.0/rest
Бұл мән енді барлық API клиенттері үшін бір жерде болады және API жолы өзгерсе, біз оны жылдам жаңартамыз. Бұрын мен микроскоппен шеге соқтым, Unirest арқылы http сұрауынан жауап алдым, оны жіпке аудардым, содан кейін Джексон арқылы осы жолды талдадым... Бұл қорқынышты, жалықтырады және көптеген қосымша нәрселерді қажет етті. Бұл кітапханада оның қалай көрінетінін көруге болады. Қолыма түскен бойда барлығын қайта өңдеймін.
Бұл кітапхананы жаңартуға тырысқысы келетін кез келген адам - ​​тек unirest кітапханасының құралдарын пайдаланып қабылдау нысандарын қосыңыз - жеке хабарламаға немесе кітапхананың өзінде жаңа шығарылым ретінде жазыңыз. Бұл сіз үшін нақты жұмыс тәжірибесі болады, бірақ мен қарсы емеспін. Мен толық codeты қарап шығуды жүргіземін және қажет болса көмектесемін.
Енді сұрақ: біздің code біз күткендей жұмыс істей ме? Жауап оңай: олар үшін тесттер жазу керек. Мен бірнеше рет айтқанымдай, әзірлеушілер сынақтарды жаза білуі керек. Сондықтан, Swagger UI арқылы біз сұрауларды жібереміз, жауаптарды қараймыз және оларды күтілетін нәтиже ретінде сынақтарға ауыстырамыз. Топтардың саны тұрақты емес және өзгеруі мүмкін екенін бірден байқаған боларсыз. Ал сіз дұрыссыз. Жалғыз сұрақ - бұл сан қаншалықты жиі өзгереді? Өте сирек, сондықтан бірнеше ай ішінде бұл мән статикалық болады деп айта аламыз. Ал егер бірдеңе өзгерсе, біз сынақтарды жаңартамыз. Кездесу - JavaRushGroupClientTest:
package com.github.javarushcommunity.jrtb.javarushclient;

import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupDiscussionInfo;
import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupInfo;
import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupRequestArgs;
import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupsCountRequestArgs;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.util.List;

import static com.github.javarushcommunity.jrtb.javarushclient.dto.GroupInfoType.TECH;

@DisplayName("Integration-level testing for JavaRushGroupClientImplTest")
class JavaRushGroupClientTest {

   private final JavaRushGroupClient groupClient = new JavaRushGroupClientImpl("https://javarush.com/api/1.0/rest");

   @Test
   public void shouldProperlyGetGroupsWithEmptyArgs() {
       //given
       GroupRequestArgs args = GroupRequestArgs.builder().build();

       //when
       List<GroupInfo> groupList = groupClient.getGroupList(args);

       //then
       Assertions.assertNotNull(groupList);
       Assertions.assertFalse(groupList.isEmpty());
   }

   @Test
   public void shouldProperlyGetWithOffSetAndLimit() {
       //given
       GroupRequestArgs args = GroupRequestArgs.builder()
               .offset(1)
               .limit(3)
               .build();

       //when
       List<GroupInfo> groupList = groupClient.getGroupList(args);

       //then
       Assertions.assertNotNull(groupList);
       Assertions.assertEquals(3, groupList.size());
   }

   @Test
   public void shouldProperlyGetGroupsDiscWithEmptyArgs() {
       //given
       GroupRequestArgs args = GroupRequestArgs.builder().build();

       //when
       List<GroupDiscussionInfo> groupList = groupClient.getGroupDiscussionList(args);

       //then
       Assertions.assertNotNull(groupList);
       Assertions.assertFalse(groupList.isEmpty());
   }

   @Test
   public void shouldProperlyGetGroupDiscWithOffSetAndLimit() {
       //given
       GroupRequestArgs args = GroupRequestArgs.builder()
               .offset(1)
               .limit(3)
               .build();

       //when
       List<GroupDiscussionInfo> groupList = groupClient.getGroupDiscussionList(args);

       //then
       Assertions.assertNotNull(groupList);
       Assertions.assertEquals(3, groupList.size());
   }

   @Test
   public void shouldProperlyGetGroupCount() {
       //given
       GroupsCountRequestArgs args = GroupsCountRequestArgs.builder().build();

       //when
       Integer groupCount = groupClient.getGroupCount(args);

       //then
       Assertions.assertEquals(30, groupCount);
   }

   @Test
   public void shouldProperlyGetGroupTECHCount() {
       //given
       GroupsCountRequestArgs args = GroupsCountRequestArgs.builder()
               .type(TECH)
               .build();

       //when
       Integer groupCount = groupClient.getGroupCount(args);

       //then
       Assertions.assertEquals(7, groupCount);
   }

   @Test
   public void shouldProperlyGetGroupById() {
       //given
       Integer androidGroupId = 16;

       //when
       GroupDiscussionInfo groupById = groupClient.getGroupById(androidGroupId);

       //then
       Assertions.assertNotNull(groupById);
       Assertions.assertEquals(16, groupById.getId());
       Assertions.assertEquals(TECH, groupById.getType());
       Assertions.assertEquals("android", groupById.getKey());
   }
}
Тесттер бұрынғы стильде жазылған. Әрбір сұрау үшін бірнеше сынақтар бар. Барлығын сынаудың қажеті жоқ, өйткені бұл API ең жақсы түрде сыналған деп ойлаймын.

Қорытынды

Осы мақаланың бөлігі ретінде біз JavaRush API жүйесіне топтарға арналған Java клиентін қостық. Олар айтқандай, өмір сүріп, үйреніңіз. Мен осы клиентті жазған кезде мен олардың құжаттамасының артықшылығын пайдаланып, олар ұсынатын нысандармен жұмысты ыңғайлы түрде қолдандым. Назарларыңызды мен ұсынған тапсырмаға аударамын. Егер біреуді қызықтырса, маған жеке хабарлама жазыңыз, бұл өте қызықты тәжірибе болатынына сенімдімін. Бұл бірінші бөлім болды. Екіншіден, біз қосу пәрменін тікелей орындаймыз және (егер біз оны бір мақалаға сыйғызсақ) пайдаланушы жазылған топтардың тізімін алуды қосамыз. Әрі қарай, кімде-кім ботқа мәтін жазуға ынтасы бар болса, маған ПМ хат жазыңыз. Мен бұл мәселеде сарапшы емеспін және кез келген көмек өте пайдалы болар еді. Осының бәрін ашық codeты әзірлеу ретінде ресімдейік, бұл қызықты болады! Әдеттегідей - лайк басыңыз, жазылыңыз, қоңырау шалыңыз , жобамызға жұлдызша беріңіз , пікір қалдырыңыз және мақаланы бағалаңыз!
пайдалы сілтемелер

Сериядағы барлық материалдардың тізімі осы мақаланың басында.

Пікірлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION