Skip to content

Commit

Permalink
ленивая загрузка изображений в ленте
Browse files Browse the repository at this point in the history
  • Loading branch information
maxcom committed Jan 2, 2025
1 parent 87581de commit 3ebb1b2
Show file tree
Hide file tree
Showing 12 changed files with 79 additions and 110 deletions.
18 changes: 8 additions & 10 deletions src/main/java/ru/org/linux/tag/TagPageController.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 1998-2024 Linux.org.ru
* Copyright 1998-2025 Linux.org.ru
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
Expand Down Expand Up @@ -104,11 +104,11 @@ class TagPageController(tagService: TagService, prepareService: TopicPrepareServ

val synonyms = tagService.getSynonymsFor(tagInfo.id)

val model = Map(
val model = Map[String, AnyRef](
"tag" -> tag,
"title" -> WordUtils.capitalize(tag),
"favsCount" -> userTagService.countFavs(tagInfo.id),
"ignoreCount" -> userTagService.countIgnore(tagInfo.id),
"favsCount" -> Int.box(userTagService.countFavs(tagInfo.id)),
"ignoreCount" -> Int.box(userTagService.countIgnore(tagInfo.id)),
"showAdsense" -> Boolean.box(!currentUser.authorized || !currentUser.profile.hideAdsense),
"showDelete" -> Boolean.box(currentUser.moderator),
"synonyms" -> synonyms.asJava,
Expand Down Expand Up @@ -146,7 +146,7 @@ class TagPageController(tagService: TagService, prepareService: TopicPrepareServ
(Seq.empty, newsTopics.take(TagPageController.TotalNewsCount-1))
}

val fullNews = prepareService.prepareTopicsForUser(fullNewsTopics, loadUserpics = false)
val fullNews = prepareService.prepareTopics(fullNewsTopics, loadUserpics = false)

val briefNewsByDate = TopicListTools.datePartition(briefNewsTopics)

Expand All @@ -164,7 +164,7 @@ class TagPageController(tagService: TagService, prepareService: TopicPrepareServ
None
}

(Map(
(Map[String, AnyRef](
"fullNews" -> fullNews.asJava,
"briefNews" -> TopicListTools.split(briefNewsByDate.map(p => p._1 -> prepareService.prepareBrief(p._2, groupInTitle = false)))
) ++ more ++ addNews, newestDate)
Expand All @@ -186,9 +186,7 @@ class TagPageController(tagService: TagService, prepareService: TopicPrepareServ
None
}

Map(
"gallery" -> list
) ++ add ++ more
Map[String, AnyRef]("gallery" -> list) ++ add ++ more
}

private def getTopicList(tag: String, tagId: Int, section: Int, mode: CommitMode)(implicit currentUser: AnySession) = {
Expand Down Expand Up @@ -217,7 +215,7 @@ class TagPageController(tagService: TagService, prepareService: TopicPrepareServ

val newestDate = forumTopics.headOption.map(t => Instant.ofEpochMilli(t.getEffectiveDate.getMillis))

(Map(
(Map[String, AnyRef](
forumSection.getUrlName -> TopicListTools.split(
topicByDate.map(p => p._1 -> prepareService.prepareBrief(p._2, groupInTitle = true)))
) ++ more ++ add, newestDate)
Expand Down
65 changes: 0 additions & 65 deletions src/main/java/ru/org/linux/topic/PreparedImage.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 1998-2024 Linux.org.ru
* Copyright 1998-2025 Linux.org.ru
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
Expand Down Expand Up @@ -70,13 +70,13 @@ class EditHistoryService(topicTagService: TopicTagService, userService: UserServ
val imageDeleted = this.image == null && dto.oldimage.isDefined

val addedImages = if (dto.oldaddimages.isDefined) {
this.additionalImages.filterNot(img => dto.oldaddimages.get.contains(img.getImage.id)).asJava
this.additionalImages.filterNot(img => dto.oldaddimages.get.contains(img.image.id)).asJava
} else {
null
}

val removedImages = if (dto.oldaddimages.isDefined) {
dto.oldaddimages.get.filterNot(this.additionalImages.map(_.getImage.id).contains).map(imageDao.getImage).flatMap(imageService.prepareImage).asJava
dto.oldaddimages.get.filterNot(this.additionalImages.map(_.image.id).contains).map(imageDao.getImage).flatMap(imageService.prepareImage).asJava
} else {
null
}
Expand Down
8 changes: 5 additions & 3 deletions src/main/scala/ru/org/linux/gallery/ImageService.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 1998-2024 Linux.org.ru
* Copyright 1998-2025 Linux.org.ru
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
Expand Down Expand Up @@ -74,7 +74,9 @@ class ImageService(imageDao: ImageDao, editHistoryDao: EditHistoryDao,
PreparedGalleryItem(item, userService.getUserCached(item.getUserid))
}

def prepareImage(image: Image): Option[PreparedImage] = {
def prepareImage(image: Image): Option[PreparedImage] = prepareImage(image, lazyLoad = false)

def prepareImage(image: Image, lazyLoad: Boolean): Option[PreparedImage] = {
Preconditions.checkNotNull(image)

val htmlPath = siteConfig.getUploadPath
Expand All @@ -87,7 +89,7 @@ class ImageService(imageDao: ImageDao, editHistoryDao: EditHistoryDao,
val medURI = siteConfig.getSecureUrl + mediumName
val fullURI = siteConfig.getSecureUrl + image.original

Some(new PreparedImage(medURI, mediumImageInfo, fullURI, fullInfo, image))
Some(PreparedImage(medURI, mediumImageInfo, fullURI, fullInfo, image, lazyLoad))
} catch {
case e: FileNotFoundException =>
logger.error(s"Image not found! id=${image.id}: ${e.getMessage}")
Expand Down
4 changes: 2 additions & 2 deletions src/main/scala/ru/org/linux/spring/MainPageController.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 1998-2024 Linux.org.ru
* Copyright 1998-2025 Linux.org.ru
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
Expand Down Expand Up @@ -48,7 +48,7 @@ class MainPageController(prepareService: TopicPrepareService, topicListService:

val mv = new ModelAndView("index")

mv.getModel.put("news", prepareService.prepareTopicsForUser(messages, loadUserpics = false).asJava)
mv.getModel.put("news", prepareService.prepareTopics(messages, loadUserpics = false).asJava)

val briefNewsByDate = TopicListTools.datePartition(titles)

Expand Down
34 changes: 34 additions & 0 deletions src/main/scala/ru/org/linux/topic/PreparedImage.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright 1998-2025 Linux.org.ru
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ru.org.linux.topic

import ru.org.linux.gallery.Image
import ru.org.linux.util.image.ImageInfo

import scala.beans.BeanProperty

case class PreparedImage(@BeanProperty mediumName: String, @BeanProperty mediumInfo: ImageInfo,
@BeanProperty fullName: String, @BeanProperty fullInfo: ImageInfo, @BeanProperty image: Image,
@BeanProperty lazyLoad: Boolean) {
def getSrcset: String = {
if (fullInfo.getWidth < Image.MaxScaledSize) {
image.getSrcsetUpTo(fullInfo.getWidth) + ", " + fullName + " " + fullInfo.getWidth + "w"
} else {
image.getSrcset
}
}

def getLoadingCode: String = if (lazyLoad) "loading=\"lazy\"" else ""
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 1998-2024 Linux.org.ru
* Copyright 1998-2025 Linux.org.ru
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
Expand Down Expand Up @@ -126,7 +126,7 @@ class TagTopicListController(userTagService: UserTagService, sectionService: Sec
} else {
val topics = topicListService.getTopicsFeed(section, None, Some(tag), offset, None, 20, noTalks = false, tech = false)

(prepareService.prepareTopicsForUser(topics, loadUserpics = false), 20)
(prepareService.prepareTopics(topics, loadUserpics = false), 20)
}

modelAndView.addObject("messages", preparedTopics.asJava)
Expand Down
6 changes: 3 additions & 3 deletions src/main/scala/ru/org/linux/topic/TopicListController.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 1998-2024 Linux.org.ru
* Copyright 1998-2025 Linux.org.ru
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
Expand Down Expand Up @@ -139,7 +139,7 @@ class TopicListController(sectionService: SectionService, topicListService: Topi

modelAndView.addObject(
"messages",
prepareService.prepareTopicsForUser(messages, loadUserpics = false).asJava)
prepareService.prepareTopics(messages, loadUserpics = false).asJava)

modelAndView.addObject("offsetNavigation", topicListForm.yearMonth.isEmpty)

Expand Down Expand Up @@ -282,7 +282,7 @@ class TopicListController(sectionService: SectionService, topicListService: Topi
if (lastModified.exists(webRequest.checkNotModified)) {
null
} else {
modelAndView.addObject("messages", prepareService.prepareTopics(messages.toSeq).asJava)
modelAndView.addObject("messages", prepareService.prepareTopicForRSS(messages.toSeq).asJava)

modelAndView
}
Expand Down
29 changes: 14 additions & 15 deletions src/main/scala/ru/org/linux/topic/TopicPrepareService.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 1998-2024 Linux.org.ru
* Copyright 1998-2025 Linux.org.ru
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
Expand Down Expand Up @@ -44,19 +44,19 @@ class TopicPrepareService(sectionService: SectionService, groupDao: GroupDao, de
warningService: WarningService) {
def prepareTopic(message: Topic)(implicit session: AnySession): PreparedTopic =
prepareTopic(message, topicTagService.getTagRefs(message).asScala, minimizeCut = false, None,
msgbaseDao.getMessageText(message.id), image = None)
msgbaseDao.getMessageText(message.id), image = None, imageLazyLoad = false)

def prepareTopic(message: Topic, tags: collection.Seq[TagRef], text: MessageText,
warnings: Seq[Warning])(implicit session: AnySession): PreparedTopic =
prepareTopic(message, tags, minimizeCut = false, None, text, None, Seq.empty, warnings)
prepareTopic(message, tags, minimizeCut = false, None, text, None, Seq.empty, warnings, imageLazyLoad = false)

def prepareTopicPreview(message: Topic, tags: Seq[TagRef], newPoll: Option[Poll], text: MessageText,
image: Option[UploadedImagePreview], additionalImages: Seq[UploadedImagePreview]): PreparedTopic = {
val imageObject = image.map(_.toImage(main = true))
val additionalImageObjects = additionalImages.map(_.toImage(main = false))

prepareTopic(message, tags, minimizeCut = false, newPoll.map(pollPrepareService.preparePollPreview),
text, imageObject, additionalImageObjects)(NonAuthorizedSession)
text, imageObject, additionalImageObjects, imageLazyLoad = false)(NonAuthorizedSession)
}

def prepareEditInfo(editInfo: EditInfoSummary, topic: Topic)(implicit session: AnySession): PreparedEditInfoSummary = {
Expand All @@ -78,7 +78,8 @@ class TopicPrepareService(sectionService: SectionService, groupDao: GroupDao, de
* @return подготовленный топик
*/
private def prepareTopic(topic: Topic, tags: collection.Seq[TagRef], minimizeCut: Boolean, poll: Option[PreparedPoll],
text: MessageText, image: Option[Image], additionalImages: Seq[Image] = Seq.empty, warnings: Seq[Warning] = Seq.empty)
text: MessageText, image: Option[Image], additionalImages: Seq[Image] = Seq.empty, warnings: Seq[Warning] = Seq.empty,
imageLazyLoad: Boolean)
(implicit session: AnySession): PreparedTopic = {
val group = groupDao.getGroup(topic.groupId)
val author = userService.getUserCached(topic.authorUserId)
Expand Down Expand Up @@ -118,12 +119,11 @@ class TopicPrepareService(sectionService: SectionService, groupDao: GroupDao, de

val loadedAdditionalImage = currentImages.filterNot(_.main) ++ additionalImages

(loadedImage.flatMap(imageService.prepareImage), loadedAdditionalImage.flatMap(imageService.prepareImage))
(loadedImage.flatMap(imageService.prepareImage(_, imageLazyLoad)), loadedAdditionalImage.flatMap(imageService.prepareImage))
} else {
(None, Seq.empty)
}


val remark = session.userOpt.flatMap { user =>
remarkDao.getRemark(user, author)
}
Expand Down Expand Up @@ -161,14 +161,14 @@ class TopicPrepareService(sectionService: SectionService, groupDao: GroupDao, de
* @param loadUserpics флаг загрузки аватар
* @return список подготовленных топиков
*/
def prepareTopicsForUser(messages: collection.Seq[Topic], loadUserpics: Boolean)
(implicit user: AnySession): collection.Seq[PersonalizedPreparedTopic] = {
def prepareTopics(messages: collection.Seq[Topic], loadUserpics: Boolean)
(implicit user: AnySession): collection.Seq[PersonalizedPreparedTopic] = {
val textMap = loadTexts(messages)
val tags = topicTagService.tagRefs(messages.map(_.id))

messages.map { message =>
messages.zipWithIndex.map { case (message, idx) =>
val preparedMessage = prepareTopic(message, tags.getOrElse(message.id, Seq.empty), minimizeCut = true, None,
textMap(message.id), image = None)
textMap(message.id), image = None, imageLazyLoad = idx >= 3)

val topicMenu = getTopicMenu(preparedMessage, loadUserpics)
new PersonalizedPreparedTopic(preparedMessage, topicMenu)
Expand All @@ -179,19 +179,18 @@ class TopicPrepareService(sectionService: SectionService, groupDao: GroupDao, de
msgbaseDao.getMessageText(messages.map(_.id))

/**
* Подготовка ленты топиков, используется в TopicListController например
* сообщения рендерятся со свернутым cut
* Подготовка ленты топиков для RSS
*
* @param messages список топиков
* @return список подготовленных топиков
*/
def prepareTopics(messages: collection.Seq[Topic]): Seq[PreparedTopic] = {
def prepareTopicForRSS(messages: collection.Seq[Topic]): Seq[PreparedTopic] = {
val textMap = loadTexts(messages)
val tags = topicTagService.tagRefs(messages.map(_.id))

messages.view.map { message =>
prepareTopic(message, tags.getOrElse(message.id, Seq.empty), minimizeCut = true, None, textMap(message.id),
image = None)(NonAuthorizedSession)
image = None, imageLazyLoad = false)(NonAuthorizedSession)
}.toSeq
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 1998-2024 Linux.org.ru
* Copyright 1998-2025 Linux.org.ru
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
Expand Down Expand Up @@ -66,7 +66,7 @@ class UncommitedTopicsController(sectionService: SectionService, topicListServic

val messages = topicListService.getUncommitedTopic(section, calendar.getTime, includeAnonymous)

val topics = prepareService.prepareTopicsForUser(messages, loadUserpics = false)
val topics = prepareService.prepareTopics(messages, loadUserpics = false)

modelAndView.addObject("messages", topics.asJava)

Expand Down
Loading

0 comments on commit 3ebb1b2

Please sign in to comment.