仿牛客网项目(帖子项目)

项目介绍:使用技术springboot+thymeleaf+redis+kafka+elasticsearch+git

前期总结:

目录

工具类介绍

1.Page

2.发送邮件MailClient

配置参数

3.HostHolder

一、首页模块

前端代码(帖子列表)

前端代码(分页)

 二、注册模块

UserService

三、登录模块

LoginController(生成验证码部分)

UserService(退出登录)

四、显示登录信息

 五、账号设置(主要的就是上传头像)

 六、检查登录状态

LoginRequired(是否登录的意思)

LoginRequiredInterceptor

 七、发布帖子

index.js

八、帖子详情页面

DiscussPostController(帖子详情部分)


工具类介绍

1.Page

package com.nowcoder.community.entity;

/**
 * 封装分页相关的信息.
 */
public class Page {

    // 当前页码
    private int current = 1;
    // 显示上限
    private int limit = 10;
    // 数据总数(用于计算总页数)
    private int rows;
    // 查询路径(用于复用分页链接)
    private String path;

    public int getCurrent() {
        return current;
    }

    public void setCurrent(int current) {
        if (current >= 1) {
            this.current = current;
        }
    }

    public int getLimit() {
        return limit;
    }

    public void setLimit(int limit) {
        if (limit >= 1 && limit <= 100) {
            this.limit = limit;
        }
    }

    public int getRows() {
        return rows;
    }

    public void setRows(int rows) {
        if (rows >= 0) {
            this.rows = rows;
        }
    }

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }

    /**
     * 获取当前页的起始行
     *
     * @return
     */
    public int getOffset() {
        // current * limit - limit
        return (current - 1) * limit;
    }

    /**
     * 获取总页数
     *
     * @return
     */
    public int getTotal() {
        // rows / limit [+1]
        if (rows % limit == 0) {
            return rows / limit;
        } else {
            return rows / limit + 1;
        }
    }

    /**
     * 获取起始页码
     *
     * @return
     */
    public int getFrom() {
        int from = current - 2;
        return from < 1 ? 1 : from;
    }

    /**
     * 获取结束页码
     *
     * @return
     */
    public int getTo() {
        int to = current + 2;
        int total = getTotal();
        return to > total ? total : to;
    }

}

总结:current代表当前页号,limit中文译为限制,也就是要限制显示几条数据,固定10条,path中定义的就是当前controller方法的映射地址,然后其他属性看注解,这个项目的分页要求显示五页也就是要求只显示五个页号 实现是通过getFrom和getTo两个方法实现,其余方法作用可以看注解。

2.发送邮件MailClient

package com.nowcoder.community.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;


@Component
public class MailClient {
    private static final Logger logger= LoggerFactory.getLogger(MailClient.class);
    @Autowired
    private JavaMailSender mailSender;
    @Value("${spring.mail.username}")
    private String from;

    /**
     *
     * @param to       接受者
     * @param subject 主题
     * @param content 内容
     */
    public void sendEmail(String to,String subject,String content) {
        try {
            MimeMessage message=mailSender.createMimeMessage();
            MimeMessageHelper helper=new MimeMessageHelper(message);
            helper.setFrom(from);
            helper.setSubject(subject);
            helper.setTo(to);
            helper.setText(content,true);//第二个参数是设置邮件内容支持html
            mailSender.send(helper.getMimeMessage());
        } catch (MessagingException e) {
            logger.error("发送邮件失败"+e.getMessage());
        }
    }

}

通过springboot发邮件主要就是对MimeMessage进行构造

配置参数

#视频写的是qq密码,这写的是授权码
spring.mail.password=xdxnosdevhtsecgf
spring.mail.protocol=smtp
mail.smtp.auth=true
spring.mail.properties.mail.smtp.ssl.enable=true

总结:依次是授权码,协议,身份验证(true代表身份验证,false代表不身份验证),是否用启用加密传送的协议验证项

3.HostHolder

package com.nowcoder.community.util;

import com.nowcoder.community.entity.User;
import org.springframework.stereotype.Component;

/**
 * 这个类用来代替session,每一个浏览器访问服务器都会创建一个线程,不能用公共类,使用threadlocal来实现线程隔离
 */
@Component
public class HostHolder {
    private ThreadLocal<User> users=new ThreadLocal<>();

    public void setUser(User user) {
        users.set(user);
    }

    public User getUser(){
        return users.get();
    }

    public void clear(){
        users.remove();
    }
}

 起到一个与session类似的作用,主要是使用了ThreadLocal本地线程

一、首页模块

代码:HomeController、DiscussPostService、UserService、LikeService、CommunityConstant、Page

模块介绍:首次编写首页模块功能为,将帖子信息从数据库查出来并返回给客户端,随后有增加点赞功能,还有一个错误跳转页面,用到了分页。

package com.nowcoder.community.controller;

import com.nowcoder.community.entity.DiscussPost;
import com.nowcoder.community.entity.Page;
import com.nowcoder.community.entity.User;
import com.nowcoder.community.service.DiscussPostService;
import com.nowcoder.community.service.LikeService;
import com.nowcoder.community.service.UserService;
import com.nowcoder.community.util.CommunityConstant;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Controller
public class HomeController implements CommunityConstant {

    @Autowired
    private DiscussPostService discussPostService;

    @Autowired
    private UserService userService;

    @Autowired
    private LikeService likeService;

    @RequestMapping(path = "/index", method = RequestMethod.GET)
    public String getIndexPage(Model model, Page page) {
        // 方法调用钱,SpringMVC会自动实例化Model和Page,并将Page注入Model.
        // 所以,在thymeleaf中可以直接访问Page对象中的数据.
        page.setRows(discussPostService.findDiscussPostRows(0));
        page.setPath("/index");

        List<DiscussPost> list = discussPostService.findDiscussPosts(0, page.getOffset(), page.getLimit());
        List<Map<String, Object>> discussPosts = new ArrayList<>();
        if (list != null) {
            for (DiscussPost post : list) {
                Map<String, Object> map = new HashMap<>();
                map.put("post", post);
                User user = userService.findUserById(post.getUserId());
                map.put("user", user);

                long likeCount = likeService.findEntityLikeCount(ENTITY_TYPE_POST, post.getId());
                map.put("likeCount", likeCount);

                discussPosts.add(map);
            }
        }
        model.addAttribute("discussPosts", discussPosts);
        return "/index";
    }

    @RequestMapping(path = "/error", method = RequestMethod.GET)
    public String getErrorPage() {
        return "/error/500";
    }

}

 总结:Page是自己定义的一个分页工具类,当把Page对象或者其他任何对象和model作为controller方法参数时,对象自动注入到model对象当中,客户端可以直接调用并使用,其中返回的list也是一个值得注意的点,之前做的项目list中封装的只是一个实体类对象,而这个项目返回的list大多封装是多个实体类,使用List<Map<String,Object>>实现,例如当前getIndexPage方法,根据这个页面可以判断当前方法要求返回帖子和当前帖子的user信息,所以当把List<DiscussPost>查出来之后还要遍历这个集合,声明一个List<Map<String,Object>>集合,遍历过程中,会根据每一个DiscussPost中的userId将对应的user信息查询出来,然后将此时的DiscussPost对象和对应的User对象存放进map集合当中然后将map放入到List<Map<String,Object>>中去,直到将List<DiscussPost>遍历完,最后将List<Map<String,Object>>注入到model中返回客户端

前端代码(帖子列表)

				<!-- 帖子列表 -->
				<ul class="list-unstyled">
					<li class="media pb-3 pt-3 mb-3 border-bottom" th:each="map:${discussPosts}">
						<a th:href="@{|/user/profile/${map.user.id}|}">
							<img th:src="${map.user.headerUrl}" class="mr-4 rounded-circle" alt="用户头像" style="width:50px;height:50px;">
						</a>
						<div class="media-body">
							<h6 class="mt-0 mb-3">
								<a th:href="@{|/discuss/detail/${map.post.id}|}" th:utext="${map.post.title}">备战春招,面试刷题跟他复习,一个月全搞定!</a>
								<span class="badge badge-secondary bg-primary" th:if="${map.post.type==1}">置顶</span>
								<span class="badge badge-secondary bg-danger" th:if="${map.post.status==1}">精华</span>
							</h6>
							<div class="text-muted font-size-12">
								<u class="mr-3" th:utext="${map.user.username}">寒江雪</u> 发布于 <b th:text="${#dates.format(map.post.createTime,'yyyy-MM-dd HH:mm:ss')}">2019-04-15 15:32:18</b>
								<ul class="d-inline float-right">
									<li class="d-inline ml-2">赞 <span th:text="${map.likeCount}">11</span></li>
									<li class="d-inline ml-2">|</li>
									<li class="d-inline ml-2">回帖 <span th:text="${map.post.commentCount}">7</span></li>
								</ul>
							</div&g
  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值