• 手写一个博客平台 ~ 第七天


    作者:fyupeng
    技术专栏:☞ https://github.com/fyupeng
    项目地址:☞ https://github.com/fyupeng/distributed-blog-system-api
    项目预览地址:☞ 博客第七天


    留给读者

    前面第六天的开发比较漫长,但你有没有发现,我解耦了数据持久层跟控制层的关联?

    还有,mapper配置文件和数据库的配置信息也完全去掉了,也就是完全解耦了与持久层的接触,而专注于控制层业务逻辑。

    这是怎么做到的呢?其实归功于RPC的功劳,如果你使用了Spring CloudEureka注册中心,你发现它的优势在于集群,而分布式简单来说是通过间接调用了SpringBoot的接口,也就是真实服务器的接口时可以直接调用的,而我的微服务它虽然真实服务也有接口,但不提供通过get和post请求调用,这也就保证了真实服务器的安全性,而只能通过代理服务去远程代理服务。

    远程代理服务怎么感觉听起来很牛掰呢?感觉好难理解呀!

    其实不难解释,所谓远程代理,其实是通过Java的反射Reflect + Netty客户端与服务端之间的通信实现。

    具体是通过自定义协议,将你要做的事,即调用这个服务(例如UserService接口你已经在控制层规范了),通过该接口去反射调用方法,怎么调用?方法不是抽象方法吗?

    Netty通信规范一套字节的编码和解码,比如我要调用这个方法,那么我就将这个类以及方法名和方法所需参数编译成字节码通过客户端传送给服务端,服务端接收到后,按照客户端编译的同方向解码,具体可以看看rpc-netty-framework的底层源码,其实很好理解的。

    下面主要开发博客的几块真实服务

    1. 通用配置和启动器配置

    1.1 文件配置
    • application.properties配置文件
    ############################################################
    #
    # Close Port And provide bean definition ioc
    #
    ############################################################
    spring.main.web-application-type=none
    spring.main.allow-bean-definition-overriding=true
    
    ############################################################
    #
    # DataSource Pool - druid
    #
    ############################################################
    spring.datasource.url=jdbc:mysql://localhost:3306/fyupeng_blog?useUnicode=true&characterEncoding=utf8&useJDBCComplliantTimezoneShift=true\
      &useLegacyDatetimeCode=false&serverTimezone=UTC
    spring.datasource.username=your_mysql_username
    spring.datasource.password=your_mysql_password
    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
    spring.datasource.druid.initial-size=1
    spring.datasource.druid.min-idle=1
    spring.datasource.druid.max-active=20
    spring.datasource.druid.test-on-borrow=true
    spring.datasource.druid.stat-view-servlet.allow=true
    ############################################################
    #
    # mybatis
    #
    ############################################################
    # mybatis
    mybatis.type-aliases-package=cn.fyupeng.pojo
    mybatis.mapper-locations=classpath:mapper/*.xml
    # Mapper
    mapper.mappers=cn.fyupeng.utils.MyMapper
    mapper.not-empty=false
    mapper.identity=MYSQL
    # page pagination
    pagehelper.helperDialect=mysql
    pagehelper.supportMethodsArguments=true
    pagehelper.params=count=countSql
    
    # springboot 1.5
    #spring.http.multipart.maxFileSize=150Mb
    #spring.http.multipart.maxRequestSize=1000Mb
    # springboot 2.0
    spring.servlet.multipart.max-file-size=150MB
    spring.servlet.multipart.max-request-size=1000MB
    
    ############################################################
    #
    # Redis
    #
    ############################################################
    
    # Redis default use dataBase
    #spring.redis.database=0
    
    ## Redis Host
    spring.redis.host=localhost
    ## Redis Port
    spring.redis.port=6379
    
    # Redis password
    spring.redis.password=your_redis_password
    
    
    #spring.redis.pool.max-active=300
    spring.redis.jedis.pool.max-active=300
    #spring.redis.pool.max-wait=10000
    spring.redis.jedis.pool.max-wait=10000
    #spring.redis.pool.maxIdle=300
    spring.redis.jedis.pool.max-idle=300
    #spring.redis.pool.minIdle=6
    spring.redis.jedis.pool.min-idle=6
    spring.redis.timeout=0
    
    # mongodb
    spring.data.mongodb.host=localhost
    spring.data.mongodb.port=27017
    spring.data.mongodb.database=database
    # 从哪个数据库创建的用户,使用它来验证身份
    spring.data.mongodb.authentication-database=database
    spring.data.mongodb.username=your_username
    spring.data.mongodb.password=your_password
    
    • resource.properties
    # nacos 配置
    cn.fyupeng.nacos.register-addr=localhost:8848
    
    # 自定义配置
    cn.fyupeng.config.serverPort=8082
    
    • 配置类
    package cn.fyupeng.config;
    
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.PropertySource;
    
    /**
     * @Auther: fyp
     * @Date: 2022/8/17
     * @Description: 资源配置
     * @Package: cn.fyupeng.config
     * @Version: 1.0
     */
    @Configuration
    @ConfigurationProperties(prefix="cn.fyupeng.config")
    //不使用默认配置文件application.properties和application.yml
    @PropertySource("classpath:resource.properties")
    public class ResourceConfig {
        private int serverPort;
    
        public int getServerPort() {
            return serverPort;
        }
    
        public void setServerPort(int serverPort) {
            this.serverPort = serverPort;
        }
    }
    
    1.2 启动器配置
    • 启动器
    package cn.fyupeng;
    
    import cn.fyupeng.config.ResourceConfig;
    import cn.fyupeng.anotion.ServiceScan;
    import cn.fyupeng.enums.SerializerCode;
    import cn.fyupeng.net.netty.server.NettyServer;
    import cn.fyupeng.utils.ResourceLoadUtils;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.CommandLineRunner;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.annotation.ComponentScan;
    import tk.mybatis.spring.annotation.MapperScan;
    
    import javax.annotation.PostConstruct;
    import java.util.Map;
    
    /**
     * @Auther: fyp
     * @Date: 2022/8/13
     * @Description:
     * @Package: cn.fyupeng
     * @Version: 1.0
     */
    
    @Slf4j
    @ServiceScan
    @SpringBootApplication
    @MapperScan(basePackages = "cn.fyupeng.mapper")
    @ComponentScan(basePackages = {"cn.fyupeng", "org.n3r.idworker"})
    public class UserServer implements CommandLineRunner {
    
        @Autowired
        private ResourceConfig resourceConfig;
    
        @PostConstruct
        public void init() {
            Map<String, String> resourceLoaders = ResourceLoadUtils.load("resource.properties");
            if (resourceLoaders != null) {
                String serverPort = resourceLoaders.get("cn.fyupeng.config.serverPort");
                resourceConfig.setServerPort(Integer.parseInt(serverPort));
            }
        }
    
        public static void main(String[] args) throws InterruptedException {
            SpringApplication.run(UserServer.class, args);
        }
    
        @Override
        public void run(String... args) throws Exception {
            //这里也可以添加一些业务处理方法,比如一些初始化参数等
            while(true){
                NettyServer nettyServer = new NettyServer("127.0.0.1", resourceConfig.getServerPort(), SerializerCode.KRYO.getCode());
                log.info("Service bind in port with "+ resourceConfig.getServerPort() +" and start successfully!");
                nettyServer.start();
                log.error("RegisterAndLoginService is died,Service is restarting....");
            }
        }
    }
    

    2. 逻辑服务

    1.1 服务接口

    与代理服务中的控制层使用的服务接口保持一致

    • UserService接口
    package cn.fyupeng.service;
    
    import cn.fyupeng.pojo.User;
    import cn.fyupeng.pojo.UserInfo;
    
    /**
     * @Auther: fyp
     * @Date: 2022/8/17
     * @Description: 用户业务服务接口
     * @Package: cn.fyupeng.service
     * @Version: 1.0
     */
    public interface UserService {
    
        /**
         * @Description: 判断用户名是否存在
         * @param username
         * @return
         */
        public boolean queryUsernameIsExist(String username);
    
        /**
         * @Description: 用户登录,根据用户名和密码查询用户
         * @param username
         * @param password
         * @return
         */
        public User queryUserForLogin(String username, String password);
    
        /**
         * 查询用户信息
         * @param userId
         * @return
         */
        User queryUser(String userId);
    
        /**
         * 查询用户详细信息
         * @param userId
         * @return
         */
        public UserInfo queryUserInfo(String userId);
    
        /**
         * 查询用户是否存在
         * @param userId
         * @return
         */
        boolean queryUserIdIsExist(String userId);
        /**
         * @Description: 用户修改信息
         * @param user
         */
        public boolean updateUser(User user);
    
        /**
         * @Description: 用户修改详细信息
         * @param user
         */
    
        /**
         * @Description: 保存用户(注册用户)
         * @param user
         */
        public void saveUser(User user);
    
        public void updateUserInfo(UserInfo user);
    
    }
    
    • ArticleService接口
    package cn.fyupeng.service;
    
    import cn.fyupeng.utils.PagedResult;
    import cn.fyupeng.pojo.Article;
    import cn.fyupeng.pojo.vo.ArticleVO;
    
    import java.util.List;
    import java.util.Map;
    
    /**
     * @Auther: fyp
     * @Date: 2022/4/2
     * @Description:
     * @Package: com.crop.service
     * @Version: 1.0
     */
    public interface ArticleService {
    
        boolean queryArticleIsExist(String articleId);
    
        boolean queryArticleIsUser(Article article);
    
        boolean save(Article article);
    
        PagedResult queryArticleSelective(Article article, Integer page, Integer pageSize);
    
        ArticleVO queryArticleDetail(String articleId);
    
        boolean saveWithIdAndUserId(Article article);
    
        void multiUpdateArticleReadCounts(List<String> articleIdKeys, Map<String, String> articleMap);
    
        void removeArticle(String articleId);
    
        PagedResult queryArticleByTime(Long timeDifference, Integer page, Integer pageSize);
    
        List<ArticleVO> queryArticleWithNoneTagByUser(String userId);
    }
    
    • ClassficationService接口
    package cn.fyupeng.service;
    
    
    import cn.fyupeng.pojo.Classfication;
    
    import java.util.List;
    
    /**
     * @Auther: fyp
     * @Date: 2022/4/3
     * @Description:
     * @Package: com.crop.service
     * @Version: 1.0
     */
    public interface ClassficationService {
        boolean queryClassficationIdIsExist(String classId);
    
        boolean saveClassfication(Classfication classfication);
    
        Classfication queryClassfication(Classfication classfication);
    
        List<Classfication> queryAllClassfications();
    
        boolean deleteClassfication(String classficationId);
    
        boolean updateClassfication(Classfication clssfication);
    }
    
    • TagService接口
    package cn.fyupeng.service;
    
    import cn.fyupeng.pojo.Articles2tags;
    import cn.fyupeng.pojo.Tag;
    import cn.fyupeng.pojo.vo.Articles2tagsVO;
    import cn.fyupeng.pojo.vo.TagVO;
    
    import java.util.List;
    
    /**
     * @Auther: fyp
     * @Date: 2022/4/8
     * @Description:
     * @Package: com.crop.service
     * @Version: 1.0
     */
    public interface TagService {
    
        boolean queryTagIsExist(Tag tag);
    
        boolean queryArticleTagIsExist(String id);
    
        boolean queryArticleTagIsExist(Articles2tags articles2tags);
    
        List<TagVO> queryAllTags(Tag tag);
    
        boolean saveTag(Tag tag);
    
        boolean updateTag(Tag tag);
    
        boolean deleteTag(String tagId);
    
        void delArticleTag(String tagId);
    
        boolean deleteTagAndArticleTagWithTagId(String tagId);
    
        Tag queryTag(String tagId);
    
        List<Articles2tagsVO> queryArticleTag(Articles2tags articles2tags);
    
        boolean saveArticleTag(Articles2tags articles2tags);
    
        boolean updateArticleTag(Articles2tags articles2tags);
    
        boolean deleteTagAndArticleTagWithArticleId(String articleId);
    }
    
    • CommentService接口
    package cn.fyupeng.service;
    
    import cn.fyupeng.pojo.Comment;
    import cn.fyupeng.pojo.vo.CommentVO;
    import cn.fyupeng.enums.CommentStatus;
    import cn.fyupeng.utils.PagedResult;
    
    import java.util.Date;
    import java.util.List;
    
    /**
     * @Auther: fyp
     * @Date: 2022/4/3
     * @Description:
     * @Package: com.crop.service
     * @Version: 1.0
     */
    public interface CommentService {
    
        boolean saveComment(Comment comment);
    
    
        void removeCommentById(String commentId);
    
        Comment queryComment(String commentId);
    
        boolean queryCommentIsExist(String commentId);
    
        boolean updateComment(Comment comment);
    
        PagedResult queryAllComments(String articleId, Integer page, Integer pageSize, Integer sort);
    
        boolean queryCommentWithFatherCommentIsExist(String commentId);
    
        void removeCommentWithFatherCommentId(String fatherCommentId);
    
        List<CommentVO> queryAllComments(String aPattern, String cPattern, String userId, Date startTime, Date endTime);
    
        void setCommentStatusWithFatherId(Comment comment, CommentStatus commentStatus);
    }
    
    2.2 服务实现
    • UserService实现类
    package cn.fyupeng.service.impl;
    
    import cn.fyupeng.mapper.UserInfoMapper;
    import cn.fyupeng.mapper.UserMapper;
    import cn.fyupeng.pojo.User;
    import cn.fyupeng.pojo.UserInfo;
    import cn.fyupeng.service.UserService;
    import cn.fyupeng.anotion.Service;
    import org.n3r.idworker.Sid;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    import org.springframework.transaction.annotation.Propagation;
    import org.springframework.transaction.annotation.Transactional;
    import tk.mybatis.mapper.entity.Example;
    import tk.mybatis.mapper.entity.Example.Criteria;
    
    import javax.annotation.PostConstruct;
    
    
    @SuppressWarnings("all")
    @Service
    @Component
    public class UserServiceImpl implements UserService {
    
        private static UserServiceImpl basicService;
    
        @Autowired
        private UserMapper userMapper;
    
        @Autowired
        private UserInfoMapper userInfoMapper;
    
        @Autowired
        private Sid sid;
    
        @PostConstruct
        public void init() {
            basicService = this;
        }
    
        public UserServiceImpl() {
        }
    
        @Override
        @Transactional(propagation = Propagation.SUPPORTS)
        public boolean queryUserIdIsExist(String userId) {
    
            User user = new User();
            user.setId(userId);
            User result = basicService.userMapper.selectOne(user);
    
            return result == null ? false : true;
        }
    
        @Override
        @Transactional(propagation = Propagation.SUPPORTS)
        public boolean queryUsernameIsExist(String username) {
    
            User user = new User();
            user.setUsername(username);
            User result = basicService.userMapper.selectOne(user);
    
            return result == null ? false : true;
        }
    
        @Override
        @Transactional(propagation = Propagation.SUPPORTS)
        public User queryUser(String userId) {
            Example userExample = new Example(User.class);
    
            Criteria criteria = userExample.createCriteria();
            criteria.andEqualTo("id", userId);
            User user = basicService.userMapper.selectOneByExample(userExample);
    
            return user;
        }
    
        @Override
        @Transactional(propagation = Propagation.SUPPORTS)
        public UserInfo queryUserInfo(String userId) {
            Example userInfoExample = new Example(UserInfo.class);
    
            Criteria criteria = userInfoExample.createCriteria();
            criteria.andEqualTo("userId", userId);
            UserInfo userInfo = basicService.userInfoMapper.selectOneByExample(userInfoExample);
            return userInfo;
        }
    
        @Override
        @Transactional(propagation = Propagation.SUPPORTS)
        public User queryUserForLogin(String username, String password){
            Example userExample = new Example(User.class);
            Criteria criteria = userExample.createCriteria();
            criteria.andEqualTo("username", username);
            criteria.andEqualTo("password", password);
            User result = basicService.userMapper.selectOneByExample(userExample);
    
            return result;
        }
    
        @Override
        @Transactional(propagation = Propagation.REQUIRED)
        public void saveUser(User user) {
    
            String userId = basicService.sid.nextShort();
            String userInfoId = basicService.sid.nextShort();
            UserInfo userInfo = new UserInfo();
    
            user.setId(userId);
    
            userInfo.setId(userInfoId);
            userInfo.setUserId(userId);
    
            basicService.userMapper.insert(user);
            basicService.userInfoMapper.insert(userInfo);
        }
    
        @Override
        @Transactional(propagation = Propagation.REQUIRED)
        public boolean updateUser(User user){
            int i = basicService.userMapper.updateByPrimaryKey(user);
    
            return i > 0 ? true : false;
            /**
             * 防止 在 controller 忘记 传进 id 值,将会导致 所有用户 被更改
             *  fix : 弃用
            if (StringUtils.isBlank(user.getId())) {
                return;
            }
            Example userExample = new Example(User.class);
    
            // id 值为空时, 会 匹配所有用户,危险 !!!
            Criteria criteria = userExample.createCriteria();
            criteria.andEqualTo("id", user.getId());
            userMapper.updateByExampleSelective(user, userExample);
             */
        }
    
        @Override
        @Transactional(propagation = Propagation.REQUIRED)
        public void updateUserInfo(UserInfo userInfo){
    
            Example userInfoExample = new Example(UserInfo.class);
    
            Criteria criteria = userInfoExample.createCriteria();
            criteria.andEqualTo("id", userInfo.getId());
            criteria.andEqualTo("userId", userInfo.getUserId());
    
            basicService.userInfoMapper.updateByExampleSelective(userInfo, userInfoExample);
        }
    
    }
    
    • ArticleServiceImpl实现
    package cn.fyupeng.service.impl;
    
    import cn.fyupeng.mapper.*;
    import cn.fyupeng.pojo.*;
    import cn.fyupeng.pojo.vo.Articles2tagsVO;
    import cn.fyupeng.utils.PagedResult;
    import cn.fyupeng.utils.TimeAgoUtils;
    import cn.fyupeng.pojo.vo.ArticleVO;
    import cn.fyupeng.service.ArticleService;
    import cn.fyupeng.anotion.Service;
    import org.apache.commons.lang3.StringUtils;
    import org.n3r.idworker.Sid;
    import org.springframework.beans.BeanUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.domain.*;
    import org.springframework.data.mongodb.core.MongoTemplate;
    import org.springframework.data.mongodb.core.query.Criteria;
    import org.springframework.data.mongodb.core.query.Query;
    import org.springframework.stereotype.Component;
    import org.springframework.transaction.annotation.Propagation;
    import org.springframework.transaction.annotation.Transactional;
    
    import javax.annotation.PostConstruct;
    import java.text.SimpleDateFormat;
    import java.util.*;
    
    /**
     * @Auther: fyp
     * @Date: 2022/4/2
     * @Description:
     * @Package: com.crop.service.impl
     * @Version: 1.0
     */
    @SuppressWarnings("all")
    @Component
    @Service
    public class ArticleServiceImpl implements ArticleService {
    
        private static ArticleServiceImpl basicService;
    
        @Autowired
        private ArticleRepository articleRepository;
    
        @Autowired
        private MongoTemplate mongoTemplate;
    
        @Autowired
        private UserInfoMapper userinfoMapper;
    
        @Autowired
        private ClassficationMapper classficationMapper;
    
        @Autowired
        private TagMapper tagMapper;
    
        @Autowired
        private Articles2tagsMapper articles2tagsMapper;
    
        @Autowired
        private Sid sid;
    
        @PostConstruct
        public void init() {
            this.basicService = this;
        }
    
        @Override
        @Transactional(propagation = Propagation.SUPPORTS)
        public boolean queryArticleIsExist(String articleId) {
    
            Article article = new Article();
            article.setId(articleId);
    
            Example<Article> articleExample = Example.of(article);
    
            Optional<Article> one = basicService.articleRepository.findOne(articleExample);
            Article result = one.isPresent() ? one.get() : null;
    
            return article == null ? false : true;
        }
    
        @Override
        @Transactional(propagation = Propagation.SUPPORTS)
        public boolean queryArticleIsUser(Article article) {
    
            ExampleMatcher matching = ExampleMatcher.matching();
            ExampleMatcher exampleMatcher = matching.withMatcher("id", ExampleMatcher.GenericPropertyMatchers.exact())
                .withMatcher("userId", ExampleMatcher.GenericPropertyMatchers.exact());
    
            Example<Article> articleExample = Example.of(article, exampleMatcher);
    
            Optional<Article> one = basicService.articleRepository.findOne(articleExample);
            Article result = one.isPresent() ? one.get() : null;
    
            return result == null ? false : true;
        }
    
        /**
         * 查询 所有文章 时, 不做 流量统计,查询单篇文章,统计 阅读量
         * @param article
         * @param page
         * @param pageSize
         * @return
         */
        @Override
        @Transactional(propagation = Propagation.SUPPORTS)
        public PagedResult queryArticleSelective(Article article, Integer page, Integer pageSize) {
    
            //分页查询对象
            if(page <= 0){
                page = 1;
            }
            // page 分页 在 mongodb 中是 从 0 开始的,转换为物理位置
            page = page - 1;
    
            if(pageSize <= 0){
                pageSize = 6;
            }
    
            ExampleMatcher matching = ExampleMatcher.matching();
            Page<Article> all = null;
    
            Article a = new Article();
    
            // 存在 分类名 为 key
            if (!StringUtils.isBlank(article.getClassId())) {
                all = readAndExcute("classId", matching, article, page, pageSize);
            } else {
                Article titleArticle = new Article();
                titleArticle.setTitle(article.getTitle());
                all = readAndExcute("title", matching, titleArticle, page, pageSize);
                if (all.getTotalElements() == 0) {
                    Article summaryArticle = new Article();
                    summaryArticle.setSummary(article.getSummary());
                    all = readAndExcute("summary", matching, summaryArticle, page, pageSize);
                    if (all.getTotalElements() == 0) {
                        Article contentArticle = new Article();
                        contentArticle.setContent(article.getSummary());
                        all = readAndExcute("content", matching, contentArticle, page, pageSize);
                        if (all.getTotalElements() == 0)
                            return null;
                    }
                }
            }
            // 总 记录数
            long total = all.getTotalElements();
    
            List<Article> content = all.getContent();
            List<ArticleVO> artileVOList = new ArrayList<>();
    
            // 时间处理
            for (Article ac : content) {
                String createTimeAgo = TimeAgoUtils.format(ac.getCreateTime());
                String updateTimeAgo = TimeAgoUtils.format(ac.getUpdateTime());
                ArticleVO articleVO = new ArticleVO();
                BeanUtils.copyProperties(ac, articleVO);
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                String normalCreateTime = sdf.format(ac.getCreateTime());
                String normalUpdateTime = sdf.format(ac.getUpdateTime());
                articleVO.setNormalCreateTime(normalCreateTime);
                articleVO.setNormalUpdateTime(normalUpdateTime);
                articleVO.setCreateTimeAgoStr(createTimeAgo);
                articleVO.setUpdateTimeAgoStr(updateTimeAgo);
                /**
                 * 查询量 太大,流量大,而且 用户 只是在 查询而已,不需要评论 和 内容
                 */
                articleVO.setContent(null);
                artileVOList.add(articleVO);
            }
    
            // 降序排序,最近发表的文章 放到了 最前面
            Collections.sort(artileVOList);
    
            // 总 页数
            int pages = all.getTotalPages();
    
            PagedResult pagedResult = new PagedResult();
            // 设置 总记录数
            pagedResult.setRecords(total);
            // 设置 内容列表
            //pagedResult.setRows(content); 原始数据
            pagedResult.setRows(artileVOList);
    
            // 设置 当前页,转换为逻辑位置
            pagedResult.setPage(page+1);
            // 设置 总页数
            pagedResult.setTotal(pages);
    
            return pagedResult;
        }
    
        @Override
        @Transactional(propagation = Propagation.SUPPORTS)
        public ArticleVO queryArticleDetail(String articleId) {
    
            /**
             * 每次获取 文章,该 文章的 阅读数要 自增 1
             */
    
            Article article = new Article();
            article.setId(articleId);
            Example<Article> articleExample = Example.of(article);
    
            Optional<Article> one = basicService.articleRepository.findOne(articleExample);
            Article result = one.isPresent() ? one.get() : null;
            ArticleVO articleVO = new ArticleVO();
            if (result != null) {
                BeanUtils.copyProperties(result, articleVO);
    
                String createTimeAgo = TimeAgoUtils.format(result.getCreateTime());
                String updateTimeAgo = TimeAgoUtils.format(result.getUpdateTime());
    
                tk.mybatis.mapper.entity.Example userInfoExample = new tk.mybatis.mapper.entity.Example(UserInfo.class);
                tk.mybatis.mapper.entity.Example.Criteria criteria = userInfoExample.createCriteria();
    
                criteria.andEqualTo("userId", result.getUserId());
    
                UserInfo userInfo = basicService.userinfoMapper.selectOneByExample(userInfoExample);
                Classfication classfication = basicService.classficationMapper.selectByPrimaryKey(result.getClassId());
    
                articleVO.setAvatar(userInfo.getAvatar());
                articleVO.setNickName(userInfo.getNickname());
                articleVO.setClassficationName(classfication.getName());
    
                // 标签
                String aid = result.getId();
                Articles2tags articles2tags = new Articles2tags();
                articles2tags.setArticleId(aid);
                List<Articles2tagsVO> select = queryArticleTag(articles2tags);
                if (select.size() != 0) {
                    Tag tag = basicService.tagMapper.selectByPrimaryKey(select.get(0).getTagId());
                    articleVO.setTagId(tag.getId());
                    articleVO.setTagName(tag.getName());
                }
    
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                String normalCreateTime = sdf.format(result.getCreateTime());
                String normalUpdateTime = sdf.format(result.getUpdateTime());
                articleVO.setNormalCreateTime(normalCreateTime);
                articleVO.setNormalUpdateTime(normalUpdateTime);
    
                articleVO.setCreateTimeAgoStr(createTimeAgo);
                articleVO.setUpdateTimeAgoStr(updateTimeAgo);
                return articleVO;
            }
    
            return null;
        }
    
        private List<Articles2tagsVO> queryArticleTag(Articles2tags articles2tags) {
    
            List<Articles2tags> articles2tagsList = basicService.articles2tagsMapper.select(articles2tags);
    
            for (Articles2tags tags : articles2tagsList) {
                System.out.println(tags);
            }
    
            List<Articles2tagsVO> articles2tagsVOList = new ArrayList<>();
            for (Articles2tags articleTags : articles2tagsList) {
    
                String articleId = articleTags.getArticleId();
                String tagId = articleTags.getTagId();
    
                Tag tag = basicService.tagMapper.selectByPrimaryKey(tagId);
    
                Article article = new Article();
                article.setId(articleId);
    
                org.springframework.data.domain.Example<Article> articleExample = org.springframework.data.domain.Example.of(article);
    
    
                Optional<Article> articleOptional = basicService.articleRepository.findOne(articleExample);
                Article one = articleOptional.isPresent() ? articleOptional.get() : null;
    
                if (one != null) {
    
                    Classfication classfication = basicService.classficationMapper.selectByPrimaryKey(one.getClassId());
    
                    Articles2tagsVO articles2tagsVO = new Articles2tagsVO();
                    BeanUtils.copyProperties(articleTags, articles2tagsVO);
    
                    articles2tagsVO.setTagName(tag.getName());
                    articles2tagsVO.setTitle(one.getTitle());
                    articles2tagsVO.setClassficationName(classfication.getName());
                    articles2tagsVO.setCommentCounts(one.getCommentCounts());
                    articles2tagsVO.setReadCounts(one.getReadCounts());
                    articles2tagsVO.setReceiveLikeCounts(one.getReceiveLikeCounts());
    
                    String createTimeAgo = TimeAgoUtils.format(one.getCreateTime());
                    String updateTimaAgo = TimeAgoUtils.format(one.getUpdateTime());
    
                    articles2tagsVO.setCreateTimeAgoStr(createTimeAgo);
                    articles2tagsVO.setUpdateTimeAgoStr(updateTimaAgo);
    
                    articles2tagsVOList.add(articles2tagsVO);
                }
            }
    
            return articles2tagsVOList;
        }
    
        @Override
        @Transactional(propagation = Propagation.REQUIRED)
        public void multiUpdateArticleReadCounts(List<String> articleIdKeys, Map<String, String> articleMap) {
            for (String articleId : articleIdKeys) {
    
                Article article = new Article();
                article.setId(articleId);
    
                Example<Article> articleExample = Example.of(article);
    
                Optional<Article> one = basicService.articleRepository.findOne(articleExample);
                Article oldArticle = one.isPresent() ? one.get() : null;
                // 获取 articleId 对应的 readCounts
                String readCounts = articleMap.get(articleId);
                // 更新 readCounts
                if (oldArticle != null) {
                    oldArticle.setReadCounts(Integer.parseInt(readCounts));
    
                    basicService.articleRepository.save(oldArticle);
                }
            }
        }
    
        @Override
        @Transactional(propagation = Propagation.REQUIRED)
        public void removeArticle(String articleId) {
            /**
             * 必须根据 id 删除
    
            Article article = new Article();
            article.setId(articleId);
            articleRepository.delete(article);
             */
            Query queryArticle = new Query();
            queryArticle.addCriteria(Criteria.where("id").is(articleId));
            basicService.mongoTemplate.remove(queryArticle, Article.class);
    
            // 删除评论
            Query queryComment = new Query();
            queryComment.addCriteria(Criteria.where("articleId").is(articleId));
            basicService.mongoTemplate.remove(queryComment, Comment.class);
    
            // 删除关联标签nav
            deleteTagAndArticleTagWithArticleId(articleId);
        }
    
        private boolean deleteTag(String tagId) {
    
            int i = basicService.tagMapper.deleteByPrimaryKey(tagId);
    
            return i > 0 ? true : false;
        }
    
        private void delArticleTag(String tagId) {
    
            tk.mybatis.mapper.entity.Example articles2tagsExample = new tk.mybatis.mapper.entity.Example(Articles2tags.class);
            tk.mybatis.mapper.entity.Example.Criteria criteria = articles2tagsExample.createCriteria();
            criteria.andEqualTo("tagId", tagId);
    
            int i = basicService.articles2tagsMapper.deleteByExample(articles2tagsExample);
    
        }
    
        private boolean deleteTagAndArticleTagWithArticleId(String articleId) {
            tk.mybatis.mapper.entity.Example example = new tk.mybatis.mapper.entity.Example(Articles2tags.class);
    
            tk.mybatis.mapper.entity.Example.Criteria criteria = example.createCriteria();
            criteria.andEqualTo("articleId", articleId);
    
            int i = basicService.articles2tagsMapper.deleteByExample(example);
    
            return i > 0 ? true : false;
        }
    
        @Override
        @Transactional(propagation = Propagation.SUPPORTS)
        public PagedResult queryArticleByTime(Long timeDifference, Integer page, Integer pageSize) {
    
            //分页查询对象
            if(page <= 0){
                page = 1;
            }
            // page 分页 在 mongodb 中是 从 0 开始的,转换为 物理位置
            page = page - 1;
    
            if(pageSize <= 0){
                pageSize = 10;
            }
    
            // 当前时间
            Long now = System.currentTimeMillis();
            Long time = now - timeDifference;
            // 一周前的 日期
            Date oneWekkAgodate = new Date(time);
    
            Query queryAll = new Query();
            Query queryCurrentPage = new Query();
    
            queryAll.addCriteria(Criteria.where("createTime").gt(oneWekkAgodate));
            queryCurrentPage.addCriteria(Criteria.where("createTime").gt(oneWekkAgodate));
    
            // 倒序 时间
            Sort sort = new Sort(Sort.Direction.DESC, "createTime");
            queryAll.with(sort);
            queryCurrentPage.with(sort);
            PageRequest pageRequest = new PageRequest(page, pageSize);
            queryCurrentPage.with(pageRequest);
            // 分页
    
            /**
             * PageHelper 不支持 mongodb 查询
             */
            //PageHelper.startPage(page, pageSize);
            List<Article> allArticleList = basicService.mongoTemplate.find(queryAll, Article.class);
            List<Article> currentPageArticleList = basicService.mongoTemplate.find(queryCurrentPage, Article.class);
    
    
            List<ArticleVO> artileVOList = new ArrayList<>();
    
            // 时间处理
            for (Article ac : currentPageArticleList) {
                String createTimeAgo = TimeAgoUtils.format(ac.getCreateTime());
                String updateTimeAgo = TimeAgoUtils.format(ac.getUpdateTime());
                ArticleVO articleVO = new ArticleVO();
                BeanUtils.copyProperties(ac, articleVO);
                articleVO.setCreateTimeAgoStr(createTimeAgo);
                articleVO.setUpdateTimeAgoStr(updateTimeAgo);
                /**
                 * 查询量 太大,流量大,而且 用户 只是在 查询而已,不需要评论 和 内容
                 */
                articleVO.setContent(null);
                artileVOList.add(articleVO);
            }
    
            long records = allArticleList.size();
            int total = 1;
            // 每页 大小 小于 总记录数 时才需要分页
            if (pageSize < records) {
                // 最后一页 还有 数据
                if (records % pageSize != 0) {
                    total += records / pageSize;
                } else {
                    total = (int) (records / pageSize);
                }
            }
    
            PagedResult pagedResult = new PagedResult();
            pagedResult.setTotal(total);
            pagedResult.setRecords(records);
            pagedResult.setRows(artileVOList);
            // page 最后转换为 逻辑位置
            pagedResult.setPage(page+1);
    
    
            return pagedResult;
        }
    
        @Override
        @Transactional(propagation = Propagation.SUPPORTS)
        public List<ArticleVO> queryArticleWithNoneTagByUser(String userId) {
    
            ExampleMatcher matching = ExampleMatcher.matching();
            ExampleMatcher articleExampleMatcher = matching.withMatcher("userId", ExampleMatcher.GenericPropertyMatchers.exact());
    
            Article article = new Article();
            article.setUserId(userId);
    
            Example<Article> articleExample = Example.of(article, articleExampleMatcher);
    
            List<Article> all = basicService.articleRepository.findAll(articleExample);
    
            List<ArticleVO> artileVOList = new ArrayList<>();
            for (Article ac : all) {
    
                String articleId = ac.getId();
                Articles2tags articles2tags = new Articles2tags();
                articles2tags.setArticleId(articleId);
                // 过滤掉 有标签 标记的 用户文章
                boolean articleTagIsExist = queryArticleTagIsExist(articles2tags);
                if (articleTagIsExist) {
                    continue;
                }
    
                String createTimeAgo = TimeAgoUtils.format(ac.getCreateTime());
                String updateTimeAgo = TimeAgoUtils.format(ac.getUpdateTime());
                ArticleVO articleVO = new ArticleVO();
                BeanUtils.copyProperties(ac, articleVO);
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                String normalCreateTime = sdf.format(ac.getCreateTime());
                String normalUpdateTime = sdf.format(ac.getUpdateTime());
                articleVO.setNormalCreateTime(normalCreateTime);
                articleVO.setNormalUpdateTime(normalUpdateTime);
                articleVO.setCreateTimeAgoStr(createTimeAgo);
                articleVO.setUpdateTimeAgoStr(updateTimeAgo);
                /**
                 * 查询量 太大,流量大,而且 用户 只是在 查询而已,不需要评论 和 内容
                 */
                articleVO.setContent(null);
                artileVOList.add(articleVO);
            }
    
            return artileVOList;
        }
    
        public boolean queryArticleTagIsExist(Articles2tags articles2tags) {
            List<Articles2tags> result = basicService.articles2tagsMapper.select(articles2tags);
    
            return result.size() == 0 ? false : true;
        }
    
    
        @Override
        @Transactional(propagation = Propagation.REQUIRED)
        public boolean save(Article article) {
    
            String articleId = basicService.sid.nextShort();
            article.setId(articleId);
            article.setCreateTime(new Date());
            article.setUpdateTime(new Date());
            article.setReadCounts(0);
            article.setCommentCounts(0);
            article.setReceiveLikeCounts(0);
    
            Article result = basicService.articleRepository.save(article);
    
            return result == null ? false : true;
        }
    
        @Override
        @Transactional(propagation = Propagation.REQUIRED)
        public boolean saveWithIdAndUserId(Article article) {
    
            Article article1 = new Article();
            article1.setId(article.getId());
    
            Example<Article> articleExample = Example.of(article1);
    
            Optional<Article> one = basicService.articleRepository.findOne(articleExample);
            Article oldArticle = one.isPresent() ? one.get() : null;
    
            article.setCreateTime(oldArticle.getCreateTime());
            article.setReadCounts(oldArticle.getReadCounts());
            article.setReceiveLikeCounts(oldArticle.getReceiveLikeCounts());
            article.setCommentCounts(oldArticle.getCommentCounts());
            article.setUpdateTime(new Date());
            Article result = basicService.articleRepository.save(article);
    
            return result == null ? false : true;
        }
    
    
        private Page<Article> readAndExcute(String metcherProperty, ExampleMatcher matching, Article article, Integer page, Integer pageSize) {
            ExampleMatcher exampleMatcher = matching.withMatcher(metcherProperty, ExampleMatcher.GenericPropertyMatchers.contains());
            Example<Article> articleExample = Example.of(article, exampleMatcher);
            Pageable pageable = new PageRequest(page, pageSize);
            return basicService.articleRepository.findAll(articleExample, pageable);
        }
    
    
    }
    
    • TagServiceImpl实现
    package cn.fyupeng.service.impl;
    
    import cn.fyupeng.pojo.Article;
    import cn.fyupeng.pojo.Articles2tags;
    import cn.fyupeng.pojo.Classfication;
    import cn.fyupeng.pojo.Tag;
    import cn.fyupeng.utils.TimeAgoUtils;
    import cn.fyupeng.mapper.ArticleRepository;
    import cn.fyupeng.mapper.Articles2tagsMapper;
    import cn.fyupeng.mapper.ClassficationMapper;
    import cn.fyupeng.mapper.TagMapper;
    import cn.fyupeng.pojo.vo.Articles2tagsVO;
    import cn.fyupeng.pojo.vo.TagVO;
    import cn.fyupeng.service.TagService;
    import cn.fyupeng.anotion.Service;
    import org.n3r.idworker.Sid;
    import org.springframework.beans.BeanUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    import org.springframework.transaction.annotation.Propagation;
    import org.springframework.transaction.annotation.Transactional;
    import tk.mybatis.mapper.entity.Example;
    
    import javax.annotation.PostConstruct;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Optional;
    
    /**
     * @Auther: fyp
     * @Date: 2022/4/8
     * @Description:
     * @Package: com.crop.service.impl
     * @Version: 1.0
     */
    @SuppressWarnings("all")
    @Component
    @Service
    public class TagServiceImpl implements TagService {
    
        private static TagServiceImpl basicService;
    
        @Autowired
        private TagMapper tagMapper;
    
        @Autowired
        private Articles2tagsMapper articles2tagsMapper;
    
        @Autowired
        private ArticleRepository articleRepository;
    
        @Autowired
        private ClassficationMapper classficationMapper;
    
        @Autowired
        private Sid sid;
    
        @PostConstruct
        public void init() {
            this.basicService = this;
        }
    
        @Override
        @Transactional(propagation = Propagation.SUPPORTS)
        public boolean queryTagIsExist(Tag tag) {
    
            Tag result = basicService.tagMapper.selectOne(tag);
    
            return result == null ? false : true;
        }
    
        @Override
        @Transactional(propagation = Propagation.SUPPORTS)
        public boolean queryArticleTagIsExist(String id) {
    
            Articles2tags result = basicService.articles2tagsMapper.selectByPrimaryKey(id);
    
            return result == null ? false : true;
        }
    
        @Override
        public boolean queryArticleTagIsExist(Articles2tags articles2tags) {
    
            List<Articles2tags> result = basicService.articles2tagsMapper.select(articles2tags);
    
            return result.size() == 0 ? false : true;
        }
    
        @Override
        @Transactional(propagation = Propagation.SUPPORTS)
        public Tag queryTag(String tagId) {
    
            Tag tag = basicService.tagMapper.selectByPrimaryKey(tagId);
    
            return tag;
        }
    
        @Override
        @Transactional(propagation = Propagation.SUPPORTS)
        public List<Articles2tagsVO> queryArticleTag(Articles2tags articles2tags) {
    
            List<Articles2tags> articles2tagsList = basicService.articles2tagsMapper.select(articles2tags);
    
            for (Articles2tags tags : articles2tagsList) {
                System.out.println(tags);
            }
    
            List<Articles2tagsVO> articles2tagsVOList = new ArrayList<>();
            for (Articles2tags articleTags : articles2tagsList) {
    
                String articleId = articleTags.getArticleId();
                String tagId = articleTags.getTagId();
    
                Tag tag = basicService.tagMapper.selectByPrimaryKey(tagId);
    
                Article article = new Article();
                article.setId(articleId);
    
                org.springframework.data.domain.Example<Article> articleExample = org.springframework.data.domain.Example.of(article);
    
    
                Optional<Article> articleOptional = basicService.articleRepository.findOne(articleExample);
                Article one = articleOptional.isPresent() ? articleOptional.get() : null;
    
                if (one != null) {
    
                    Classfication classfication = basicService.classficationMapper.selectByPrimaryKey(one.getClassId());
    
                    Articles2tagsVO articles2tagsVO = new Articles2tagsVO();
                    BeanUtils.copyProperties(articleTags, articles2tagsVO);
    
                    articles2tagsVO.setTagName(tag.getName());
                    articles2tagsVO.setTitle(one.getTitle());
                    articles2tagsVO.setClassficationName(classfication.getName());
                    articles2tagsVO.setCommentCounts(one.getCommentCounts());
                    articles2tagsVO.setReadCounts(one.getReadCounts());
                    articles2tagsVO.setReceiveLikeCounts(one.getReceiveLikeCounts());
    
                    String createTimeAgo = TimeAgoUtils.format(one.getCreateTime());
                    String updateTimaAgo = TimeAgoUtils.format(one.getUpdateTime());
    
                    articles2tagsVO.setCreateTimeAgoStr(createTimeAgo);
                    articles2tagsVO.setUpdateTimeAgoStr(updateTimaAgo);
    
                    articles2tagsVOList.add(articles2tagsVO);
                }
            }
    
            return articles2tagsVOList;
        }
    
        @Override
        @Transactional(propagation = Propagation.SUPPORTS)
        public List<TagVO> queryAllTags(Tag tag) {
    
            List<Tag> select = basicService.tagMapper.select(tag);
    
            List<TagVO> tagVOList = new ArrayList<>();
            for (Tag one : select) {
                String tagId = one.getId();
    
                Articles2tags articles2tags = new Articles2tags();
                articles2tags.setTagId(tagId);
                List<Articles2tags> articles2tagsList = basicService.articles2tagsMapper.select(articles2tags);
    
                TagVO tagVO = new TagVO();
    
                BeanUtils.copyProperties(one, tagVO);
    
                tagVO.setArticleNum(articles2tagsList.size());
    
                tagVOList.add(tagVO);
            }
    
            return tagVOList;
        }
    
        @Override
        @Transactional(propagation = Propagation.REQUIRED)
        public boolean saveTag(Tag tag) {
    
            String tagId = basicService.sid.nextShort();
            tag.setId(tagId);
    
            int i = basicService.tagMapper.insert(tag);
    
            return i > 0 ? true : false;
        }
    
        @Override
        @Transactional(propagation = Propagation.REQUIRED)
        public boolean saveArticleTag(Articles2tags articles2tags) {
    
            String articles2tagsId = basicService.sid.nextShort();
            articles2tags.setId(articles2tagsId);
    
            int i = basicService.articles2tagsMapper.insert(articles2tags);
    
            return i > 0 ? true : false;
        }
    
        @Override
        @Transactional(propagation = Propagation.REQUIRED)
        public boolean updateArticleTag(Articles2tags articles2tags) {
    
            int i = basicService.articles2tagsMapper.updateByPrimaryKey(articles2tags);
    
            return i > 0 ? true : false;
        }
    
        @Override
        @Transactional(propagation = Propagation.REQUIRED)
        public boolean deleteTagAndArticleTagWithArticleId(String articleId) {
            Example example = new Example(Articles2tags.class);
    
            Example.Criteria criteria = example.createCriteria();
            criteria.andEqualTo("articleId", articleId);
    
            int i = basicService.articles2tagsMapper.deleteByExample(example);
    
            return i > 0 ? true : false;
        }
    
        @Override
        @Transactional(propagation = Propagation.REQUIRED)
        public boolean updateTag(Tag tag) {
    
            int i = basicService.tagMapper.updateByPrimaryKeySelective(tag);
    
            return i > 0 ? true : false;
        }
    
        @Override
        @Transactional(propagation = Propagation.REQUIRED)
        public boolean deleteTag(String tagId) {
    
            int i = basicService.tagMapper.deleteByPrimaryKey(tagId);
    
            return i > 0 ? true : false;
        }
    
        @Override
        @Transactional(propagation = Propagation.REQUIRED)
        public void delArticleTag(String tagId) {
    
            Example articles2tagsExample = new Example(Articles2tags.class);
            Example.Criteria criteria = articles2tagsExample.createCriteria();
            criteria.andEqualTo("tagId", tagId);
    
            int i = basicService.articles2tagsMapper.deleteByExample(articles2tagsExample);
    
        }
    
        @Override
        @Transactional(propagation = Propagation.REQUIRED)
        public boolean deleteTagAndArticleTagWithTagId(String tagId) {
            boolean result = deleteTag(tagId);
            if (result)
                delArticleTag(tagId);
            return result;
        }
    
    }
    
    • CommentServiceImpl实现
    package cn.fyupeng.service.impl;
    
    import cn.fyupeng.anotion.Service;
    import cn.fyupeng.mapper.CommentRepository;
    import cn.fyupeng.mapper.UserInfoMapper;
    import cn.fyupeng.pojo.Article;
    import cn.fyupeng.pojo.Comment;
    import cn.fyupeng.pojo.UserInfo;
    import cn.fyupeng.service.CommentService;
    import cn.fyupeng.pojo.vo.CommentVO;
    import cn.fyupeng.enums.CommentStatus;
    import cn.fyupeng.utils.PagedResult;
    import cn.fyupeng.utils.TimeAgoUtils;
    import org.apache.commons.lang3.StringUtils;
    import org.n3r.idworker.Sid;
    import org.springframework.beans.BeanUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.domain.*;
    import org.springframework.data.mongodb.core.MongoTemplate;
    import org.springframework.data.mongodb.core.query.Criteria;
    import org.springframework.data.mongodb.core.query.Query;
    import org.springframework.stereotype.Component;
    import org.springframework.transaction.annotation.Propagation;
    import org.springframework.transaction.annotation.Transactional;
    
    import javax.annotation.PostConstruct;
    import java.text.SimpleDateFormat;
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.List;
    import java.util.Optional;
    
    /**
     * @Auther: fyp
     * @Date: 2022/4/3
     * @Description:
     * @Package: com.crop.service.impl
     * @Version: 1.0
     */
    @SuppressWarnings("all")
    @Component
    @Service
    public class CommentServiceImpl implements CommentService {
    
        private static CommentServiceImpl basicService;
    
        @Autowired
        private CommentRepository commentRepository;
    
        @Autowired
        private UserInfoMapper userInfoMapper;
    
        @Autowired
        private MongoTemplate mongoTemplate;
    
        @Autowired
        private Sid sid;
    
        @PostConstruct
        public void init() {
            this.basicService = this;
        }
    
        @Override
        @Transactional(propagation = Propagation.SUPPORTS)
        public boolean queryCommentIsExist(String commentId) {
    
            Comment comment = new Comment();
            comment.setId(commentId);
    
            Example<Comment> commentExample = Example.of(comment);
    
            Optional<Comment> one = basicService.commentRepository.findOne(commentExample);
    
            return one.isPresent() ? true : false;
        }
    
        @Override
        @Transactional(propagation = Propagation.SUPPORTS)
        public Comment queryComment(String commentId) {
    
            Comment comment = new Comment();
            comment.setId(commentId);
    
            Example<Comment> commentExample = Example.of(comment);
    
            Optional<Comment> one = basicService.commentRepository.findOne(commentExample);
    
            return one.isPresent() ? one.get() : null;
        }
    
        @Override
        @Transactional(propagation = Propagation.SUPPORTS)
        public PagedResult queryAllComments(String articleId, Integer page, Integer pageSize, Integer sortNum) {
    
            //分页查询对象
            if(page <= 0){
                page = 1;
            }
            // page 分页 在 mongodb 中是 从 0 开始的
            page = page - 1;
    
            if(pageSize <= 0){
                pageSize = 10;
            }
    
            ExampleMatcher matching = ExampleMatcher.matching();
    
            ExampleMatcher articleExampleMatcher = matching
                    .withMatcher("articleId", ExampleMatcher.GenericPropertyMatchers.exact())
                    .withMatcher("status", ExampleMatcher.GenericPropertyMatchers.exact());
    
            Comment comment = new Comment();
            comment.setArticleId(articleId);
            comment.setStatus(CommentStatus.NORMAL.getStatus());
    
            Example<Comment> articleExample = Example.of(comment, articleExampleMatcher);
    
            //mongodb数据中默认是 按时间正序排序(顺着时间走向排序、升序)
            Pageable pageable = new PageRequest(page, pageSize);
    
            if (sortNum == 2) {
                Sort sort = new Sort(Sort.Direction.DESC, "createTime");
                pageable = new PageRequest(page, pageSize, sort);
            }
    
    
            Page<Comment> all = basicService.commentRepository.findAll(articleExample, pageable);
    
            int pages = all.getTotalPages();
            long total = all.getTotalElements();
            List<Comment> content = all.getContent();
    
            List<CommentVO> commentVOList = new ArrayList<>();
            // po -> vo 永久层对象 - 视图层对象
            forCopyComment(content, commentVOList);
    
    
            PagedResult pagedResult = new PagedResult();
            // 页数
            pagedResult.setTotal(pages);
            // 当前页
            pagedResult.setPage(page);
            // 总记录数
            pagedResult.setRecords(total);
            // 内容列表
            pagedResult.setRows(commentVOList);
    
            return pagedResult;
        }
    
        @Override
        @Transactional(propagation = Propagation.SUPPORTS)
        public boolean queryCommentWithFatherCommentIsExist(String commentId) {
    
            ExampleMatcher matching = ExampleMatcher.matching();
            ExampleMatcher exampleMatcher = matching
                    .withMatcher("fatherCommentId", ExampleMatcher.GenericPropertyMatchers.exact());
    
    
            Comment comment = new Comment();
            comment.setFatherCommentId(commentId);
    
            Example<Comment> commentExample = Example.of(comment, exampleMatcher);
    
            Optional<Comment> one = basicService.commentRepository.findOne(commentExample);
    
            return one.isPresent() ? true : false;
        }
    
        @Override
        @Transactional(propagation = Propagation.REQUIRED)
        public boolean saveComment(Comment comment) {
    
            String commentId = basicService.sid.nextShort();
            comment.setId(commentId);
            comment.setCreateTime(new Date());
            comment.setStatus(CommentStatus.NORMAL.getStatus());
    
            Comment result = basicService.commentRepository.save(comment);
    
            return result == null ? false : true;
        }
    
        @Override
        @Transactional(propagation = Propagation.REQUIRED)
        public boolean updateComment(Comment comment) {
    
            comment.setStatus(CommentStatus.NORMAL.getStatus());
    
            Comment result = basicService.commentRepository.save(comment);
    
            return result == null ? false : true;
        }
    
        @Override
        @Transactional(propagation = Propagation.REQUIRED)
        public void removeCommentById(String commentId) {
    
            Comment comment = new Comment();
            comment.setId(commentId);
    
            basicService.commentRepository.delete(comment);
    
        }
    
        @Override
        @Transactional(propagation = Propagation.REQUIRED)
        public void removeCommentWithFatherCommentId(String fatherCommentId) {
    
            Comment comment = new Comment();
            comment.setFatherCommentId(fatherCommentId);
    
            basicService.commentRepository.delete(comment);
        }
    
        @Override
        @Transactional(propagation = Propagation.SUPPORTS)
        public List<CommentVO> queryAllComments(String aPattern, String cPattern, String userId, Date startDate, Date endDate) {
    
            if (StringUtils.isBlank(aPattern)) {
                aPattern = "";
            }
            Article article = new Article();
            article.setTitle(aPattern);
            article.setSummary(aPattern);
    
            ExampleMatcher articleMatcher = ExampleMatcher.matching()
                    .withMatcher("title", ExampleMatcher.GenericPropertyMatchers.contains())
                    .withMatcher("summary", ExampleMatcher.GenericPropertyMatchers.contains());
    
            Example<Article> articleExample = Example.of(article, articleMatcher);
    
            if (StringUtils.isBlank(cPattern)) {
                cPattern = "";
            }
            Comment comment = new Comment();
            comment.setComment(cPattern);
    
            ExampleMatcher commentMatcher = ExampleMatcher.matching()
                    .withMatcher("comment", ExampleMatcher.GenericPropertyMatchers.contains());
    
            Example<Comment> commentExample = Example.of(comment, commentMatcher);
    
            // 不去匹配cPattern, 做时间 跨度 过滤
            Query queryAllArticle = new Query();
            // 不去 查询文章 时间
            //queryAllArticle.addCriteria(Criteria.where("createTime").gt(startDate).lt(endDate));
    
            List<Comment> resultCommentList = new ArrayList<>();
    
            if (StringUtils.isNotBlank(aPattern) && StringUtils.isNotBlank(cPattern)) {
                queryAllArticle.addCriteria(new Criteria().alike(articleExample));
    
                List<Article> articleAllList = basicService.mongoTemplate.find(queryAllArticle, Article.class);
                for (Article ac : articleAllList) {
                    Query queryAllComment = new Query();
                    prepareQuery(queryAllComment, startDate, endDate);
                    queryAllComment.addCriteria(Criteria.where("articleId").is(ac.getId()));
                    if (userId != null)
                        queryAllComment.addCriteria(Criteria.where("fromUserId").is(userId));
    
                    queryAllComment.addCriteria(new Criteria().alike(commentExample));
    
                    List<Comment> comments = basicService.mongoTemplate.find(queryAllComment, Comment.class);
    
                    resultCommentList.addAll(comments);
                }
            } else {
                if (StringUtils.isBlank(cPattern)) {
                    queryAllArticle.addCriteria(new Criteria().alike(articleExample));
    
                    List<Article> articleAllList = basicService.mongoTemplate.find(queryAllArticle, Article.class);
                    for (Article ac : articleAllList) {
                        Query queryAllComment = new Query();
                        prepareQuery(queryAllComment, startDate, endDate);
                        queryAllComment.addCriteria(Criteria.where("articleId").is(ac.getId()));
                        if (userId != null)
                            queryAllComment.addCriteria(Criteria.where("fromUserId").is(userId));
    
                        List<Comment> comments = basicService.mongoTemplate.find(queryAllComment, Comment.class);
    
                        resultCommentList.addAll(comments);
                    }
                }
                if (StringUtils.isBlank(aPattern)) {
                    Query queryAllComment = new Query();
                    prepareQuery(queryAllComment, startDate, endDate);
                    queryAllComment.addCriteria(new Criteria().alike(commentExample));
                    if (userId != null)
                        queryAllComment.addCriteria(Criteria.where("fromUserId").is(userId));
    
                    List<Comment> comments = basicService.mongoTemplate.find(queryAllComment, Comment.class);
    
                    resultCommentList.addAll(comments);
                }
            }
    
            List<CommentVO> commentVOList = new ArrayList<>();
            forCopyComment(resultCommentList, commentVOList);
    
            return commentVOList;
        }
    
        @Override
        @Transactional(propagation = Propagation.REQUIRED)
        public void setCommentStatusWithFatherId(Comment comment, CommentStatus commentStatus) {
            // 本评论
            comment.setStatus(commentStatus.getStatus());
            basicService.commentRepository.save(comment);
    
            String fatherCommentId = comment.getId();
            Comment childComment = new Comment();
            childComment.setFatherCommentId(fatherCommentId);
    
            ExampleMatcher commentMatcher = ExampleMatcher.matching();
            ExampleMatcher commentExampleMatcher = commentMatcher.withMatcher("fatherCommentId", ExampleMatcher.GenericPropertyMatchers.exact());
    
            Example<Comment> commentExample = Example.of(childComment, commentExampleMatcher);
    
            // 子评论
            List<Comment> childCommentList = basicService.commentRepository.findAll(commentExample);
            for (Comment ct : childCommentList) {
                ct.setStatus(commentStatus.getStatus());
                basicService.commentRepository.save(ct);
            }
        }
    
    
        private void forCopyComment(List<Comment> commentList, List<CommentVO> commentVOList) {
            for (Comment ct : commentList) {
                CommentVO commentVO = new CommentVO();
                BeanUtils.copyProperties(ct, commentVO);
    
                // fromUser
                String fromUserId = ct.getFromUserId();
                UserInfo userInfoWithFromUserId = new UserInfo();
                userInfoWithFromUserId.setUserId(fromUserId);
                UserInfo fromUserInfo = basicService.userInfoMapper.selectOne(userInfoWithFromUserId);
                commentVO.setFromUserNickName(fromUserInfo.getNickname());
                commentVO.setFromUserAvatar(fromUserInfo.getAvatar());
                // fatherCommentContent
                String fatherCommentId = ct.getFatherCommentId();
                if (fatherCommentId != null) {
                    Comment comment = new Comment();
                    comment.setId(fatherCommentId);
    
                    Example<Comment> commentExample = Example.of(comment);
    
                    Optional<Comment> one = basicService.commentRepository.findOne(commentExample);
                    if (one.isPresent()) {
                        commentVO.setFatherCommentContent(one.get().getComment());
                    }
                }
                // toUser
                String toUserId = ct.getToUserId();
                if (toUserId != null) {
                    UserInfo userInfoWithToUserId = new UserInfo();
                    userInfoWithToUserId.setUserId(toUserId);
                    UserInfo toUserInfo = basicService.userInfoMapper.selectOne(userInfoWithToUserId);
                    commentVO.setToUserNickName(toUserInfo == null ? null : toUserInfo.getNickname());
                }
    
                //time
                String createTimeAgo = TimeAgoUtils.format(ct.getCreateTime());
                commentVO.setCreateTimeAgo(createTimeAgo);
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                String normalCreateTime = sdf.format(ct.getCreateTime());
                commentVO.setNormalCreateTime(normalCreateTime);
    
                // 防止 被恶意使用
                commentVO.setToUserId(null);
                commentVOList.add(commentVO);
            }
        }
    
        private void prepareQuery(Query query, Date startDate, Date endDate) {
            query.addCriteria(Criteria.where("createTime").gt(startDate).lt(endDate));
            /**
             * 管理员应该 获取所有状态的 评论
             */
            //query.addCriteria(Criteria.where("status").is(CommentStatus.NORMAL.getStatus()));
            Sort sort = new Sort(Sort.Direction.DESC, "createTime");
            query.with(sort);
        }
    
    
    }
    
    • ClassficationServiceImpl实现
    package cn.fyupeng.service.impl;
    
    import cn.fyupeng.mapper.ClassficationMapper;
    import cn.fyupeng.pojo.Classfication;
    import cn.fyupeng.service.ClassficationService;
    import cn.fyupeng.anotion.Service;
    import org.n3r.idworker.Sid;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    import org.springframework.transaction.annotation.Propagation;
    import org.springframework.transaction.annotation.Transactional;
    import tk.mybatis.mapper.entity.Example;
    import tk.mybatis.mapper.entity.Example.Criteria;
    
    import javax.annotation.PostConstruct;
    import java.util.List;
    
    /**
     * @Auther: fyp
     * @Date: 2022/4/3
     * @Description:
     * @Package: com.crop.service.impl
     * @Version: 1.0
     */
    @SuppressWarnings("all")
    @Component
    @Service
    public class ClassficationServiceImpl implements ClassficationService {
    
        private static ClassficationServiceImpl basicService;
    
        @Autowired
        private ClassficationMapper classficationMapper;
    
        @Autowired
        private Sid sid;
    
        @PostConstruct
        public void init() {
            this.basicService = this;
        }
    
        @Override
        @Transactional(propagation = Propagation.SUPPORTS)
        public boolean queryClassficationIdIsExist(String classId) {
    
            Classfication classfication = basicService.classficationMapper.selectByPrimaryKey(classId);
    
            return classfication == null ? false : true;
        }
    
        /**
         * 当前没有事务,以 无事务方式 执行,有 事务,多个查询线程 使用同一个 事务
         * @param classfication
         * @return
         */
        @Override
        @Transactional(propagation = Propagation.SUPPORTS)
        public Classfication queryClassfication(Classfication classfication) {
    
            List<Classfication> result = basicService.classficationMapper.select(classfication);
    
            return (result == null || result.size() == 0) ? null : result.get(0);
        }
    
        @Override
        @Transactional(propagation = Propagation.SUPPORTS)
        public List<Classfication> queryAllClassfications() {
    
            Example classficationExample = new Example(Classfication.class);
            Criteria criteria = classficationExample.createCriteria();
    
            List<Classfication> result = basicService.classficationMapper.selectAll();
    
    
            return result;
        }
    
    
        /**
         * 当前没有其他事务,新建事务,这样该方法 调用多次 实际上是 多个事务,体现原子性
         * @param classfication
         */
        @Override
        @Transactional(propagation = Propagation.REQUIRED)
        public boolean saveClassfication(Classfication classfication) {
    
            String classficationId = basicService.sid.nextShort();
    
            classfication.setId(classficationId);
    
            int i = basicService.classficationMapper.insert(classfication);
    
            return i > 0 ? true : false;
        }
    
        @Override
        @Transactional(propagation = Propagation.REQUIRED)
        public boolean updateClassfication(Classfication clssfication) {
    
            int i = basicService.classficationMapper.updateByPrimaryKeySelective(clssfication);
    
            return i > 0 ? true : false;
        }
    
        @Override
        @Transactional(propagation = Propagation.REQUIRED)
        public boolean deleteClassfication(String classficationId) {
    
            int i = basicService.classficationMapper.deleteByPrimaryKey(classficationId);
    
            return i > 0 ? true : false;
        }
    
    }
    

    这样真实服务的五个具体服务实现了,接下来就是要将它们部署到服务器,怎么部署呢?

    在第一天的时候就给了大家的脚本文件,可以用它来快速启动和关闭。

    首先必装JDK

    • 第一种,Oracle官方下载,需要先登录,再获取下载链接

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FqN3dIiD-1663662505781)(C:\Users\fyp01\AppData\Roaming\Typora\typora-user-images\image-20220905213433073.png)]

    由于Oracle这里设置了得验证登录,所以没法使用wget方式直接拉取下载,得先下载到本地再使用xftp拉取到服务器中

    • 第二种,Open JDK下载

    先到OpenJDK官网:https://jdk.java.net/18/,选择不是Arch版本的tar.gz软件包,右键复制链接
    image-20220905213433073

    直接在linux上存放软件压缩包的地方,我存在/opt/software/上,通过以下命名拉取

    wget https://download.java.net/java/GA/jdk18.0.2.1/db379da656dc47308e138f21b33976fa/1/GPL/openjdk-18.0.2.1_linux-x64_bin.tar.gz
    

    拉取完成后,通过以下命令完成解压

    tar -xf openjdk-18.0.2.1_linux-x64_bin.tar.gz
    

    在移动到合适位置,我一般移动到/usr/local/目录中

    mv jdk18.0.2.1 /usr/local/
    

    接着配置环境变量,我一般不改动系统原有变量,而是将环境变量生效的目录/etc/profile.d中添加一个my_env.sh文件,在里面添加变量再去生效

    # JAVA_HOME
    export JAVA_HOME=/usr/local/jdk1.8.0_341
    export PATH=$PATH:$JAVA_HOME/bin
    

    生效使用"touch"命令或“.”命令

    touch my_env.sh
    

    使用以下命令校验是否生效

    java -version
    

    其次是Nacos的下载和启动

    Nacos被注册的是哪一台服务器,即五个真实服务的机器上,因为这样注册服务在同一台机器比在其他服务上注册性能要高,服务器性能允许情况下可以这么使用。

    Nacos官网在国内访问很慢,下载Linux版本也很慢,推荐下载的时候可以在凌晨5点到9点之间,会快些。

    wget https://github.com/alibaba/nacos/releases/download/2.1.1/nacos-server-2.1.1.tar.gz
    

    拉取完毕后,解压后移动步骤跟上面一样,不再赘述

    启动是在主目录下的bin下通过以下命令

    ./start.sh -m standalone
    

    再使用jps命令查看是否已经启动,jps是对java进程的查询

    [root@localhost bin]# jps
    1840896 Jps
    1840881 nacos-server.jar
    

    启动项目的话,我是将项目放到了下面目录中

    [root@localhost jarList]# ls
    blog-article-server        blog-comment-server  blog-user-server  status.sh
    blog-classfication-server  blog-tag-server      start.sh          stop.sh
    [root@localhost jarList]# pwd
    /usr/local/jarList
    [root@localhost jarList]# cd blog-user-server/
    [root@localhost blog-user-server]# ls
    config  fyupeng-blog-user-server.jar  logs
    [root@localhost blog-user-server]# ls config/
    application.properties  resource.properties
    

    记住每个服务启动前,配置的端口号不能相同,并且如果是在云服务器上,要保证端口开放而且防火墙没有限制该端口(或者关闭防火墙)。

    centos6.5及之前:

    [root@localhost]# service iptable status
    

    centos7.0及以上:

    [root@localhost]# systemctl status firewalld.service
    

    服务启动完毕后,当然就是部署完毕了,可以试着上线,如果不配置域名直接访问也是可以的,配置域名需要到云服务器所在服务提供商按照官方配置域名流程,一般为1个礼拜即可下来。

    各位伙伴也陪伴了我一个礼拜了,相信你们这个项目不仅可以拿下,而且在任何时候都能拿得出手,因为涉及到分布式,如果面试介绍项目时,大概率会面临一致性的问题,该项目没有涉及到分布式事务的设计,所以大家加油吧,剩下的交给各位了!

    分布式事务可以考虑消息队列去同步事务,可以考虑轻量级的RabbitMQ,它以易上手易使用而闻名。

  • 相关阅读:
    【Unity3D】GUI控件
    Maven打Jar包,启动报NoClassDefFoundError错误
    Spark:性能调优实战
    Python正则表达式
    详解Unity中的Nav Mesh新特性|导航寻路系统 (二)
    uinapp微信小程序隐私政策授权
    图像运算和图像增强三
    树的相关知识的注意事项
    隐式转换导致索引失效的原因
    常德市2022年成人高考疫情防控的重要提醒
  • 原文地址:https://blog.csdn.net/F15217283411/article/details/126956098