diff --git a/blog_main/src/main/java/cn/sticki/blog/config/MybatisPlusConfig.java b/blog_main/src/main/java/cn/sticki/blog/config/MybatisPlusConfig.java index 57319e63..d40e582c 100644 --- a/blog_main/src/main/java/cn/sticki/blog/config/MybatisPlusConfig.java +++ b/blog_main/src/main/java/cn/sticki/blog/config/MybatisPlusConfig.java @@ -1,6 +1,7 @@ package cn.sticki.blog.config; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -8,10 +9,11 @@ @Configuration public class MybatisPlusConfig { - @Bean // 配置分页 + @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); - interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); + interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); // 配置分页助手 + interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor()); // 阻止恶意的全表更新删除 return interceptor; } diff --git a/blog_main/src/main/java/cn/sticki/blog/config/ResourcePath.java b/blog_main/src/main/java/cn/sticki/blog/config/ResourcePath.java index e2427f88..35231d06 100644 --- a/blog_main/src/main/java/cn/sticki/blog/config/ResourcePath.java +++ b/blog_main/src/main/java/cn/sticki/blog/config/ResourcePath.java @@ -13,6 +13,10 @@ public class ResourcePath { public static String defaultAvatar; + public static String blogImage; + + public static String blogImageUrlBase; + public void setAvatar(String avatar) { ResourcePath.avatar = avatar; } @@ -25,4 +29,12 @@ public void setDefaultAvatar(String defaultAvatar) { ResourcePath.defaultAvatar = defaultAvatar; } + public void setBlogImage(String blogImage) { + ResourcePath.blogImage = blogImage; + } + + public void setBlogImageUrlBase(String blogImageUrlBase) { + ResourcePath.blogImageUrlBase = blogImageUrlBase; + } + } \ No newline at end of file diff --git a/blog_main/src/main/java/cn/sticki/blog/config/SpringSecurityConfig.java b/blog_main/src/main/java/cn/sticki/blog/config/SpringSecurityConfig.java index 5cb0281e..e3e42a88 100644 --- a/blog_main/src/main/java/cn/sticki/blog/config/SpringSecurityConfig.java +++ b/blog_main/src/main/java/cn/sticki/blog/config/SpringSecurityConfig.java @@ -1,11 +1,11 @@ package cn.sticki.blog.config; import cn.sticki.blog.security.filter.AuthenticationTokenFilter; +import cn.sticki.blog.security.filter.IPLimitFilter; import cn.sticki.blog.security.handler.AuthAccessDeniedHandler; import cn.sticki.blog.security.handler.AuthenticationEntryPointHandler; import cn.sticki.blog.security.handler.LoginFailureHandler; import cn.sticki.blog.security.handler.LoginSuccessHandler; -import cn.sticki.blog.util.ResponseUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -57,12 +57,15 @@ public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private AuthenticationEntryPointHandler authenticationEntryPointHandler; - /** - * 自定义登录逻辑验证器 - */ + // /** + // * 自定义登录逻辑验证器 + // */ // @Autowired // private UserAuthenticationProvider userAuthenticationProvider; + /** + * 用户认证过滤器 + */ @Autowired private AuthenticationTokenFilter authenticationTokenFilter; // @@ -73,7 +76,7 @@ public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { // private AccessDeniedHandler accessDeniedHandler; @Autowired - private ResponseUtils responseUtils; + private IPLimitFilter ipLimitFilter; // @Resource // private AuthenticationFailureHandlerAdvice authenticationFailureHandlerAdvice; @@ -114,6 +117,8 @@ protected void configure(HttpSecurity http) throws Exception { http.headers().cacheControl(); // 添加JWT过滤器 http.addFilterAt(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); + // 添加ip限制过滤器 + http.addFilterBefore(ipLimitFilter, UsernamePasswordAuthenticationFilter.class); } @Bean diff --git a/blog_main/src/main/java/cn/sticki/blog/controller/BlogActionController.java b/blog_main/src/main/java/cn/sticki/blog/controller/BlogActionController.java index a082026d..0a73b688 100644 --- a/blog_main/src/main/java/cn/sticki/blog/controller/BlogActionController.java +++ b/blog_main/src/main/java/cn/sticki/blog/controller/BlogActionController.java @@ -17,7 +17,7 @@ @Slf4j @RestController -@RequestMapping("/blog") +@RequestMapping("/action/blog") public class BlogActionController { @Resource diff --git a/blog_main/src/main/java/cn/sticki/blog/controller/BlogConsoleController.java b/blog_main/src/main/java/cn/sticki/blog/controller/BlogConsoleController.java index 00ca37b9..8eb1d2b6 100644 --- a/blog_main/src/main/java/cn/sticki/blog/controller/BlogConsoleController.java +++ b/blog_main/src/main/java/cn/sticki/blog/controller/BlogConsoleController.java @@ -140,4 +140,14 @@ public RestTemplate completelyDeleteBlog(@NotNull Integer id) throws UserIllegal return new RestTemplate(blogConsoleService.remove(wrapper)); } + @PostMapping("/img") + public RestTemplate uploadBlogImg(@NotNull MultipartFile file) { + log.debug("uploadBlogImg, fileName->{}, userId->{}", file.getOriginalFilename(), authenticationFacade.getUser().getId()); + if (fileUtils.isNotEmpty(file)) { + fileUtils.checkFile(file, 1024 * 1024L, FileType.JPEG, FileType.PNG); + } + String url = blogConsoleService.uploadImage(file); + return new RestTemplate(url); + } + } diff --git a/blog_main/src/main/java/cn/sticki/blog/controller/BlogController.java b/blog_main/src/main/java/cn/sticki/blog/controller/BlogController.java index 7953fc80..3fd67798 100644 --- a/blog_main/src/main/java/cn/sticki/blog/controller/BlogController.java +++ b/blog_main/src/main/java/cn/sticki/blog/controller/BlogController.java @@ -4,7 +4,9 @@ import cn.sticki.blog.pojo.domain.BlogBasic; import cn.sticki.blog.pojo.domain.User; import cn.sticki.blog.pojo.dto.UserBlogActionStatusDTO; -import cn.sticki.blog.pojo.vo.*; +import cn.sticki.blog.pojo.vo.BlogListVO; +import cn.sticki.blog.pojo.vo.HotBlogListVO; +import cn.sticki.blog.pojo.vo.RestTemplate; import cn.sticki.blog.security.AuthenticationFacade; import cn.sticki.blog.service.BlogActionService; import cn.sticki.blog.service.BlogBasicService; @@ -70,9 +72,7 @@ public RestTemplate recommendBlog(@RequestParam(defaultValue = "1") int page) { public RestTemplate searchBlog(@NotNull String key, @RequestParam(defaultValue = "1") int page) { log.debug("searchBlog,search->{},page->{}", key, page); BlogListVO blogListVO = blogBasicService.searchBlog(key, page, pageSize); - IListVO blogList = new ListVO<>(); - blogList.setRecords(blogListVO.getRecords()); - return new RestTemplate(blogList); + return new RestTemplate(blogListVO); } /** diff --git a/blog_main/src/main/java/cn/sticki/blog/controller/CommentController.java b/blog_main/src/main/java/cn/sticki/blog/controller/CommentController.java new file mode 100644 index 00000000..b2e92ebd --- /dev/null +++ b/blog_main/src/main/java/cn/sticki/blog/controller/CommentController.java @@ -0,0 +1,64 @@ +package cn.sticki.blog.controller; + +import cn.sticki.blog.exception.userException.UserArgumentException; +import cn.sticki.blog.pojo.domain.Comment; +import cn.sticki.blog.pojo.domain.User; +import cn.sticki.blog.pojo.vo.CommentListVO; +import cn.sticki.blog.pojo.vo.RestTemplate; +import cn.sticki.blog.security.AuthenticationFacade; +import cn.sticki.blog.service.CommentService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; + +@Slf4j +@RestController +@RequestMapping("/comment") +public class CommentController { + + @Resource + private AuthenticationFacade authenticationFacade; + + @Resource + private CommentService commentService; + + /** + * 新增评论 + * + * @param comment 必须传入被评论的博客id和评论内容 + */ + @PostMapping + public RestTemplate createComment(@RequestBody Comment comment) { + if (comment.getBlogId() == null || comment.getContent() == null) + throw new UserArgumentException(); + User user = authenticationFacade.getUser(); + comment.setUserId(user.getId()); + commentService.create(comment); + return new RestTemplate(); + } + + /** + * 删除评论 + * + * @param id 评论id + */ + @DeleteMapping + public RestTemplate deleteComment(@RequestParam Integer id) { + User user = authenticationFacade.getUser(); + commentService.checkAndDelete(user.getId(), id); + return new RestTemplate(); + } + + /** + * 获取评论列表 + * + * @param blogId 评论的博客id + */ + @GetMapping("/list") + public RestTemplate getCommentList(@RequestParam Integer blogId, @RequestParam Integer page, @RequestParam(defaultValue = "3") Integer pageSize) { + CommentListVO commentListVO = commentService.getList(blogId, page, pageSize); + return new RestTemplate(commentListVO); + } + +} diff --git a/blog_main/src/main/java/cn/sticki/blog/controller/RegisterController.java b/blog_main/src/main/java/cn/sticki/blog/controller/RegisterController.java index af7868f1..efe78e21 100644 --- a/blog_main/src/main/java/cn/sticki/blog/controller/RegisterController.java +++ b/blog_main/src/main/java/cn/sticki/blog/controller/RegisterController.java @@ -48,7 +48,7 @@ public RestTemplate sendMailVerify(String mail) throws Exception { registerService.sendMailVerify(mail); return new RestTemplate(true); } - return new RestTemplate(false, "发送频繁"); + return new RestTemplate(400, "发送频繁"); } /** diff --git a/blog_main/src/main/java/cn/sticki/blog/controller/ResourceController.java b/blog_main/src/main/java/cn/sticki/blog/controller/ResourceController.java index 99808b38..38b7f2c7 100644 --- a/blog_main/src/main/java/cn/sticki/blog/controller/ResourceController.java +++ b/blog_main/src/main/java/cn/sticki/blog/controller/ResourceController.java @@ -1,8 +1,8 @@ package cn.sticki.blog.controller; import cn.sticki.blog.config.ResourcePath; -import cn.sticki.blog.exception.systemException.MinioException; import cn.sticki.blog.util.OssUtils; +import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; import org.springframework.stereotype.Controller; @@ -13,7 +13,6 @@ import javax.annotation.Resource; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; -import java.io.IOException; @Slf4j @Controller @@ -30,26 +29,26 @@ public class ResourceController { * @param response 响应头 */ @GetMapping("/avatar/{file}") - public void getAvatar(@PathVariable @NotNull String file, @NotNull HttpServletResponse response) - throws IOException, MinioException { - log.debug("getAvatar, fileName->{}", file); - response.setContentType("image/jpeg"); - try ( - ServletOutputStream outputStream = response.getOutputStream() - ) { - ossUtils.download(ResourcePath.avatar + file, outputStream); - } + public void getAvatar(@PathVariable @NotNull String file, @NotNull HttpServletResponse response) { + getImg(ResourcePath.avatar + file, response); } @GetMapping("/blog-cover/{file}") - public void getBlogCover(@PathVariable @NotNull String file, @NotNull HttpServletResponse response) - throws IOException, MinioException { - log.debug("getBlogCover, fileName->{}", file); + public void getBlogCover(@PathVariable @NotNull String file, @NotNull HttpServletResponse response) { + getImg(ResourcePath.blogCoverImage + file, response); + } + + @GetMapping("/blog-img/{file}") + public void getBlogImg(@PathVariable @NotNull String file, @NotNull HttpServletResponse response) { + getImg(ResourcePath.blogImage + file, response); + } + + @SneakyThrows + private void getImg(String filePath, HttpServletResponse response) { + log.debug("getImg, fileName->{}", filePath); response.setContentType("image/jpeg"); - try ( - ServletOutputStream outputStream = response.getOutputStream() - ) { - ossUtils.download(ResourcePath.blogCoverImage + file, outputStream); + try (ServletOutputStream outputStream = response.getOutputStream()) { + ossUtils.download(filePath, outputStream); } } diff --git a/blog_main/src/main/java/cn/sticki/blog/controller/UserController.java b/blog_main/src/main/java/cn/sticki/blog/controller/UserController.java index 1bb9cbdd..45362b65 100644 --- a/blog_main/src/main/java/cn/sticki/blog/controller/UserController.java +++ b/blog_main/src/main/java/cn/sticki/blog/controller/UserController.java @@ -45,10 +45,10 @@ public class UserController { public RestTemplate getByUsername(String username) { User user = authenticationFacade.getUser(); User getUser = null; - if (username == null && user != null) { + if ((username == null || username.length() == 0) && user != null) { getUser = user; log.debug("getByUsername, sessionUser ,user->{}", getUser.getClass()); - } else if (username != null) { + } else if (username != null && username.length() != 0) { getUser = userService.getByUsername(username); log.debug("getByUsername, userService.getByUsername ,user->{}", getUser); } diff --git a/blog_main/src/main/java/cn/sticki/blog/controller/UserFollowController.java b/blog_main/src/main/java/cn/sticki/blog/controller/UserFollowController.java new file mode 100644 index 00000000..31ffdf0f --- /dev/null +++ b/blog_main/src/main/java/cn/sticki/blog/controller/UserFollowController.java @@ -0,0 +1,55 @@ +package cn.sticki.blog.controller; + +import cn.sticki.blog.pojo.domain.FansBasic; +import cn.sticki.blog.pojo.domain.FollowBasic; +import cn.sticki.blog.pojo.domain.User; +import cn.sticki.blog.pojo.vo.ListVO; +import cn.sticki.blog.pojo.vo.RestTemplate; +import cn.sticki.blog.security.AuthenticationFacade; +import cn.sticki.blog.service.UserFollowService; +import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; + +@Slf4j +@RestController +@RequestMapping("/user") +public class UserFollowController { + + // 默认每页20条 + private final int pageSize = 20; + + @Resource + private AuthenticationFacade authenticationFacade; + + @Resource + private UserFollowService userFollowService; + + @GetMapping("/follow") + public RestTemplate getFollowList(@RequestParam(defaultValue = "1") int page) { + User user = authenticationFacade.getUser(); + ListVO listVO = userFollowService.getFollowList(user.getId(), page, pageSize); + return new RestTemplate(listVO); + } + + @GetMapping("/fans") + public RestTemplate getFansList(@RequestParam(defaultValue = "1") int page) { + User user = authenticationFacade.getUser(); + ListVO listVO = userFollowService.getFansList(user.getId(), page, pageSize); + return new RestTemplate(listVO); + } + + @PostMapping("/follow") + public RestTemplate doFollow(@NotNull Integer followId) { + User user = authenticationFacade.getUser(); + try { + boolean result = userFollowService.follow(user.getId(), followId); + return new RestTemplate(200, "success", result, true); + } catch (Exception e) { + return new RestTemplate(200, "fail", null, false); + } + } + +} diff --git a/blog_main/src/main/java/cn/sticki/blog/controller/advice/ProjectExceptionAdvice.java b/blog_main/src/main/java/cn/sticki/blog/controller/advice/ProjectExceptionAdvice.java index 54934a13..e991d7bb 100644 --- a/blog_main/src/main/java/cn/sticki/blog/controller/advice/ProjectExceptionAdvice.java +++ b/blog_main/src/main/java/cn/sticki/blog/controller/advice/ProjectExceptionAdvice.java @@ -5,15 +5,18 @@ import cn.sticki.blog.exception.userException.UserIllegalException; import cn.sticki.blog.pojo.vo.RestTemplate; import lombok.extern.slf4j.Slf4j; +import org.apache.catalina.connector.ClientAbortException; import org.springframework.beans.TypeMismatchException; import org.springframework.http.converter.HttpMessageConversionException; import org.springframework.validation.BindException; +import org.springframework.web.HttpMediaTypeException; import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.bind.MissingRequestValueException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.servlet.NoHandlerFoundException; +import javax.servlet.ServletException; import java.net.ConnectException; import java.util.ArrayList; @@ -32,13 +35,19 @@ public RestTemplate doException(Exception e) { return new RestTemplate(500, "服务器故障,请稍后再试", null, false); } + @ExceptionHandler(ServletException.class) + public RestTemplate doServletException(Exception e) { + log.warn("请求异常,{}", e.getMessage()); + return new RestTemplate(400, "请求异常", null, false); + } + @ExceptionHandler(HttpMessageConversionException.class) public RestTemplate doHttpMessageConversionException(HttpMessageConversionException e) { - e.printStackTrace(); + log.warn("数据异常,{}", e.getMessage()); return new RestTemplate(400, "数据异常", null, false); } - @ExceptionHandler(HttpRequestMethodNotSupportedException.class) + @ExceptionHandler({HttpRequestMethodNotSupportedException.class, HttpMediaTypeException.class}) public RestTemplate doHttpRequestMethodNotSupportedException(Exception e) { log.warn("请求方式异常,{}", e.getMessage()); return new RestTemplate(400, "请求方式异常", null, false); @@ -76,6 +85,12 @@ public RestTemplate doConnectException(ConnectException e) { return new RestTemplate(501, "服务器连接故障,请联系管理员", null, false); } + @ExceptionHandler(ClientAbortException.class) + public RestTemplate doClientAbortException(ClientAbortException e) { + log.warn("连接被关闭,{}", e.getMessage()); + return new RestTemplate(501, "连接被关闭", null, false); + } + @ExceptionHandler(SqlLimitException.class) public RestTemplate doSqlLimitException(SqlLimitException e) { log.info("请求分页数量超过上限,{}", e.getMessage()); diff --git a/blog_main/src/main/java/cn/sticki/blog/enumeration/CacheSpace.java b/blog_main/src/main/java/cn/sticki/blog/enumeration/CacheSpace.java index 163e4d3f..be999615 100644 --- a/blog_main/src/main/java/cn/sticki/blog/enumeration/CacheSpace.java +++ b/blog_main/src/main/java/cn/sticki/blog/enumeration/CacheSpace.java @@ -27,4 +27,9 @@ public class CacheSpace { */ public static final String UserService_MailVerify = "userService:mailVerify:"; + /** + * ip 计数 + */ + public static final String IpService_Count = "ipService:Count:"; + } diff --git a/blog_main/src/main/java/cn/sticki/blog/exception/userException/UserArgumentException.java b/blog_main/src/main/java/cn/sticki/blog/exception/userException/UserArgumentException.java new file mode 100644 index 00000000..99a2d8cf --- /dev/null +++ b/blog_main/src/main/java/cn/sticki/blog/exception/userException/UserArgumentException.java @@ -0,0 +1,9 @@ +package cn.sticki.blog.exception.userException; + +public class UserArgumentException extends UserIllegalException { + + public UserArgumentException() { + super("用户参数异常"); + } + +} diff --git a/blog_main/src/main/java/cn/sticki/blog/mapper/BlogGeneralMapper.java b/blog_main/src/main/java/cn/sticki/blog/mapper/BlogGeneralMapper.java index edcb84af..8fc2cef1 100644 --- a/blog_main/src/main/java/cn/sticki/blog/mapper/BlogGeneralMapper.java +++ b/blog_main/src/main/java/cn/sticki/blog/mapper/BlogGeneralMapper.java @@ -20,4 +20,10 @@ public interface BlogGeneralMapper extends BaseMapper { @Update("update blog_general set collection_num = collection_num - 1 where blog_id = #{blogId};") int decreaseCollectionNum(Integer blogId); + @Update("update blog_general set comment_num = comment_num + 1 where blog_id = #{blogId};") + int increaseCommentNum(Integer blogId); + + @Update("update blog_general set comment_num = comment_num - 1 where blog_id = #{blogId};") + int decreaseCommentNum(Integer blogId); + } diff --git a/blog_main/src/main/java/cn/sticki/blog/mapper/BlogImgMapper.java b/blog_main/src/main/java/cn/sticki/blog/mapper/BlogImgMapper.java new file mode 100644 index 00000000..761f39f1 --- /dev/null +++ b/blog_main/src/main/java/cn/sticki/blog/mapper/BlogImgMapper.java @@ -0,0 +1,10 @@ +package cn.sticki.blog.mapper; + +import cn.sticki.blog.pojo.domain.BlogImg; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface BlogImgMapper extends BaseMapper { + +} diff --git a/blog_main/src/main/java/cn/sticki/blog/mapper/CommentBasicMapper.java b/blog_main/src/main/java/cn/sticki/blog/mapper/CommentBasicMapper.java new file mode 100644 index 00000000..65cea46b --- /dev/null +++ b/blog_main/src/main/java/cn/sticki/blog/mapper/CommentBasicMapper.java @@ -0,0 +1,10 @@ +package cn.sticki.blog.mapper; + +import cn.sticki.blog.pojo.domain.CommentBasic; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface CommentBasicMapper extends BaseMapper { + +} diff --git a/blog_main/src/main/java/cn/sticki/blog/mapper/CommentMapper.java b/blog_main/src/main/java/cn/sticki/blog/mapper/CommentMapper.java new file mode 100644 index 00000000..dc22d2bb --- /dev/null +++ b/blog_main/src/main/java/cn/sticki/blog/mapper/CommentMapper.java @@ -0,0 +1,10 @@ +package cn.sticki.blog.mapper; + +import cn.sticki.blog.pojo.domain.Comment; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface CommentMapper extends BaseMapper { + +} diff --git a/blog_main/src/main/java/cn/sticki/blog/mapper/FansBasicMapper.java b/blog_main/src/main/java/cn/sticki/blog/mapper/FansBasicMapper.java new file mode 100644 index 00000000..7a630e62 --- /dev/null +++ b/blog_main/src/main/java/cn/sticki/blog/mapper/FansBasicMapper.java @@ -0,0 +1,10 @@ +package cn.sticki.blog.mapper; + +import cn.sticki.blog.pojo.domain.FansBasic; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface FansBasicMapper extends BaseMapper { + +} diff --git a/blog_main/src/main/java/cn/sticki/blog/mapper/FollowBasicMapper.java b/blog_main/src/main/java/cn/sticki/blog/mapper/FollowBasicMapper.java new file mode 100644 index 00000000..0add2ba6 --- /dev/null +++ b/blog_main/src/main/java/cn/sticki/blog/mapper/FollowBasicMapper.java @@ -0,0 +1,10 @@ +package cn.sticki.blog.mapper; + +import cn.sticki.blog.pojo.domain.FollowBasic; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface FollowBasicMapper extends BaseMapper { + +} diff --git a/blog_main/src/main/java/cn/sticki/blog/mapper/UserFollowMapper.java b/blog_main/src/main/java/cn/sticki/blog/mapper/UserFollowMapper.java new file mode 100644 index 00000000..9bb84197 --- /dev/null +++ b/blog_main/src/main/java/cn/sticki/blog/mapper/UserFollowMapper.java @@ -0,0 +1,10 @@ +package cn.sticki.blog.mapper; + +import cn.sticki.blog.pojo.domain.UserFollow; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface UserFollowMapper extends BaseMapper { + +} diff --git a/blog_main/src/main/java/cn/sticki/blog/pojo/domain/BlogImg.java b/blog_main/src/main/java/cn/sticki/blog/pojo/domain/BlogImg.java new file mode 100644 index 00000000..2eb65cd2 --- /dev/null +++ b/blog_main/src/main/java/cn/sticki/blog/pojo/domain/BlogImg.java @@ -0,0 +1,20 @@ +package cn.sticki.blog.pojo.domain; + +import lombok.Data; + +import java.sql.Timestamp; + +@Data +public class BlogImg { + + Integer id; + + String img; + + Integer visit; + + Timestamp modified_time; + + Timestamp create_time; + +} diff --git a/blog_main/src/main/java/cn/sticki/blog/pojo/domain/Comment.java b/blog_main/src/main/java/cn/sticki/blog/pojo/domain/Comment.java new file mode 100644 index 00000000..28568436 --- /dev/null +++ b/blog_main/src/main/java/cn/sticki/blog/pojo/domain/Comment.java @@ -0,0 +1,24 @@ +package cn.sticki.blog.pojo.domain; + +import lombok.Data; + +import java.sql.Timestamp; + +@Data +public class Comment { + + Integer id; // 评论id + + Integer userId; // 用户id + + Integer blogId; // 博客id + + String content; // 评论内容 + + Integer parentId; // 父评论id + + Integer parentUserId; // 回复的用户id + + Timestamp createTime; // 创建时间 + +} diff --git a/blog_main/src/main/java/cn/sticki/blog/pojo/domain/CommentBasic.java b/blog_main/src/main/java/cn/sticki/blog/pojo/domain/CommentBasic.java new file mode 100644 index 00000000..b4e8b7d6 --- /dev/null +++ b/blog_main/src/main/java/cn/sticki/blog/pojo/domain/CommentBasic.java @@ -0,0 +1,30 @@ +package cn.sticki.blog.pojo.domain; + +import lombok.Data; + +import java.sql.Timestamp; + +@Data +public class CommentBasic { + + Integer id; // 评论id + + Integer blogId; // 博客id + + Integer userId; // 发表评论的用户id + + String nickname; // 用户昵称 + + String avatarUrl; // 头像链接 + + String content; // 评论内容 + + Timestamp createTime; // 发表时间 + + Integer parentId; // 父评论id + + Integer parentUserId; // 回复的用户id + + String parentNickname; // 回复的用户昵称 + +} diff --git a/blog_main/src/main/java/cn/sticki/blog/pojo/domain/FansBasic.java b/blog_main/src/main/java/cn/sticki/blog/pojo/domain/FansBasic.java new file mode 100644 index 00000000..5ecc35c7 --- /dev/null +++ b/blog_main/src/main/java/cn/sticki/blog/pojo/domain/FansBasic.java @@ -0,0 +1,30 @@ +package cn.sticki.blog.pojo.domain; + +import lombok.Data; + +import java.sql.Timestamp; + +@Data +public class FansBasic { + + Integer id; + + Integer userId; + + Integer fansId; + + String note; + + Integer status; + + Timestamp createTime; + + String username; + + String nickname; + + String avatarUrl; + + Timestamp registerTime; + +} diff --git a/blog_main/src/main/java/cn/sticki/blog/pojo/domain/FollowBasic.java b/blog_main/src/main/java/cn/sticki/blog/pojo/domain/FollowBasic.java new file mode 100644 index 00000000..6ab215f1 --- /dev/null +++ b/blog_main/src/main/java/cn/sticki/blog/pojo/domain/FollowBasic.java @@ -0,0 +1,30 @@ +package cn.sticki.blog.pojo.domain; + +import lombok.Data; + +import java.sql.Timestamp; + +@Data +public class FollowBasic { + + Integer id; + + Integer userId; + + Integer followId; + + String note; + + Integer status; + + Timestamp createTime; + + String username; + + String nickname; + + String avatarUrl; + + Timestamp registerTime; + +} diff --git a/blog_main/src/main/java/cn/sticki/blog/pojo/domain/UserFollow.java b/blog_main/src/main/java/cn/sticki/blog/pojo/domain/UserFollow.java new file mode 100644 index 00000000..a78daa53 --- /dev/null +++ b/blog_main/src/main/java/cn/sticki/blog/pojo/domain/UserFollow.java @@ -0,0 +1,22 @@ +package cn.sticki.blog.pojo.domain; + +import lombok.Data; + +import java.sql.Timestamp; + +@Data +public class UserFollow { + + Integer id; + + Integer fansId; + + Integer followId; + + String note; + + Integer status; + + Timestamp createTime; + +} diff --git a/blog_main/src/main/java/cn/sticki/blog/pojo/dto/CommentDTO.java b/blog_main/src/main/java/cn/sticki/blog/pojo/dto/CommentDTO.java new file mode 100644 index 00000000..a040c0b4 --- /dev/null +++ b/blog_main/src/main/java/cn/sticki/blog/pojo/dto/CommentDTO.java @@ -0,0 +1,17 @@ +package cn.sticki.blog.pojo.dto; + +import cn.sticki.blog.pojo.domain.CommentBasic; +import lombok.Data; + +import java.util.List; + +@Data +public class CommentDTO { + + CommentBasic info; + + List sub; + + long subCount; + +} diff --git a/blog_main/src/main/java/cn/sticki/blog/pojo/vo/BlogContentVO.java b/blog_main/src/main/java/cn/sticki/blog/pojo/vo/BlogContentVO.java index 113108fa..4fc30981 100644 --- a/blog_main/src/main/java/cn/sticki/blog/pojo/vo/BlogContentVO.java +++ b/blog_main/src/main/java/cn/sticki/blog/pojo/vo/BlogContentVO.java @@ -14,4 +14,6 @@ public class BlogContentVO { User author; + CommentListVO comment; + } diff --git a/blog_main/src/main/java/cn/sticki/blog/pojo/vo/CommentListVO.java b/blog_main/src/main/java/cn/sticki/blog/pojo/vo/CommentListVO.java new file mode 100644 index 00000000..1c950642 --- /dev/null +++ b/blog_main/src/main/java/cn/sticki/blog/pojo/vo/CommentListVO.java @@ -0,0 +1,13 @@ +package cn.sticki.blog.pojo.vo; + +import cn.sticki.blog.pojo.dto.CommentDTO; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +public class CommentListVO extends ListVO { + + long allCount = 0; // 总评论数量(包括二级评论) + +} diff --git a/blog_main/src/main/java/cn/sticki/blog/pojo/vo/ListVO.java b/blog_main/src/main/java/cn/sticki/blog/pojo/vo/ListVO.java index 6ce2b329..3c0e9c8c 100644 --- a/blog_main/src/main/java/cn/sticki/blog/pojo/vo/ListVO.java +++ b/blog_main/src/main/java/cn/sticki/blog/pojo/vo/ListVO.java @@ -18,7 +18,7 @@ public class ListVO implements IListVO { long total = 0; /** - * 每页显示条数,默认 10 + * 每页显示条数,默认 20 */ long size = 20; diff --git a/blog_main/src/main/java/cn/sticki/blog/security/filter/AuthenticationTokenFilter.java b/blog_main/src/main/java/cn/sticki/blog/security/filter/AuthenticationTokenFilter.java index b3627c6f..48cc0211 100644 --- a/blog_main/src/main/java/cn/sticki/blog/security/filter/AuthenticationTokenFilter.java +++ b/blog_main/src/main/java/cn/sticki/blog/security/filter/AuthenticationTokenFilter.java @@ -60,7 +60,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse if (user == null) { user = userMapper.selectById(id); } - log.debug("Token validate successful,user->{}", user); + log.debug("Token get success,user->{}", user); // TODO 获取权限信息封装到Authentication中 // 存入SecurityContextHolder,这里构造一个已认证的 authenticationToken ,之后就不用再认证了。 if (user != null) { diff --git a/blog_main/src/main/java/cn/sticki/blog/security/filter/IPLimitFilter.java b/blog_main/src/main/java/cn/sticki/blog/security/filter/IPLimitFilter.java new file mode 100644 index 00000000..1ba7a057 --- /dev/null +++ b/blog_main/src/main/java/cn/sticki/blog/security/filter/IPLimitFilter.java @@ -0,0 +1,59 @@ +package cn.sticki.blog.security.filter; + +import cn.sticki.blog.enumeration.CacheSpace; +import cn.sticki.blog.pojo.vo.RestTemplate; +import cn.sticki.blog.util.RequestUtils; +import cn.sticki.blog.util.ResponseUtils; +import com.alicp.jetcache.Cache; +import com.alicp.jetcache.anno.CreateCache; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; + +import javax.annotation.Resource; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +@Slf4j +@Component +public class IPLimitFilter extends OncePerRequestFilter { + + private final int time = 5; + + private final int count = 30; + + @Resource + private ResponseUtils responseUtils; + + @CreateCache(name = CacheSpace.IpService_Count, expire = time) + private Cache cache; + + /** + * ip访问限制过滤器 + */ + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { + // todo 有待优化,目前逻辑为,连续访问30次,需要冷却5s + // 获取当前ip + String ip = RequestUtils.getIPAddress(request); + // ip计数 + Integer ipCount = cache.get(ip); + if (ipCount == null) ipCount = 0; + if (ipCount > count) { + // ip访问超过限制 + responseUtils.objectToJson(response, new RestTemplate(408, "访问频繁,请稍后再试")); + response.sendError(403, "Reject request"); + } else { + ipCount++; + cache.put(ip, ipCount); + //放行 + filterChain.doFilter(request, response); + } + // 打印访问情况 + log.info("{} {} {} {}", request.getRemoteAddr(), request.getMethod(), response.getStatus(), request.getServletPath()); + } + +} \ No newline at end of file diff --git a/blog_main/src/main/java/cn/sticki/blog/service/BlogConsoleService.java b/blog_main/src/main/java/cn/sticki/blog/service/BlogConsoleService.java index 9e40b987..f036e424 100644 --- a/blog_main/src/main/java/cn/sticki/blog/service/BlogConsoleService.java +++ b/blog_main/src/main/java/cn/sticki/blog/service/BlogConsoleService.java @@ -32,4 +32,9 @@ public interface BlogConsoleService extends IService { */ void uploadCoverImage(String name, MultipartFile coverImage); + /** + * 上传博客图片,自动命名为文件的md5值,返回图片路径 + */ + String uploadImage(MultipartFile coverImage); + } diff --git a/blog_main/src/main/java/cn/sticki/blog/service/CommentService.java b/blog_main/src/main/java/cn/sticki/blog/service/CommentService.java new file mode 100644 index 00000000..3759f9b5 --- /dev/null +++ b/blog_main/src/main/java/cn/sticki/blog/service/CommentService.java @@ -0,0 +1,43 @@ +package cn.sticki.blog.service; + +import cn.sticki.blog.pojo.domain.Comment; +import cn.sticki.blog.pojo.vo.CommentListVO; + +public interface CommentService { + + /** + * 创建评论 + */ + void create(Comment comment); + + /** + * 删除评论 + * + * @param id 评论id + */ + void delete(int id); + + /** + * 检查评论发表人 + * + * @param userId 用户id + * @param commentId 评论id + * @return 若该评论是该用户发表的,返回true + */ + boolean checkPublisher(int userId, int commentId); + + /** + * 检查发表人并删除评论 + */ + void checkAndDelete(int userId, int commentId); + + /** + * 获取评论信息列表 + * + * @param blogId 博客id + * @param page 当前页 + * @param pageSize 页大小 + */ + CommentListVO getList(int blogId, int page, int pageSize); + +} diff --git a/blog_main/src/main/java/cn/sticki/blog/service/UserFollowService.java b/blog_main/src/main/java/cn/sticki/blog/service/UserFollowService.java new file mode 100644 index 00000000..a381de6d --- /dev/null +++ b/blog_main/src/main/java/cn/sticki/blog/service/UserFollowService.java @@ -0,0 +1,32 @@ +package cn.sticki.blog.service; + +import cn.sticki.blog.pojo.domain.FansBasic; +import cn.sticki.blog.pojo.domain.FollowBasic; +import cn.sticki.blog.pojo.vo.ListVO; + +public interface UserFollowService { + + /** + * 关注用户,已关注的状态下则取消关注 + * + * @param userId 用户id(操作者) + * @param followId 关注者的id + * @return 返回调用后是否为关注状态,若为关注则返回true、未关注则返回false + */ + boolean follow(int userId, int followId); + + /** + * 获取关注列表 + * + * @return 关注列表 + */ + ListVO getFollowList(int userId, int page, int pageSize); + + /** + * 获取粉丝列表 + * + * @return 粉丝列表 + */ + ListVO getFansList(int userId, int page, int pageSize); + +} diff --git a/blog_main/src/main/java/cn/sticki/blog/service/impl/BlogBasicServiceImpl.java b/blog_main/src/main/java/cn/sticki/blog/service/impl/BlogBasicServiceImpl.java index 101eb47e..d5725851 100644 --- a/blog_main/src/main/java/cn/sticki/blog/service/impl/BlogBasicServiceImpl.java +++ b/blog_main/src/main/java/cn/sticki/blog/service/impl/BlogBasicServiceImpl.java @@ -9,6 +9,7 @@ import cn.sticki.blog.pojo.vo.BlogContentVO; import cn.sticki.blog.pojo.vo.BlogListVO; import cn.sticki.blog.service.BlogBasicService; +import cn.sticki.blog.service.CommentService; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; @@ -31,6 +32,9 @@ public class BlogBasicServiceImpl extends ServiceImpl implem @Resource private FileUtils fileUtils; + @Resource + private BlogImgMapper blogImgMapper; + @Override public void saveBlog(BlogSaveDTO blogDTO) throws UserException, DAOException { log.debug("saveBlog, id->{}", blogDTO.getId()); @@ -187,4 +189,27 @@ public void uploadCoverImage(String name, MultipartFile coverImage) { } } + @SneakyThrows + @Override + public String uploadImage(MultipartFile coverImage) { + try (InputStream stream = coverImage.getInputStream()) { + String md5 = EncryptUtils.toMD5(stream); + // 存数据库,上传图片 + // 先判断数据库是否存在这条记录,存在的话直接返回链接就行了 + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(BlogImg::getImg, md5); + if (!blogImgMapper.exists(wrapper)) { + // 不存在,则新增 + BlogImg blogImg = new BlogImg(); + blogImg.setImg(md5); + blogImg.setCreate_time(new Timestamp(System.currentTimeMillis())); + blogImgMapper.insert(blogImg); + // 上传图片 + ossUtils.upload(coverImage, ResourcePath.blogImage + md5); + } + // 返回访问链接 + return ResourcePath.blogImageUrlBase + md5; + } + } + } diff --git a/blog_main/src/main/java/cn/sticki/blog/service/impl/CommentServiceImpl.java b/blog_main/src/main/java/cn/sticki/blog/service/impl/CommentServiceImpl.java new file mode 100644 index 00000000..f6d19b0b --- /dev/null +++ b/blog_main/src/main/java/cn/sticki/blog/service/impl/CommentServiceImpl.java @@ -0,0 +1,153 @@ +package cn.sticki.blog.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.sticki.blog.exception.userException.UserIllegalException; +import cn.sticki.blog.mapper.BlogGeneralMapper; +import cn.sticki.blog.mapper.BlogMapper; +import cn.sticki.blog.mapper.CommentBasicMapper; +import cn.sticki.blog.mapper.CommentMapper; +import cn.sticki.blog.pojo.domain.Blog; +import cn.sticki.blog.pojo.domain.Comment; +import cn.sticki.blog.pojo.domain.CommentBasic; +import cn.sticki.blog.pojo.dto.CommentDTO; +import cn.sticki.blog.pojo.vo.CommentListVO; +import cn.sticki.blog.service.CommentService; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +@Slf4j +@Service +public class CommentServiceImpl implements CommentService { + + @Resource + private CommentMapper commentMapper; + + @Resource + private BlogMapper blogMapper; + + @Resource + private BlogGeneralMapper blogGeneralMapper; + + @Resource + private CommentBasicMapper commentBasicMapper; + + @Override + public void create(Comment comment) { + // 检查博客是否存在,检查父评论id是否在该博客下 + boolean exists = false; + if (comment.getParentId() != null) { + // 判断博客id和父评论id是否正确 + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(Comment::getBlogId, comment.getBlogId()).eq(Comment::getId, comment.getParentId()); + Comment parentComment = commentMapper.selectOne(wrapper); + if (parentComment != null) { + exists = true; + // 如果父评论还有上一级评论,则设置父评论的上一级评论为当前评论的父评论,如此,所有子评论的父评论id都一定是一级评论 + comment.setParentId(parentComment.getParentId() != null ? parentComment.getParentId() : parentComment.getId()); + // 为了防止有歧义难以理解,故改写成了上面这句 + // if (parentComment.getParentId() != null) comment.setParentId(parentComment.getParentId()); + comment.setParentUserId(parentComment.getUserId()); + } + } else { + // 判断博客id是否存在 + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(Blog::getId, comment.getBlogId()); + exists = blogMapper.exists(wrapper); + } + if (!exists) throw new UserIllegalException("数据异常"); + comment.setId(null); + comment.setCreateTime(new Timestamp(System.currentTimeMillis())); + commentMapper.insert(comment); + blogGeneralMapper.increaseCommentNum(comment.getId()); + } + + @Override + public void delete(int id) { + int count = commentMapper.deleteById(id); + if (count == 0) + log.warn("comment 删除异常,id->{}", id); + else { + // 减少数量 + blogGeneralMapper.decreaseCommentNum(id); + } + } + + @Override + public boolean checkPublisher(int userId, int commentId) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(Comment::getUserId, userId).eq(Comment::getId, commentId); + return commentMapper.exists(wrapper); + } + + @Override + public void checkAndDelete(int userId, int commentId) { + if (!checkPublisher(userId, commentId)) { + log.warn("非法删除评论,id->{},commentId->{}", userId, commentId); + throw new UserIllegalException(); + } else { + delete(commentId); + } + } + + @Override + public CommentListVO getList(int blogId, int page, int pageSize) { + CommentListVO vo = new CommentListVO(); + // 先查总数量 + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(CommentBasic::getBlogId, blogId); // 只要博客id一致即可 + Long count = commentBasicMapper.selectCount(wrapper); + vo.setAllCount(count); + if (count == 0) return vo; // 若总数为0,直接返回 + + // 以时间排序,只查该博客下没有父评论id的,存入父评论组数中 + wrapper.orderByDesc(CommentBasic::getCreateTime).isNull(CommentBasic::getParentId); + IPage iPage = new Page<>(page, pageSize); + commentBasicMapper.selectPage(iPage, wrapper); + BeanUtil.copyProperties(iPage, vo, "records"); + // 复制父评论 + ArrayList dtoList = new ArrayList<>(); + for (CommentBasic record : iPage.getRecords()) { + CommentDTO dto = new CommentDTO(); + dto.setInfo(record); + dtoList.add(dto); + } + vo.setRecords(dtoList); + + // 查询子评论 + // 先获取父评论的id列表 + ArrayList idList = new ArrayList<>(); + for (CommentBasic commentBasic : iPage.getRecords()) { + idList.add(commentBasic.getId()); + } + // 以父评论id查询所有子评论,按时间排序 + wrapper.clear(); + wrapper.eq(CommentBasic::getBlogId, blogId) + .in(CommentBasic::getParentId, idList) + .orderByDesc(CommentBasic::getCreateTime); + // 查询所有子评论 + List subList = commentBasicMapper.selectList(wrapper); + // 将子评论填充到父评论下 + for (CommentDTO commentDTO : dtoList) { + Integer parentId = commentDTO.getInfo().getId(); + ArrayList tempSub = new ArrayList<>(); + for (CommentBasic sub : subList) { + if (Objects.equals(parentId, sub.getParentId())) + tempSub.add(sub); + } + commentDTO.setSub(tempSub); + commentDTO.setSubCount(tempSub.size()); + } + + return vo; + } + +} diff --git a/blog_main/src/main/java/cn/sticki/blog/service/impl/UserCollectBlogServiceImpl.java b/blog_main/src/main/java/cn/sticki/blog/service/impl/UserCollectBlogServiceImpl.java index 92795f15..8f6a11bc 100644 --- a/blog_main/src/main/java/cn/sticki/blog/service/impl/UserCollectBlogServiceImpl.java +++ b/blog_main/src/main/java/cn/sticki/blog/service/impl/UserCollectBlogServiceImpl.java @@ -70,7 +70,12 @@ public BlogListVO getCollectBlogList(@NotNull Integer userId, int page, int page wrapper.eq(UserCollectBlog::getUserId, userId); IPage iPage = new Page<>(page, pageSize); userCollectBlogMapper.selectPage(iPage, wrapper); + BlogListVO blogListVO = BeanUtil.copyProperties(iPage, BlogListVO.class); List userCollectBlogList = iPage.getRecords(); + // 若为空,则直接返回 + if (userCollectBlogList.isEmpty()) { + return blogListVO; + } ArrayList blogIdList = new ArrayList<>(); for (UserCollectBlog blog : userCollectBlogList) { blogIdList.add(blog.getBlogId()); @@ -79,7 +84,7 @@ public BlogListVO getCollectBlogList(@NotNull Integer userId, int page, int page LambdaQueryWrapper blogWrapper = new LambdaQueryWrapper<>(); blogWrapper.in(BlogBasic::getId, blogIdList); List blogBasicList = blogBasicMapper.selectList(blogWrapper); - BlogListVO blogListVO = BeanUtil.copyProperties(iPage, BlogListVO.class, "records"); + blogListVO.setRecords(blogBasicList); return blogListVO; } diff --git a/blog_main/src/main/java/cn/sticki/blog/service/impl/UserFollowServiceImpl.java b/blog_main/src/main/java/cn/sticki/blog/service/impl/UserFollowServiceImpl.java new file mode 100644 index 00000000..77bbc383 --- /dev/null +++ b/blog_main/src/main/java/cn/sticki/blog/service/impl/UserFollowServiceImpl.java @@ -0,0 +1,84 @@ +package cn.sticki.blog.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.sticki.blog.exception.userException.UserIllegalException; +import cn.sticki.blog.mapper.FansBasicMapper; +import cn.sticki.blog.mapper.FollowBasicMapper; +import cn.sticki.blog.mapper.UserFollowMapper; +import cn.sticki.blog.pojo.domain.FansBasic; +import cn.sticki.blog.pojo.domain.FollowBasic; +import cn.sticki.blog.pojo.domain.UserFollow; +import cn.sticki.blog.pojo.vo.ListVO; +import cn.sticki.blog.service.UserFollowService; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.sql.Timestamp; + +@Slf4j +@Service +public class UserFollowServiceImpl implements UserFollowService { + + @Resource + private UserFollowMapper userFollowMapper; + + @Resource + private FollowBasicMapper followBasicMapper; + + @Resource + private FansBasicMapper fansBasicMapper; + + @Override + public boolean follow(int userId, int followId) { + if (userId == followId) { + log.warn("User follow oneself,userId->{}", userId); + throw new UserIllegalException("Error for follow oneself"); + } + // 关注用户,查询是否存在关注记录,若不存在,则添加记录,若存在,则取消记录 + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(UserFollow::getFansId, userId).eq(UserFollow::getFollowId, followId); + if (userFollowMapper.exists(wrapper)) { + // 若存在,则删除记录,返回false + userFollowMapper.delete(wrapper); + return false; + } else { + UserFollow userFollow = new UserFollow(); + userFollow.setFansId(userId); + userFollow.setFollowId(followId); + userFollow.setCreateTime(new Timestamp(System.currentTimeMillis())); + // 不存在,添加记录,返回true + userFollowMapper.insert(userFollow); + return true; + } + } + + @Override + public ListVO getFollowList(int userId, int page, int pageSize) { + // 获取关注列表 + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(FollowBasic::getUserId, userId); + IPage iPage = new Page<>(page, pageSize); + followBasicMapper.selectPage(iPage, wrapper); + // 赋值返回 + ListVO listVO = new ListVO<>(); + BeanUtil.copyProperties(iPage, listVO); + return listVO; + } + + @Override + public ListVO getFansList(int userId, int page, int pageSize) { + // 获取粉丝列表 + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(FansBasic::getUserId, userId); + IPage iPage = new Page<>(page, pageSize); + fansBasicMapper.selectPage(iPage, wrapper); + ListVO listVO = new ListVO<>(); + BeanUtil.copyProperties(iPage, listVO); + return listVO; + } + +} diff --git a/blog_main/src/main/java/cn/sticki/blog/service/impl/UserServiceImpl.java b/blog_main/src/main/java/cn/sticki/blog/service/impl/UserServiceImpl.java index ddce25fc..eef51386 100644 --- a/blog_main/src/main/java/cn/sticki/blog/service/impl/UserServiceImpl.java +++ b/blog_main/src/main/java/cn/sticki/blog/service/impl/UserServiceImpl.java @@ -19,6 +19,7 @@ import org.jetbrains.annotations.NotNull; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; @@ -27,6 +28,7 @@ @Slf4j @Service +@Transactional public class UserServiceImpl implements UserService { @Resource diff --git a/blog_main/src/main/java/cn/sticki/blog/util/EncryptUtils.java b/blog_main/src/main/java/cn/sticki/blog/util/EncryptUtils.java new file mode 100644 index 00000000..57e1f4a3 --- /dev/null +++ b/blog_main/src/main/java/cn/sticki/blog/util/EncryptUtils.java @@ -0,0 +1,34 @@ +package cn.sticki.blog.util; + +import cn.sticki.blog.exception.userException.FileException; +import org.springframework.util.DigestUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; + +public class EncryptUtils { + + /** + * MD5加密 + * + * @param str 待加密字符串 + * @return 16进制加密字符串 + */ + public static String toMD5(String str) { + return DigestUtils.md5DigestAsHex(str.getBytes(StandardCharsets.UTF_8)); + } + + public static String toMD5(byte[] bytes) { + return DigestUtils.md5DigestAsHex(bytes); + } + + public static String toMD5(InputStream inputStream) { + try { + return DigestUtils.md5DigestAsHex(inputStream); + } catch (IOException e) { + throw new FileException("空文件"); + } + } + +} diff --git a/blog_main/src/main/java/cn/sticki/blog/util/OssUtils.java b/blog_main/src/main/java/cn/sticki/blog/util/OssUtils.java index dbe83d2c..169874bb 100644 --- a/blog_main/src/main/java/cn/sticki/blog/util/OssUtils.java +++ b/blog_main/src/main/java/cn/sticki/blog/util/OssUtils.java @@ -70,13 +70,13 @@ public Boolean removeBucket(String bucketName) throws MinioException { /** * 上传文件,请手动关闭inputStream */ - public void upload(String objectName, InputStream inputStream, long objectSize, long partSize, String contentType) + public void upload(String filePath, InputStream inputStream, long objectSize, long partSize, String contentType) throws MinioException { try { minioClient.putObject(PutObjectArgs .builder() .bucket(MinioConfig.bucketName) - .object(objectName) + .object(filePath) // 文件大小和分片大小,填-1默认为5Mib .stream(inputStream, objectSize, partSize) .contentType(contentType) @@ -108,14 +108,28 @@ public void upload(MultipartFile multipartFile) throws MinioException, IOExcepti } } + public void upload(MultipartFile multipartFile, String filePath) throws MinioException, IOException { + try ( + InputStream inputStream = multipartFile.getInputStream() + ) { + this.upload( + filePath, + inputStream, + multipartFile.getSize(), + -1, + multipartFile.getContentType() + ); + } + } + /** * 下载文件 * - * @param fileName 文件名 + * @param filePath 文件名(包括路径) * @param outputStream 输出流 */ - public void download(String fileName, ServletOutputStream outputStream) throws MinioException, IOException { - InputStream inputStream = this.download(fileName); + public void download(String filePath, ServletOutputStream outputStream) throws MinioException, IOException { + InputStream inputStream = this.download(filePath); IOUtils.copy(inputStream, outputStream); inputStream.close(); } @@ -123,14 +137,14 @@ public void download(String fileName, ServletOutputStream outputStream) throws M /** * 下载文件,需要手动关闭流,否则会一直占用资源 * - * @param fileName 文件名 + * @param filePath 文件名(包括路径) */ - public InputStream download(String fileName) throws MinioException { + public InputStream download(String filePath) throws MinioException { try { return minioClient.getObject(GetObjectArgs .builder() .bucket(MinioConfig.bucketName) - .object(fileName) + .object(filePath) .build()); } catch (Exception e) { // e.printStackTrace(); diff --git a/blog_main/src/main/java/cn/sticki/blog/util/RequestUtils.java b/blog_main/src/main/java/cn/sticki/blog/util/RequestUtils.java new file mode 100644 index 00000000..2f71ed9f --- /dev/null +++ b/blog_main/src/main/java/cn/sticki/blog/util/RequestUtils.java @@ -0,0 +1,45 @@ +package cn.sticki.blog.util; + +import javax.servlet.http.HttpServletRequest; + +public class RequestUtils { + + public static String getIPAddress(HttpServletRequest request) { + String ip = null; + + //X-Forwarded-For:Squid 服务代理 + String ipAddresses = request.getHeader("X-Forwarded-For"); + + if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { + //Proxy-Client-IP:apache 服务代理 + ipAddresses = request.getHeader("Proxy-Client-IP"); + } + + if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { + //WL-Proxy-Client-IP:weblogic 服务代理 + ipAddresses = request.getHeader("WL-Proxy-Client-IP"); + } + + if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { + //HTTP_CLIENT_IP:有些代理服务器 + ipAddresses = request.getHeader("HTTP_CLIENT_IP"); + } + + if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { + //X-Real-IP:nginx服务代理 + ipAddresses = request.getHeader("X-Real-IP"); + } + + //有些网络通过多层代理,那么获取到的ip就会有多个,一般都是通过逗号(,)分割开来,并且第一个ip为客户端的真实IP + if (ipAddresses != null && ipAddresses.length() != 0) { + ip = ipAddresses.split(",")[0]; + } + + //还是不能获取到,最后再通过request.getRemoteAddr();获取 + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { + ip = request.getRemoteAddr(); + } + return ip; + } + +} diff --git a/blog_main/src/main/resources/application.yml b/blog_main/src/main/resources/application.yml index 2e1b1ac7..c181c069 100644 --- a/blog_main/src/main/resources/application.yml +++ b/blog_main/src/main/resources/application.yml @@ -103,9 +103,11 @@ minio: bucket-name: xxx resource-path: - avatar: avatar/ default-avatar: default_avatar.jpg + avatar: avatar/ blog-cover-image: blogCover/ + blog-image: blog/ + blog-image-url-base: https://local.sticki.cn/api/v1/resource/blog-img/ security: # JWT配置 @@ -119,7 +121,7 @@ security: # 过期时间 单位秒 1天后过期=86400 7天后过期=604800 expiration: 604800 # 配置不需要认证的接口,中间不能加空格 - ant-matchers: /login/**,/blog/**,/resource/**,/user,/register/** + ant-matchers: /login/**,/blog/**,/resource/**,/user,/register/**,/comment/list jetcache: statIntervalMinutes: 15 diff --git a/vueblog/package-lock.json b/vueblog/package-lock.json index 341d0457..03e4626d 100644 --- a/vueblog/package-lock.json +++ b/vueblog/package-lock.json @@ -12,7 +12,9 @@ "bootstrap": "^3.4.1", "core-js": "^3.8.3", "element-ui": "^2.15.6", + "github-markdown-css": "^5.1.0", "jquery": "^3.6.0", + "markdown-it": "^13.0.0", "mavon-editor": "^2.10.4", "qs": "^6.10.3", "vue": "^2.6.14", @@ -3024,6 +3026,11 @@ "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", "dev": true }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, "node_modules/array-flatten": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", @@ -5141,6 +5148,11 @@ "node": ">=6" } }, + "node_modules/github-markdown-css": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/github-markdown-css/-/github-markdown-css-5.1.0.tgz", + "integrity": "sha512-QLtORwHHtUHhPMHu7i4GKfP6Vx5CWZn+NKQXe+cBhslY1HEt0CTEkP4d/vSROKV0iIJSpl4UtlQ16AD8C6lMug==" + }, "node_modules/glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", @@ -5896,6 +5908,14 @@ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "dev": true }, + "node_modules/linkify-it": { + "version": "4.0.1", + "resolved": "https://registry.npmmirror.com/linkify-it/-/linkify-it-4.0.1.tgz", + "integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==", + "dependencies": { + "uc.micro": "^1.0.1" + } + }, "node_modules/loader-runner": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", @@ -6197,6 +6217,29 @@ "node": ">=8" } }, + "node_modules/markdown-it": { + "version": "13.0.1", + "resolved": "https://registry.npmmirror.com/markdown-it/-/markdown-it-13.0.1.tgz", + "integrity": "sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==", + "dependencies": { + "argparse": "^2.0.1", + "entities": "~3.0.1", + "linkify-it": "^4.0.1", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + }, + "bin": { + "markdown-it": "bin/markdown-it.js" + } + }, + "node_modules/markdown-it/node_modules/entities": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/entities/-/entities-3.0.1.tgz", + "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", + "engines": { + "node": ">=0.12" + } + }, "node_modules/mavon-editor": { "version": "2.10.4", "resolved": "https://registry.npmjs.org/mavon-editor/-/mavon-editor-2.10.4.tgz", @@ -6211,6 +6254,11 @@ "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", "dev": true }, + "node_modules/mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==" + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -8790,6 +8838,11 @@ "node": ">= 0.6" } }, + "node_modules/uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" + }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", @@ -11973,6 +12026,11 @@ "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", "dev": true }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, "array-flatten": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", @@ -13692,6 +13750,11 @@ "pump": "^3.0.0" } }, + "github-markdown-css": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/github-markdown-css/-/github-markdown-css-5.1.0.tgz", + "integrity": "sha512-QLtORwHHtUHhPMHu7i4GKfP6Vx5CWZn+NKQXe+cBhslY1HEt0CTEkP4d/vSROKV0iIJSpl4UtlQ16AD8C6lMug==" + }, "glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", @@ -14291,6 +14354,14 @@ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "dev": true }, + "linkify-it": { + "version": "4.0.1", + "resolved": "https://registry.npmmirror.com/linkify-it/-/linkify-it-4.0.1.tgz", + "integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==", + "requires": { + "uc.micro": "^1.0.1" + } + }, "loader-runner": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", @@ -14532,6 +14603,25 @@ "semver": "^6.0.0" } }, + "markdown-it": { + "version": "13.0.1", + "resolved": "https://registry.npmmirror.com/markdown-it/-/markdown-it-13.0.1.tgz", + "integrity": "sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==", + "requires": { + "argparse": "^2.0.1", + "entities": "~3.0.1", + "linkify-it": "^4.0.1", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + }, + "dependencies": { + "entities": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/entities/-/entities-3.0.1.tgz", + "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==" + } + } + }, "mavon-editor": { "version": "2.10.4", "resolved": "https://registry.npmjs.org/mavon-editor/-/mavon-editor-2.10.4.tgz", @@ -14546,6 +14636,11 @@ "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", "dev": true }, + "mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==" + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -16540,6 +16635,11 @@ "mime-types": "~2.1.24" } }, + "uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" + }, "unicode-canonical-property-names-ecmascript": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", diff --git a/vueblog/src/assets/css/base.css b/vueblog/src/assets/css/base.css index 9ae2e42a..1e31a395 100644 --- a/vueblog/src/assets/css/base.css +++ b/vueblog/src/assets/css/base.css @@ -53,4 +53,14 @@ a { .right { float: right; -} \ No newline at end of file +} +ol, ul { + list-style: none; +} +* { + -webkit-user-select: text; + -khtml-user-select: text; + -moz-user-select: text; + -ms-user-select: text; + user-select: text; +} diff --git a/vueblog/src/assets/img/blogDetail/blogComment/commentLike.png b/vueblog/src/assets/img/blogDetail/blogComment/commentLike.png new file mode 100644 index 00000000..a77866dd Binary files /dev/null and b/vueblog/src/assets/img/blogDetail/blogComment/commentLike.png differ diff --git a/vueblog/src/assets/img/blogDetail/blogComment/commentLikeActive.png b/vueblog/src/assets/img/blogDetail/blogComment/commentLikeActive.png new file mode 100644 index 00000000..7e25cddb Binary files /dev/null and b/vueblog/src/assets/img/blogDetail/blogComment/commentLikeActive.png differ diff --git a/vueblog/src/assets/img/blogDetail/blogComment/commentReply.png b/vueblog/src/assets/img/blogDetail/blogComment/commentReply.png new file mode 100644 index 00000000..0baf7256 Binary files /dev/null and b/vueblog/src/assets/img/blogDetail/blogComment/commentReply.png differ diff --git a/vueblog/src/assets/img/blogDetail/collection2.png b/vueblog/src/assets/img/blogDetail/collection2.png new file mode 100644 index 00000000..9e8f2ea2 Binary files /dev/null and b/vueblog/src/assets/img/blogDetail/collection2.png differ diff --git a/vueblog/src/assets/img/blogDetail/collection2_active.png b/vueblog/src/assets/img/blogDetail/collection2_active.png new file mode 100644 index 00000000..6354be00 Binary files /dev/null and b/vueblog/src/assets/img/blogDetail/collection2_active.png differ diff --git a/vueblog/src/assets/img/blogDetail/comment.png b/vueblog/src/assets/img/blogDetail/comment.png new file mode 100644 index 00000000..7eb4802b Binary files /dev/null and b/vueblog/src/assets/img/blogDetail/comment.png differ diff --git a/vueblog/src/assets/img/blogDetail/good.png b/vueblog/src/assets/img/blogDetail/good.png new file mode 100644 index 00000000..433dd5c2 Binary files /dev/null and b/vueblog/src/assets/img/blogDetail/good.png differ diff --git a/vueblog/src/assets/img/blogDetail/good_active.png b/vueblog/src/assets/img/blogDetail/good_active.png new file mode 100644 index 00000000..7d646657 Binary files /dev/null and b/vueblog/src/assets/img/blogDetail/good_active.png differ diff --git a/vueblog/src/axios.js b/vueblog/src/axios.js index 1e741478..1ca11fae 100644 --- a/vueblog/src/axios.js +++ b/vueblog/src/axios.js @@ -1,4 +1,42 @@ import axios from "axios"; +import ElementUI from 'element-ui'; // axios.defaults.baseURL="https://local.sticki.cn/api/v1" -axios.defaults.baseURL="/api" +// axios.defaults.baseURL="https://api.scblogs.cn/v1" +axios.defaults.baseURL = "/api" + +// 前置拦截 +axios.interceptors.request.use(config => { + return config +}) + +// 后置拦截 +axios.interceptors.response.use(response => { + let res = response.data; + console.log("===============") + console.log(res) + console.log("===============") + + if (res.code === 200) { + return response + } else if (res.code === 401) { + ElementUI.Message.error("未登录") + return Promise.reject(response.data.message) + } else { + ElementUI.Message.error("错误") + return Promise.reject(response.data.message) + } +}, + error => { + console.log("00"); + console.log(error) + if (error.response.data) { + error.message = error.response.data.message + } + if (error.response.status === 401) { + ElementUI.Message.error("未登录") + } + ElementUI.Message.error(error.message) + return Promise.reject(error) + } +) diff --git a/vueblog/src/components/P_user/Manage/managecontent.vue b/vueblog/src/components/P_user/Manage/managecontent.vue index f3d027f7..a8dbc795 100644 --- a/vueblog/src/components/P_user/Manage/managecontent.vue +++ b/vueblog/src/components/P_user/Manage/managecontent.vue @@ -2,6 +2,8 @@
+
    @@ -30,18 +32,34 @@
    这里啥也没有啊
-
-
+
+ 啥也没搜到! +
+
+
-
{{ item.title }}
-
{{ item.description }}
-
- {{ item.releaseTime }}. - {{ item.viewNum }}阅读 . - {{ item.likeNum }}点赞 . - {{ item.commentNum }}评论 . - {{ item.collectionNum }}收藏 +
{{ item.title }}
+
{{ item.description }}
+
+ {{ item.releaseTime }}. + {{ item.viewNum }}阅读 . + {{ item.likeNum }}点赞 . + {{ item.commentNum }}评论 . + {{ item.collectionNum }}收藏 +
+
+ +

这是一段内容这是一段内容确定删除吗?

+
+ 取消 + 确定 +
+ 删除 +
@@ -95,35 +113,43 @@ export default { // 显示遍历的列表 List: [], // 博客页数 - page:1, + page:0, // 搜索博客 searchblog:"", config:{ + params:{status:"0",page:"0"}, headers:{ - 'token':localStorage.getItem('token',{ - params:{ - status:"" - } - }) + 'token':localStorage.getItem('token') } - } + }, + visible2:false } }, - created(){ + async mounted(){ // 获取全部用户博客数据显示各种状态下的数据 - this.GetData() + // await this.GetData() + this.$refs.noneSearch.style.display="none" }, + // watch:{ + // config:{ + // handler(newName, oldName) { + // console.log('注意此时的config对象变化了',this.config); + // }, + // immediate: true + // } + // }, methods:{ - GetData(){ - console.log("开始调用") - this.$axios.get("/blog-console/blog-list",this.config).then(res=>{ - console.log("获取全部用户博客返回数据",res) - this.allList=res.data.data.blogList - this.List=this.allList + async GetData(){ + this.List=[] + await this.$axios.get("/blog-console/blog-list",this.config).then(res=>{ + this.allList=res.data.data.records + // this.page=res.data.data.pages + this.List=this.List.concat(this.allList) + // 将传参的页数标记增大1 + this.config.params.page+1 if(this.List.length>0){ this.$refs.writeBlog.style.display="none" } - console.log("此时应该展示的用户博客",this.List); }) }, // 手动选择部分 @@ -132,33 +158,43 @@ export default { }, // 滑动触底时调用 async infiniteHandler($state) { - console.log("其实已经到底了") - this.$axios - .get("/blog/list?page="+this.page) + await this.$axios + .get("/blog-console/blog-list",this.config) .then((res) => { - console.log("获取列表接口返回值",res) - if(res.data.data.length) { - this.page +=1; // 下一页 - this.allList = this.allList.concat(res.data.data); + if(res.data.data.records.length>0) { + this.config.params.page +=1; // 下一页 + this.allList = this.allList.concat(res.data.data.records); this.List=this.allList - console.log("此时所有的博客列表是",this.List) $state.loaded(); }else { - $state.complete(); + $state.complete(); } }) + if(this.List.length>0){ + this.$refs.writeBlog.style.display="none" + this.$refs.noneSearch.style.display="none" + } + console.log("此时所有的博客列表是",this.List) }, // 查找关键字博客列表 SearchBlog(){ this.$axios.get("/blog/search",{params:{ key:this.searchblog, }}).then(res=>{ - console.log("搜索博客返回的数据",res) + console.log("搜索返回的数据是",res.data) + if(res.data.data.records.length==0){ + // 显示啥都没搜到 + this.$refs.firstContent.style.display="none" + this.$refs.noneSearch.style.display="block" + }else{ + this.$refs.firstContent.style.display="block" + this.$refs.noneSearch.style.display="none" + this.List=res.data.records + } }) }, // 跳转至博客具体内容列表 TurnToShow(index){ - console.log("获取到的文章ID是",index) var routeUrl= this.$router.resolve({name:'BlogDetail',params:{blogId:index}}) window.open(routeUrl.href, '_blank'); }, @@ -173,13 +209,16 @@ export default { this.ScreenList[i].chose=false } this.ScreenList[index].chose=true + this.config.params.status=(index-1).toString() + this.config.params.page=1 + this.GetData()//所有博客 } } } } - \ No newline at end of file diff --git a/vueblog/src/components/P_user/PMELeftTabs/lefttabs8.vue b/vueblog/src/components/P_user/PMELeftTabs/lefttabs8.vue new file mode 100644 index 00000000..5e648b1a --- /dev/null +++ b/vueblog/src/components/P_user/PMELeftTabs/lefttabs8.vue @@ -0,0 +1,153 @@ + + + + + \ No newline at end of file diff --git a/vueblog/src/main.js b/vueblog/src/main.js index 67c67293..80511c25 100644 --- a/vueblog/src/main.js +++ b/vueblog/src/main.js @@ -36,3 +36,4 @@ new Vue({ render: h => h(App), }).$mount('#app') + diff --git a/vueblog/src/router/index.js b/vueblog/src/router/index.js index c55767dd..1756b6cb 100644 --- a/vueblog/src/router/index.js +++ b/vueblog/src/router/index.js @@ -13,6 +13,8 @@ const PersonalBlog = () => import('@/views/PersonalBlog') const PersonalMessageEdit = () => import('@/views/PersonalMessageEdit') const ContentManagement = () => import('@/views/ContentManagement') +// const Test = () => import('@/views/Test') + Vue.use(VueRouter) @@ -26,47 +28,47 @@ const routes = [ { path: '/home', name: 'Home', - component: Home + component: Home, }, { path: '/login', name: 'Login', - component: Login + component: Login, }, { path: '/register', name: 'register', - component: Register + component: Register, }, { path: '/blog/search', name: 'BlogSearch', - component: BlogSearch + component: BlogSearch, }, { path: '/blog/add', name: 'BlogAdd', - component: BlogEdit + component: BlogEdit, }, { path: '/blog/publish', name: 'BlogPublishSuccess', - component: BlogPublishSuccess + component: BlogPublishSuccess, }, { path: '/blog/:blogId', name: 'BlogDetail', - component: BlogDetail + component: BlogDetail, }, { path: '/blog/:blogId/edit', name: 'BlogEdit', - component: BlogEdit + component: BlogEdit, }, { path: '/Personal_Blog', name: 'PersonalBlog', - component: PersonalBlog + component: PersonalBlog, }, { path: '/PersonalMessageEdit', @@ -78,10 +80,16 @@ const routes = [ name: 'ContentManagement', component: ContentManagement }, + // { + // path: '/test', + // name: 'Test', + // component: Test + // }, ] const router = new VueRouter({ mode: 'history', + // mode: 'hash', base: process.env.BASE_URL, routes }) diff --git a/vueblog/src/views/ContentManagement.vue b/vueblog/src/views/ContentManagement.vue index dd7cd364..c76c0c57 100644 --- a/vueblog/src/views/ContentManagement.vue +++ b/vueblog/src/views/ContentManagement.vue @@ -98,15 +98,16 @@ export default { diff --git a/vueblog/src/views/blogDetail/childComps/BlogComment.vue b/vueblog/src/views/blogDetail/childComps/BlogComment.vue new file mode 100644 index 00000000..049895e8 --- /dev/null +++ b/vueblog/src/views/blogDetail/childComps/BlogComment.vue @@ -0,0 +1,531 @@ + + + + + diff --git a/vueblog/src/views/blogEdit/BlogEdit.vue b/vueblog/src/views/blogEdit/BlogEdit.vue index eb10eb59..753ccd91 100644 --- a/vueblog/src/views/blogEdit/BlogEdit.vue +++ b/vueblog/src/views/blogEdit/BlogEdit.vue @@ -30,6 +30,9 @@ @@ -74,6 +77,26 @@ export default { this.avatarUrl = window.localStorage.avatarUrl; }, methods: { + // md文档开始 + // 将图片上传到服务器,返回地址替换到md中 + imgAdd(pos, $file) { + var _this = this + var formdata = new FormData(); + formdata.append('file', $file); + this.$axios.post("https://local.sticki.cn/api/v1/blog-console/img",formdata,{ + headers: { token: localStorage.getItem("token") }, + }).then((response) => { + // 第二步.将返回的url替换到文本原位置![...](0) -> ![...](url) + if (response.status === 200) { + var url = response.data.data; + _this.$refs.md.$img2Url(pos,url) + } + }) + }, + imgDel(pos) { + + }, + // md文档结束 dialogShowChange(val) { this.dialogShow = val; }, diff --git a/vueblog/src/views/blogEdit/childComps/BlogEditDialog.vue b/vueblog/src/views/blogEdit/childComps/BlogEditDialog.vue index 4bec73a1..7e418917 100644 --- a/vueblog/src/views/blogEdit/childComps/BlogEditDialog.vue +++ b/vueblog/src/views/blogEdit/childComps/BlogEditDialog.vue @@ -42,44 +42,6 @@ - - - - - - - 公开 diff --git a/vueblog/src/views/blogSearch/BlogSearch.vue b/vueblog/src/views/blogSearch/BlogSearch.vue index 4f22ea49..e3362008 100644 --- a/vueblog/src/views/blogSearch/BlogSearch.vue +++ b/vueblog/src/views/blogSearch/BlogSearch.vue @@ -29,16 +29,10 @@
关于我们-{{ key }}
@@ -64,6 +58,18 @@ export default { return { key: this.$store.state.searchKey, blogSearchList: [], + relatedList: [ + "蓝桥杯历年真题", + "计算机毕业设计", + "微信小程序商城搭建", + "数据可视化工具", + "彻底搞懂背包问题", + "队列的基本操作", + "迷宫问题求解", + "前端练手项目合集", + "凯撒密码实现", + "数据库从入门到精通", + ], }; }, watch: { @@ -80,11 +86,21 @@ export default { // 保存key this.$store.commit("copySearchKey", this.key); sessionStorage.setItem("store", JSON.stringify(this.$store.state)); + this.$axios.get("/blog/search?key=" + this.key).then((res) => { console.log("加载后再次点击搜索", res); this.blogSearchList = res.data.data; }); }, + // 点击热搜榜搜索博客 + relatedSearch(key) { + this.key = key; + // 状态保持清除后刷新页面 + window.location.reload(); + // 保存key + this.$store.commit("copySearchKey", this.key); + sessionStorage.setItem("store", JSON.stringify(this.$store.state)); + } }, }; @@ -93,8 +109,7 @@ export default { .container { width: 100%; height: 100%; - /* min-height: 100vh; */ - min-height: calc(100vh - 65px); + min-height: calc(100vh - 48px); background-color: #f2f2f2; } diff --git a/vueblog/src/views/blogSearch/childComps/BlogSearchArticleItem.vue b/vueblog/src/views/blogSearch/childComps/BlogSearchArticleItem.vue index 90710e1f..7c2e4927 100644 --- a/vueblog/src/views/blogSearch/childComps/BlogSearchArticleItem.vue +++ b/vueblog/src/views/blogSearch/childComps/BlogSearchArticleItem.vue @@ -112,11 +112,14 @@ export default { // }, infiniteHandler($state) { this.$axios - .get("/blog/search",{params:{key:this.key,page:this.page}}) + .get("/blog/search",{params:{key:this.key,page:this.page}},{ + headers: { token: localStorage.getItem("token") }, + }) .then((res) => { - if(res.data.data.length) { + console.log(res) + if(res.data.data.records.length) { this.page +=1; // 下一页 - this.blogSearchList = this.blogSearchList.concat(res.data.data); + this.blogSearchList = this.blogSearchList.concat(res.data.data.records); console.log("下拉刷新",this.blogSearchList) // console.log(this.blogSearchList) $state.loaded(); diff --git a/vueblog/src/views/home/Home.vue b/vueblog/src/views/home/Home.vue index 5910b79f..9f489ee1 100644 --- a/vueblog/src/views/home/Home.vue +++ b/vueblog/src/views/home/Home.vue @@ -235,7 +235,7 @@ export default { .nav-content ul { position: relative; background-color: #fff; - box-shadow: 0 4px 30px 0 rgb(232 232 237 / 50%); + box-shadow: 0 4px 5px 0 rgb(232 232 237 / 50%); z-index: 5; } .nav-content ul li { diff --git a/vueblog/src/views/home/childComps/HomeArticleItem.vue b/vueblog/src/views/home/childComps/HomeArticleItem.vue index d682f646..7ec0d466 100644 --- a/vueblog/src/views/home/childComps/HomeArticleItem.vue +++ b/vueblog/src/views/home/childComps/HomeArticleItem.vue @@ -1,36 +1,58 @@ diff --git a/vueblog/src/views/login/childComps/LoginItem.vue b/vueblog/src/views/login/childComps/LoginItem.vue index e893cde0..6404830b 100644 --- a/vueblog/src/views/login/childComps/LoginItem.vue +++ b/vueblog/src/views/login/childComps/LoginItem.vue @@ -46,6 +46,7 @@