JavaRush /Java Blog /Random-TL /Pagdaragdag ng kliyente sa mga artikulo - "Proyekto ng Ja...

Pagdaragdag ng kliyente sa mga artikulo - "Proyekto ng Java mula A hanggang Z"

Nai-publish sa grupo
Kumusta sa lahat, mahal kong mga kaibigan. Hakbang-hakbang ay papalapit na kami sa aming layunin - ang maging MVP ng aming proyekto - JavaRush Telegram Bot. Gaya ng sinabi ko sa huling artikulo, 5 na lang ang natitira. Ngayon ay tatalakayin natin ang dalawa sa kanila. "Proyekto ng Java mula A hanggang Z": Pagdaragdag ng kliyente sa mga artikulo - 1Gusto kong ulitin na hindi dito magtatapos ang proyekto. Mayroon pa akong isang tonelada ng mga ideya at pangitain kung paano dapat umunlad ang proyektong ito, kung ano ang mga bagong bagay na maaaring idagdag dito, kung ano ang maaaring gawin nang mas mahusay. Bago ang MVP, gagawa kami ng isang hiwalay na artikulo sa paksa ng refactoring - iyon ay, tungkol sa pagpapabuti ng kalidad ng code nang hindi binabago ang pag-andar nito. Sa oras na iyon, makikita na ang buong proyekto at magiging malinaw kung ano at saan mapapabuti. Sa aming kaso, kami ay lubos na mapoprotektahan mula sa paglabag sa pag-andar, dahil maraming mga pagsubok ang naisulat. Magsusulat din kami ng retrospective sa kung ano ang gusto namin at kung ano ang nakuha namin sa huli. Ito ay isang napaka-kapaki-pakinabang na bagay: tingnan natin kung gaano katama ang lahat ng nakita anim na buwan na ang nakalipas. Hindi bababa sa ito ay napaka-interesante sa akin. Kung sinuman ang gustong subukan ang kanilang sarili bilang manu-manong tester, sumulat sa amin at makikipagtulungan kami. Sabay-sabay nating pahusayin ang proyektong ito! Kaya, narito sila: dalawang gawain na inilarawan anim na buwan na ang nakalipas: JRTB-8 at JRTB-9 . Sinimulan kong tingnan kung ano ang kailangang ipatupad para sa mga gawaing ito, at napagtanto ko na sa mga tuntunin ng paglulunsad ng mga utos, handa na ang lahat. Nangyayari ito...) Dito, maaari mong tingnan ang StartCommand , ang execute method :
@Override
public void execute(Update update) {
   String chatId = update.getMessage().getChatId().toString();

   telegramUserService.findByChatId(chatId).ifPresentOrElse(
           user -> {
               user.setActive(true);
               telegramUserService.save(user);
           },
           () -> {
               TelegramUser telegramUser = new TelegramUser();
               telegramUser.setActive(true);
               telegramUser.setChatId(chatId);
               telegramUserService.save(telegramUser);
           });

   sendBotMessageService.sendMessage(chatId, START_MESSAGE);
}
Gumagana ang logic dito: kung ang aming database ay mayroon nang ganoong user sa pamamagitan ng chatId, itinakda lang namin ang active = true field para sa kanya. At kung walang ganoong user, gumawa kami ng bago. Pareho para sa /stop command sa StopCommand :
@Override
public void execute(Update update) {
   telegramUserService.findByChatId(update.getMessage().getChatId().toString())
           .ifPresent(it -> {
               it.setActive(false);
               telegramUserService.save(it);
           });
   sendBotMessageService.sendMessage(update.getMessage().getChatId().toString(), STOP_MESSAGE);
}
Makikita na kapag tinawag ang command na ito, ang active = false field lang ang nakatakda para sa user. At iyon lang: mabubuhay ang kanyang mga subscription at maghihintay sa mga pakpak kapag nagpasya muli ang user na i-activate ang chat gamit ang bot. At tila nakumpleto na ang gawain at maaaring isara. Ngunit wala ito doon. Ang pinakamahalagang gawain ay ang lumikha ng alerto tungkol sa mga bagong artikulo sa subscription. Dito ganap na maa-update at makukumpleto ang mga gawaing ito. Ibig sabihin, hangga't hindi natin naipapatupad ang notification ng mga bagong artikulo, hindi ito maaaring isara. Samakatuwid, alagaan natin ang gawain JRTB-4 - paggawa ng tseke bawat 20 minuto at mga abiso tungkol sa mga bagong artikulo. Kaibigan! Gusto mo bang malaman kaagad kung kailan inilabas ang bagong code para sa proyekto? Kailan lalabas ang isang bagong artikulo? Sumali sa aking tg channel . Doon ko kinokolekta ang aking mga artikulo, ang aking mga saloobin, ang aking open-source na pag-unlad nang magkasama.

Ipinapatupad namin ang JRTB-4

Ano ang kailangan nating gawin bilang bahagi ng gawaing ito:
  1. Lumikha ng trabaho na pana-panahong bibisita sa lahat ng grupo kung saan mayroon kaming mga subscription sa database, pag-uri-uriin ang mga artikulo ayon sa petsa ng publikasyon at tingnan kung ang ID ng huling publikasyon ay tumutugma sa halaga sa GroupSub. Kung hindi ito tumugma, kailangan mong maunawaan nang eksakto kung gaano karaming mga artikulo ang nai-publish mula noong huling pagkakataon. Ina-update namin ang last_article_id sa GroupSub7 sa kasalukuyang estado.

  2. Kapag nakakita kami ng isang listahan ng mga nai-publish na artikulo, makikita namin ang lahat ng mga ACTIVE na gumagamit para sa mga pangkat na ito at nagpapadala sa kanila ng mga abiso tungkol sa mga bagong artikulo.

Upang gawin ito, gagamitin namin ang isang bagay bilang Spring Scheduler. Ito ay isang mekanismo sa Spring Framework, kasama nito maaari kang lumikha ng mga gawain na isasagawa sa isang tiyak na oras. Alinman sa bawat 15-20-40 minuto, o tuwing Huwebes sa 15:30 o ilang iba pang opsyon. Tinatawag din silang tracing paper mula sa English - joba. Habang ginagawa natin ang gawaing ito, sadyang mag-iiwan ako ng isang depekto sa paghahanap ng mga bagong artikulo. Ito ay medyo bihira at lumitaw lamang sa isang sitwasyon kung saan mano-mano kong sinubukan ang pagpapatakbo ng gawaing ito. Upang gawin ito kailangan mong magsulat ng isang kliyente para sa paghahanap ng mga artikulo. Para magawa ito, gagamitin namin ang Swagger API na pamilyar na sa amin . Mayroong isang post-controller. Interesado lang kaming maghanap ng koleksyon ng mga artikulo gamit ang ilang partikular na mga filter:
/api/1.0/rest/posts Kumuha ng mga post sa pamamagitan ng mga filter
Makikipagtulungan kami sa kahilingang ito. Ano ang kailangan natin dito? Kumuha ng listahan ng mga artikulong kabilang sa isang partikular na grupo, at dapat na pagbukud-bukurin ang mga ito ayon sa petsa ng publikasyon. Sa ganitong paraan maaari naming kunin ang huling 15 na artikulo at suriin kung ang mga bagong publikasyon ay nai-publish batay sa lastArticleId mula sa aming database. Kung mayroon man, ipapasa namin ang mga ito para sa pagproseso at pagpapadala sa gumagamit. Kaya kailangan nating isulat ang JavaRushPostClient .

Nagsusulat kami ng JavaRushPostClient

Dito hindi namin susubukan na sakupin ang lahat ng mga kahilingang ipinadala sa amin sa API at gagawa lang ng kailangan namin. Sa paggawa nito, nakakamit natin ang dalawang layunin nang sabay-sabay:
  1. Pinapabilis namin ang proseso ng pagsulat ng aming aplikasyon.

  2. Ipinauubaya namin ang gawaing ito sa mga gustong tumulong sa aming komunidad at magpasya na subukan ang kanilang sarili bilang isang developer. Gagawa ako ng mga gawain para dito na maaaring tapusin pagkatapos ng MVP.

Kaya gawin na natin. Upang i-query ang seksyong Mga Modelo sa Swagger UI, gagawa kami ng mga sumusunod na DTO:"Proyekto ng Java mula A hanggang Z": Pagdaragdag ng kliyente sa mga artikulo - 2

BaseUserInfo:

package com.github.javarushcommunity.jrtb.javarushclient.dto;

import lombok.Data;

/**
* DTO, which represents base user information.
*/
@Data
public class BaseUserInfo {
   private String city;
   private String country;
   private String displayName;
   private Integer id;
   private String job;
   private String key;
   private Integer level;
   private String pictureUrl;
   private String position;
   private UserPublicStatus publicStatus;
   private String publicStatusMessage;
   private Integer rating;
   private Integer userId;
}

Wika:

package com.github.javarushcommunity.jrtb.javarushclient.dto;

/**
* DTO, which represents languages.
*/
public enum Language {
   UNKNOWN,
   ENGLISH,
   GERMAN,
   SPANISH,
   HINDI,
   FRENCH,
   PORTUGUESE,
   POLISH,
   BENGALI,
   PUNJABI,
   CHINESE,
   ITALIAN,
   INDONESIAN,
   MARATHI,
   TAMIL,
   TELUGU,
   JAPANESE,
   KOREAN,
   URDU,
   TAIWANESE,
   NETHERLANDS,
   RUSSIAN,
   UKRAINIAN
}

LikesInfo:

package com.github.javarushcommunity.jrtb.javarushclient.dto;

/**
* DTO, which represents like's information.
*/
public class LikesInfo {

   private Integer count;
   private LikeStatus status;
}

LikeStatus:

package com.github.javarushcommunity.jrtb.javarushclient.dto;

/**
* DTO, which represents like's status.
*/
public enum LikeStatus {

   UNKNOWN,
   LIKE,
   HOT,
   FOLLOW,
   FAVORITE,
   SOLUTION,
   HELPFUL,
   ARTICLE,
   OSCAR,
   DISLIKE,
   WRONG,
   SPAM,
   ABUSE,
   FOUL,
   TROLLING,
   OFFTOPIC,
   DUPLICATE,
   DIRTY,
   OUTDATED,
   BORING,
   UNCLEAR,
   HARD,
   EASY,
   FAKE,
   SHAM,
   AWFUL
}

Uri ng Post:

package com.github.javarushcommunity.jrtb.javarushclient.dto;

/**
* DTO, which represents post types.
*/
public enum PostType {
   UNKNOWN, USUAL, INNER_LINK, OUTER_LINK
}

UserPublicStatus:

package com.github.javarushcommunity.jrtb.javarushclient.dto;

/**
* DTO, which represents user public status.
*/
public enum UserPublicStatus {
   UNKNOWN,
   BEGINNER,
   ACTIVE,
   STRONG,
   GRADUATED,
   INTERNSHIP_IN_PROGRESS,
   INTERNSHIP_COMPLETED,
   RESUME_COMPLETED,
   LOOKING_FOR_JOB,
   HAVE_JOB;
}

VisibilityStatus:
package com.github.javarushcommunity.jrtb.javarushclient.dto;

/**
* DTO, which represents visibility status.
*/
public enum VisibilityStatus {
   UNKNOWN,
   RESTRICTED,
   PUBLIC,
   PROTECTED,
   PRIVATE,
   DISABLED,
   DELETED
}
Batay sa lahat ng mga DTO na ito, sumulat tayo ng isang pangunahing klase upang makatanggap ng mga artikulo:

PostInfo:

package com.github.javarushcommunity.jrtb.javarushclient.dto;

import lombok.Data;

/**
* DTO, which represents post information.
*/
@Data
public class PostInfo {

   private BaseUserInfo authorInfo;
   private Integer commentsCount;
   private String content;
   private Long createdTime;
   private String description;
   private GroupInfo groupInfo;
   private Integer id;
   private String key;
   private Language language;
   private LikesInfo likesInfo;
   private GroupInfo originalGroupInfo;
   private String pictureUrl;
   private Double rating;
   private Integer ratingCount;
   private String title;
   private PostType type;
   private Long updatedTime;
   private UserDiscussionInfo userDiscussionInfo;
   private Integer views;
   private VisibilityStatus visibilityStatus;

}
Ngayon, gumawa tayo ng interface na gagamitin at ang pagpapatupad nito. Kakailanganin lamang namin ng isang paraan upang gumana sa mga artikulo:

JavaRushPostClient:

package com.github.javarushcommunity.jrtb.javarushclient;

import com.github.javarushcommunity.jrtb.javarushclient.dto.PostInfo;

import java.util.List;

/**
* Client for Javarush Open API corresponds to Posts.
*/
public interface JavaRushPostClient {

   /**
    * Find new posts since lastPostId in provided group.
    *
    * @param groupId provided group ID.
    * @param lastPostId provided last post ID.
    * @return the collection of the new {@link PostInfo}.
    */
   List<PostInfo> findNewPosts(Integer groupId, Integer lastPostId);
}
Ang findNewPosts ay tumatagal ng dalawang argumento: ang group ID at ang huling ID ng artikulo na nai-post na ng bot. Samakatuwid, ang lahat ng mga artikulong iyon na nai-publish sa ibang pagkakataon kaysa sa artikulong may lastPostId ay ipapadala . At ang pagpapatupad nito:
package com.github.javarushcommunity.jrtb.javarushclient;

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

import java.util.ArrayList;
import java.util.List;

@Component
public class JavaRushPostClientImpl implements JavaRushPostClient {

   private final String javarushApiPostPath;

   public JavaRushPostClientImpl(@Value("${javarush.api.path}") String javarushApi) {
       this.javarushApiPostPath = javarushApi + "/posts";
   }

   @Override
   public List<PostInfo> findNewPosts(Integer groupId, Integer lastPostId) {
       List<PostInfo> lastPostsByGroup = Unirest.get(javarushApiPostPath)
               .queryString("order", "NEW")
               .queryString("groupKid", groupId)
               .queryString("limit", 15)
               .asObject(new GenericType<List<PostInfo>>() {
               }).getBody();
       List<PostInfo> newPosts = new ArrayList<>();
       for (PostInfo post : lastPostsByGroup) {
           if (lastPostId.equals(post.getId())) {
               return newPosts;
           }
           newPosts.add(post);
       }
       return newPosts;
   }
}
Nagdagdag kami ng ilang mga filter sa kahilingan:
  • order = BAGO - upang ang listahan ay naglalaman ng mga bago;
  • groupKid = groupId - maghanap lamang ng ilang grupo;
  • limit = 15 — nililimitahan namin ang bilang ng mga artikulo sa bawat kahilingan. Ang dalas namin ay 15-20 minuto at inaasahan namin na sa panahong ito ay hindi hihigit sa 15 (!) ang isusulat.
Susunod, kapag nakahanap na kami ng mga artikulo, tatakbo kami sa listahan at naghahanap ng mga bago. Ang algorithm ay simple at intuitive. Kung nais mong pagbutihin ito, sumulat). Sumulat tayo ng isang simpleng pagsubok para sa kliyenteng ito:
package com.github.javarushcommunity.jrtb.javarushclient;

import com.github.javarushcommunity.jrtb.javarushclient.dto.PostInfo;
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.JavaRushGroupClientTest.JAVARUSH_API_PATH;

@DisplayName("Integration-level testing for JavaRushPostClient")
class JavaRushPostClientTest {

   private final JavaRushPostClient postClient = new JavaRushPostClientImpl(JAVARUSH_API_PATH);

   @Test
   public void shouldProperlyGetNew15Posts() {
       //when
       List<PostInfo> newPosts = postClient.findNewPosts(30, 2935);

       //then
       Assertions.assertEquals(15, newPosts.size());
   }
}
Ito ay isang napakasimpleng pagsubok na nagsusuri kung mayroong anumang komunikasyon sa kliyente o wala. Nakahanap siya ng 15 bagong artikulo sa grupo ng mga proyekto ng Java, dahil binigay ko sa kanya ang ID ng unang artikulo sa grupong ito, at mayroon nang higit sa 15 sa kanila... Mayroon na silang 22! Hindi ko akalain na magiging ganito karami sila. Paano ko nalaman agad? Sa tingin mo ba nagpunta siya upang bilangin ang mga ito? Hindi) Gumamit ako ng swager at tiningnan ang bilang ng mga artikulo para sa isang partikular na grupo. Oo nga pala, maaari kang tumingin ng ganito sa iba... At gaano karaming mga artikulo ang nasa RANDOM na grupo?... Sasabihin ko sa iyo ngayon: mayroong 1062 sa kanila! Grabe ang dami.

Katapusan ng unang bahagi

Dito nagdagdag kami ng trabaho kasama ang kliyente ayon sa artikulo. Nagawa na namin ang lahat, sa pagkakataong ito sa tingin ko dapat simple at mabilis ang lahat. Sa susunod na artikulo idaragdag namin ang Spring Scheduler at isusulat ang FindNewArticleService . Well, gaya ng dati, i-like - mag-subscribe - i-ring ang kampana , bigyan ang aming proyekto ng bituin , magsulat ng mga komento at i-rate ang artikulo! Salamat sa lahat ng nagbabasa - see you soon!

Ang isang listahan ng lahat ng mga materyales sa serye ay nasa simula ng artikulong ito.

Mga komento
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION