feat: support set path suffix.

pull/484/head
ruibaby 2020-01-07 20:16:11 +08:00
parent 13ab09b799
commit bb58dd5ec4
10 changed files with 209 additions and 158 deletions

View File

@ -1,13 +1,7 @@
package run.halo.app.controller.content;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.PageUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.web.SortDefault;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
@ -16,13 +10,11 @@ import run.halo.app.cache.lock.CacheLock;
import run.halo.app.controller.content.model.PostModel;
import run.halo.app.model.entity.Post;
import run.halo.app.model.enums.PostStatus;
import run.halo.app.model.vo.PostListVO;
import run.halo.app.service.*;
import run.halo.app.service.OptionService;
import run.halo.app.service.PostService;
import java.util.concurrent.TimeUnit;
import static org.springframework.data.domain.Sort.Direction.DESC;
/**
* Blog archive page controller
*
@ -38,14 +30,6 @@ public class ContentArchiveController {
private final PostService postService;
private final ThemeService themeService;
private final PostCategoryService postCategoryService;
private final PostMetaService postMetaService;
private final PostTagService postTagService;
private final OptionService optionService;
private final StringCacheStore cacheStore;
@ -53,18 +37,10 @@ public class ContentArchiveController {
private final PostModel postModel;
public ContentArchiveController(PostService postService,
ThemeService themeService,
PostCategoryService postCategoryService,
PostMetaService postMetaService,
PostTagService postTagService,
OptionService optionService,
StringCacheStore cacheStore,
PostModel postModel) {
this.postService = postService;
this.themeService = themeService;
this.postCategoryService = postCategoryService;
this.postMetaService = postMetaService;
this.postTagService = postTagService;
this.optionService = optionService;
this.cacheStore = cacheStore;
this.postModel = postModel;
@ -78,7 +54,7 @@ public class ContentArchiveController {
*/
@GetMapping
public String archives(Model model) {
return this.archives(model, 1, Sort.by(DESC, "createTime"));
return this.archives(model, 1);
}
/**
@ -89,36 +65,8 @@ public class ContentArchiveController {
*/
@GetMapping(value = "page/{page}")
public String archives(Model model,
@PathVariable(value = "page") Integer page,
@SortDefault(sort = "createTime", direction = DESC) Sort sort) {
Pageable pageable = PageRequest.of(page - 1, optionService.getPostPageSize(), sort);
Page<Post> postPage = postService.pageBy(PostStatus.PUBLISHED, pageable);
Page<PostListVO> postListVos = postService.convertToListVo(postPage);
int[] pageRainbow = PageUtil.rainbow(page, postListVos.getTotalPages(), 3);
model.addAttribute("is_archives", true);
model.addAttribute("pageRainbow", pageRainbow);
model.addAttribute("posts", postListVos);
return themeService.render("archives");
}
/**
* Render post page.
*
* @param url post slug url.
* @param token view token.
* @param model model
* @return template path: themes/{theme}/post.ftl
*/
@GetMapping("{url}")
public String post(@PathVariable("url") String url,
@RequestParam(value = "token", required = false) String token,
Model model) {
Post post = postService.getByUrl(url);
return postModel.post(post, token, model);
@PathVariable(value = "page") Integer page) {
return postModel.list(page, model, "is_archives", "archives");
}
@GetMapping(value = "{url}/password")

View File

@ -0,0 +1,71 @@
package run.halo.app.controller.content;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import run.halo.app.controller.content.model.PostModel;
import run.halo.app.controller.content.model.SheetModel;
import run.halo.app.exception.NotFoundException;
import run.halo.app.model.entity.Post;
import run.halo.app.model.entity.Sheet;
import run.halo.app.model.enums.PostPermalinkType;
import run.halo.app.model.properties.PermalinkProperties;
import run.halo.app.service.OptionService;
import run.halo.app.service.PostService;
import run.halo.app.service.SheetService;
/**
* @author ryanwang
* @date 2020-01-07
*/
@Slf4j
@Controller
@RequestMapping
public class ContentContentController {
private final PostModel postModel;
private final SheetModel sheetModel;
private final OptionService optionService;
private final PostService postService;
private final SheetService sheetService;
public ContentContentController(PostModel postModel,
SheetModel sheetModel,
OptionService optionService,
PostService postService,
SheetService sheetService) {
this.postModel = postModel;
this.sheetModel = sheetModel;
this.optionService = optionService;
this.postService = postService;
this.sheetService = sheetService;
}
@GetMapping("{prefix}/{url}")
public String content(@PathVariable("prefix") String prefix,
@PathVariable("url") String url,
@RequestParam(value = "token", required = false) String token,
Model model) {
PostPermalinkType postPermalinkType = optionService.getPostPermalinkType();
String archivesPrefix = optionService.getByPropertyOrDefault(PermalinkProperties.ARCHIVES_PREFIX, String.class, PermalinkProperties.ARCHIVES_PREFIX.defaultValue());
String sheetPrefix = optionService.getByPropertyOrDefault(PermalinkProperties.SHEET_PREFIX, String.class, PermalinkProperties.SHEET_PREFIX.defaultValue());
if (postPermalinkType.equals(PostPermalinkType.DEFAULT) && archivesPrefix.equals(prefix)) {
Post post = postService.getByUrl(url);
return postModel.content(post, token, model);
} else if (sheetPrefix.equals(prefix)) {
Sheet sheet = sheetService.getByUrl(url);
return sheetModel.content(sheet, token, model);
} else {
throw new NotFoundException("Not Found");
}
}
}

View File

@ -1,11 +1,6 @@
package run.halo.app.controller.content;
import cn.hutool.core.util.PageUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@ -14,17 +9,11 @@ import org.springframework.web.bind.annotation.RequestMapping;
import run.halo.app.controller.content.model.PostModel;
import run.halo.app.model.entity.Post;
import run.halo.app.model.enums.PostPermalinkType;
import run.halo.app.model.enums.PostStatus;
import run.halo.app.model.properties.PostProperties;
import run.halo.app.model.vo.PostListVO;
import run.halo.app.service.OptionService;
import run.halo.app.service.PostService;
import run.halo.app.service.ThemeService;
import java.util.Objects;
import static org.springframework.data.domain.Sort.Direction.DESC;
/**
* Blog index page controller
*
@ -40,17 +29,13 @@ public class ContentIndexController {
private final OptionService optionService;
private final ThemeService themeService;
private final PostModel postModel;
public ContentIndexController(PostService postService,
OptionService optionService,
ThemeService themeService,
PostModel postModel) {
this.postService = postService;
this.optionService = optionService;
this.themeService = themeService;
this.postModel = postModel;
}
@ -69,7 +54,7 @@ public class ContentIndexController {
if (PostPermalinkType.ID.equals(permalinkType) && !Objects.isNull(p)) {
Post post = postService.getById(p);
return postModel.post(post, token, model);
return postModel.content(post, token, model);
}
return this.index(model, 1);
@ -85,18 +70,6 @@ public class ContentIndexController {
@GetMapping(value = "page/{page}")
public String index(Model model,
@PathVariable(value = "page") Integer page) {
String indexSort = optionService.getByPropertyOfNonNull(PostProperties.INDEX_SORT).toString();
int pageSize = optionService.getPostPageSize();
Pageable pageable = PageRequest.of(page >= 1 ? page - 1 : page, pageSize, Sort.by(DESC, "topPriority").and(Sort.by(DESC, indexSort)));
Page<Post> postPage = postService.pageBy(PostStatus.PUBLISHED, pageable);
Page<PostListVO> posts = postService.convertToListVo(postPage);
int[] rainbow = PageUtil.rainbow(page, posts.getTotalPages(), 3);
model.addAttribute("is_index", true);
model.addAttribute("posts", posts);
model.addAttribute("rainbow", rainbow);
return themeService.render("index");
return postModel.list(page, model, "is_index", "index");
}
}

View File

@ -1,6 +1,5 @@
package run.halo.app.controller.content;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
@ -10,17 +9,9 @@ import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import run.halo.app.cache.StringCacheStore;
import run.halo.app.exception.ForbiddenException;
import run.halo.app.model.dto.PhotoDTO;
import run.halo.app.model.entity.Sheet;
import run.halo.app.model.enums.PostStatus;
import run.halo.app.model.support.HaloConst;
import run.halo.app.model.vo.SheetDetailVO;
import run.halo.app.service.PhotoService;
import run.halo.app.service.SheetService;
import run.halo.app.service.ThemeService;
import run.halo.app.utils.MarkdownUtils;
import static org.springframework.data.domain.Sort.Direction.DESC;
@ -35,22 +26,16 @@ import static org.springframework.data.domain.Sort.Direction.DESC;
public class ContentSheetController {
private final SheetService sheetService;
private final ThemeService themeService;
private final PhotoService photoService;
private final StringCacheStore cacheStore;
public ContentSheetController(SheetService sheetService,
public ContentSheetController(
ThemeService themeService,
PhotoService photoService,
StringCacheStore cacheStore) {
this.sheetService = sheetService;
PhotoService photoService
) {
this.themeService = themeService;
this.photoService = photoService;
this.cacheStore = cacheStore;
}
/**
@ -91,50 +76,4 @@ public class ContentSheetController {
public String links() {
return themeService.render("links");
}
/**
* Render custom sheet
*
* @param url sheet url
* @param token view token
* @param model model
* @return template path: themes/{theme}/sheet.ftl
*/
@GetMapping(value = "/s/{url}")
public String sheet(@PathVariable(value = "url") String url,
@RequestParam(value = "token", required = false) String token,
Model model) {
Sheet sheet = sheetService.getByUrl(url);
if (StringUtils.isEmpty(token)) {
sheet = sheetService.getBy(PostStatus.PUBLISHED, url);
} else {
// render markdown to html when preview sheet
sheet.setFormatContent(MarkdownUtils.renderHtml(sheet.getOriginalContent()));
// verify token
String cachedToken = cacheStore.getAny(token, String.class).orElseThrow(() -> new ForbiddenException("您没有该页面的访问权限"));
if (!cachedToken.equals(token)) {
throw new ForbiddenException("您没有该页面的访问权限");
}
}
sheetService.publishVisitEvent(sheet.getId());
SheetDetailVO sheetDetailVO = sheetService.convertToDetailVo(sheet);
// sheet and post all can use
model.addAttribute("sheet", sheetDetailVO);
model.addAttribute("post", sheetDetailVO);
model.addAttribute("is_sheet", true);
// TODO,Will be deprecated
model.addAttribute("comments", Page.empty());
if (themeService.templateExists(ThemeService.CUSTOM_SHEET_PREFIX + sheet.getTemplate() + HaloConst.SUFFIX_FTL)) {
return themeService.render(ThemeService.CUSTOM_SHEET_PREFIX + sheet.getTemplate());
}
return themeService.render("sheet");
}
}

View File

@ -12,7 +12,6 @@ import run.halo.app.model.support.HaloConst;
import run.halo.app.service.OptionService;
import run.halo.app.service.UserService;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@ -48,7 +47,7 @@ public class MainController {
}
@GetMapping("${halo.admin-path:admin}")
public void admin(HttpServletRequest request, HttpServletResponse response) throws IOException {
public void admin(HttpServletResponse response) throws IOException {
String adminIndexRedirectUri = StringUtils.appendIfMissing(this.haloProperties.getAdminPath(), "/") + INDEX_REDIRECT_URI;
response.sendRedirect(adminIndexRedirectUri);
}

View File

@ -1,7 +1,11 @@
package run.halo.app.controller.content.model;
import cn.hutool.core.util.PageUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Component;
import org.springframework.ui.Model;
import run.halo.app.cache.StringCacheStore;
@ -11,15 +15,21 @@ import run.halo.app.model.entity.Post;
import run.halo.app.model.entity.PostMeta;
import run.halo.app.model.entity.Tag;
import run.halo.app.model.enums.PostStatus;
import run.halo.app.model.properties.PostProperties;
import run.halo.app.model.support.HaloConst;
import run.halo.app.model.vo.PostListVO;
import run.halo.app.service.*;
import run.halo.app.utils.MarkdownUtils;
import java.util.List;
import static org.springframework.data.domain.Sort.Direction.DESC;
/**
* @author ryan0up
* @date 2020/1/7
* Post Model
*
* @author ryanwang
* @date 2020-01-07
*/
@Component
public class PostModel {
@ -54,7 +64,7 @@ public class PostModel {
this.cacheStore = cacheStore;
}
public String post(Post post, String token, Model model) {
public String content(Post post, String token, Model model) {
if (post.getStatus().equals(PostStatus.INTIMATE) && StringUtils.isEmpty(token)) {
String redirect = String.format("%s/archives/%s/password", optionService.getBlogBaseUrl(), post.getUrl());
@ -92,4 +102,21 @@ public class PostModel {
return themeService.render("post");
}
public String list(Integer page, Model model, String decide, String template) {
String indexSort = optionService.getByPropertyOfNonNull(PostProperties.INDEX_SORT).toString();
int pageSize = optionService.getPostPageSize();
Pageable pageable = PageRequest.of(page >= 1 ? page - 1 : page, pageSize, Sort.by(DESC, "topPriority").and(Sort.by(DESC, indexSort)));
Page<Post> postPage = postService.pageBy(PostStatus.PUBLISHED, pageable);
Page<PostListVO> posts = postService.convertToListVo(postPage);
int[] rainbow = PageUtil.rainbow(page, posts.getTotalPages(), 3);
model.addAttribute(decide, true);
model.addAttribute("posts", posts);
model.addAttribute("rainbow", rainbow);
model.addAttribute("pageRainbow", rainbow);
return themeService.render(template);
}
}

View File

@ -0,0 +1,66 @@
package run.halo.app.controller.content.model;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Component;
import org.springframework.ui.Model;
import run.halo.app.cache.StringCacheStore;
import run.halo.app.exception.ForbiddenException;
import run.halo.app.model.entity.Sheet;
import run.halo.app.model.support.HaloConst;
import run.halo.app.model.vo.SheetDetailVO;
import run.halo.app.service.SheetService;
import run.halo.app.service.ThemeService;
import run.halo.app.utils.MarkdownUtils;
/**
* Sheet model.
*
* @author ryanwang
* @date 2020-01-07
*/
@Component
public class SheetModel {
private final SheetService sheetService;
private final StringCacheStore cacheStore;
private final ThemeService themeService;
public SheetModel(SheetService sheetService, StringCacheStore cacheStore, ThemeService themeService) {
this.sheetService = sheetService;
this.cacheStore = cacheStore;
this.themeService = themeService;
}
public String content(Sheet sheet, String token, Model model) {
if (!StringUtils.isEmpty(token)) {
// render markdown to html when preview sheet
sheet.setFormatContent(MarkdownUtils.renderHtml(sheet.getOriginalContent()));
// verify token
String cachedToken = cacheStore.getAny(token, String.class).orElseThrow(() -> new ForbiddenException("您没有该页面的访问权限"));
if (!cachedToken.equals(token)) {
throw new ForbiddenException("您没有该页面的访问权限");
}
}
sheetService.publishVisitEvent(sheet.getId());
SheetDetailVO sheetDetailVO = sheetService.convertToDetailVo(sheet);
// sheet and post all can use
model.addAttribute("sheet", sheetDetailVO);
model.addAttribute("post", sheetDetailVO);
model.addAttribute("is_sheet", true);
// TODO,Will be deprecated
model.addAttribute("comments", Page.empty());
if (themeService.templateExists(ThemeService.CUSTOM_SHEET_PREFIX + sheet.getTemplate() + HaloConst.SUFFIX_FTL)) {
return themeService.render(ThemeService.CUSTOM_SHEET_PREFIX + sheet.getTemplate());
}
return themeService.render("sheet");
}
}

View File

@ -37,7 +37,13 @@ public enum PermalinkProperties implements PropertyEnum {
* Sheet prefix
* such as: /s/${url}
*/
SHEET_PREFIX("sheet_prefix", String.class, "s");
SHEET_PREFIX("sheet_prefix", String.class, "s"),
/**
* Path suffix
* such as: .html or .jsp
*/
PATH_SUFFIX("path_suffix", String.class, "");
private final String value;

View File

@ -24,8 +24,10 @@ import run.halo.app.model.dto.TagDTO;
import run.halo.app.model.dto.post.BasePostDetailDTO;
import run.halo.app.model.entity.*;
import run.halo.app.model.enums.LogType;
import run.halo.app.model.enums.PostPermalinkType;
import run.halo.app.model.enums.PostStatus;
import run.halo.app.model.params.PostQuery;
import run.halo.app.model.properties.PermalinkProperties;
import run.halo.app.model.vo.ArchiveMonthVO;
import run.halo.app.model.vo.ArchiveYearVO;
import run.halo.app.model.vo.PostDetailVO;
@ -450,6 +452,12 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
String blogUrl = optionService.getBlogBaseUrl();
PostPermalinkType permalinkType = optionService.getPostPermalinkType();
String pathSuffix = optionService.getByPropertyOrDefault(PermalinkProperties.PATH_SUFFIX, String.class, "");
String archivesPrefix = optionService.getByPropertyOrDefault(PermalinkProperties.ARCHIVES_PREFIX, String.class, "");
return postPage.map(post -> {
PostListVO postListVO = new PostListVO().convertFrom(post);
@ -486,6 +494,20 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
// Set comment count
postListVO.setCommentCount(commentCountMap.getOrDefault(post.getId(), 0L));
StringBuilder fullPath = new StringBuilder(blogUrl);
if (permalinkType.equals(PostPermalinkType.DEFAULT)) {
fullPath.append("/")
.append(archivesPrefix)
.append("/")
.append(postListVO.getUrl())
.append(pathSuffix);
} else if (permalinkType.equals(PostPermalinkType.ID)) {
fullPath.append("/?p=")
.append(postListVO.getId());
}
postListVO.setFullPath(fullPath.toString());
return postListVO;
});
}

View File

@ -2,7 +2,7 @@
<div class="post animated fadeInDown">
<div class="post-title">
<h3>
<a href="${context!}/archives/${post.url}">${post.title}</a>
<a href="${post.fullPath!}">${post.title}</a>
</h3>
</div>
<div class="post-content">