ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

仿牛客网社区项目(一)开发首页

2022-04-28 14:33:56  阅读:355  来源: 互联网

标签:仿牛 int userId private limit 客网 import public 首页


开发社区首页

  • 开发流程
    • 1次请求的执行过程
  • 分步实现
    • 开发社区首页,显示前10个帖子
    • 开发分页组件,分页显示所有的帖子

img

我们首先开发社区首页,显示帖子,先查看一下存帖子的表,在navicat右边可以查看DDL(Data Definition Language),也就是建表语句,workbench查看的方法自行百度。根据DDL了解一下表的结构。

img

然后我们就可以进行开发,根据上图的依赖关系,我们从下往上进行,也就是entity-dao-service-controller的顺序。

实体类

首先是实体类,和上一节的操作一样,比较简单。根据数据库字段写好就行。其实有插件可以自动生成实体类和xml,但是在学习阶段,建议自己敲一遍熟悉一下。

package com.neu.langsam.community.entity;

import java.util.Date;

@Data
@ToString
public class DiscussPost {
        @TableId(value = "id",type = IdType.AUTO)
        private Integer id;
        private Integer userId;
        private String title;
        private String content;
        private int type;
        private int status;
        private Date createTime;
        private int commentCount;
        private double score;

}

DAO层

实体类写完后,写dao层接口,这里定义了两个方法,一个是查询帖子,另一个是查询帖子数量,可以用来实现后面的分页。需要注意的点在注释里写了。

然后需要写接口对应的mapper配置文件,和上一节内容差不多,有几个需要注意的点

  • namespace要修改成对应的接口
  • 使用了标签动态拼接sql语句,当满足if的条件时,拼接上if标签里的内容,这样我们就可以根据传入的userId的值,来判断是查询首页帖子还是查询我的帖子。
  • 另外使用了order by来排序,首先按照帖子类型倒序,再按照时间倒叙,这样就实现了精华帖置顶并且新帖在前的功能,后面还会实现按热度排序。
package com.neu.langsam.community.dao;

import com.neu.langsam.community.entity.DiscussPost;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

@Mapper
public interface DiscussPostMapper {

    //首页帖子实际不用传入userId,但考虑到之后需要实现我的帖子功能,这里就整合到一起,offset偏移量表示当前是第几行,limit表示每页数量

    List<DiscussPost> selectDiscussPosts(int userId,int offset,int limit);


    //动态拼接条件,方法有且只有一个条件时,需要用@Param注解给参数取别名,也可以在属性名太长的时候取别名来简化
    int selectDiscussPostRows(@Param("userId") int userId);

}
  • DiscussPostMapper-xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.neu.langsam.community.dao.DiscussPostMapper">

    <sql id="selectFields">
        id,user_id,title,content,type,status,create_time,comment_count,score
    </sql>

    <select id="selectDiscussPosts" resultType="DiscussPost">
        select <include refid="selectFields"></include>
        from discuss_post
        where status!=2
        <if test="userId!=0">
            and user_id=#{userId}
        </if>
        order by type desc,create_time desc
        limit #{offset},#{limit}
    </select>

    <select id="selectDiscussPostRows" resultType="int">
        select count(id)
        from discuss_post
        where status!=2
        <if test="userId!=0">
            and user_id=#{userId}
        </if>
    </select>

</mapper>

然后测试一下,可以看到控制台输出没问题。

img

Service层

我们这个业务比较简单,但是也必须严格遵守层次去编写,便于我们后面的一些维护和安全性的实现。这里还有另一个问题,discusspost表里有userId字段,但是我们不可能直接给用户显示id,需要显示用户名。有两种方案:

  • 写sql的时候用id再查询一下用户名拼接到一起
  • 用之前写好的查询user的方法,和我查询到的discusspost再做一个组合

看起来第二种方法更麻烦一些,但是当我们后面用到redis缓存数据库后,这样的方法就可能效率更高了。那么我们再写一个UserService提供查询用户方法。

package com.neu.langsam.community.service;

import com.neu.langsam.community.dao.DiscussPostMapper;
import com.neu.langsam.community.entity.DiscussPost;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class DiscussPostService {

    @Autowired
    private DiscussPostMapper discussPostMapper;

    public List<DiscussPost> findDiscussPosts(int userId,int offset,int limit){
        return discussPostMapper.selectDiscussPosts(userId,offset,limit);
    }

    

    public int findDiscussPostRows(int userId){
        return discussPostMapper.selectDiscussPostRows(userId);
    }

}
package com.neu.langsam.community.service;


import com.neu.langsam.community.dao.UserMapper;
import com.neu.langsam.community.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    public User findUserById(int id){
        return userMapper.selectById(id);
    }
}

导入网页

前端的网页我们使用教程模板,在我的gayhub可以找到,把template下的文件复制到项目就行。

img

Controller层

首先在controller包下新建HomeController,使用注解注入Service

	@Autowired
    private DiscussPostService discussPostService;
    @Autowired
    private UserService userService;

第一个任务

首页上显示10个帖子。这里先写固定值,后续再进行改进。前面提到的显示用户名的方式,采用第二种,利用post里的id去查询对应的user,然后用HashMap装到一起,再用list处理map。

最终我们传给模板引擎的就是一个list,list里是每个帖子对应的map,每个map里有post对象和user对象,每个对象有自己的属性和get、set方法。那么利用thymeleaf的语法,去遍历这些对象,将值赋给相应的标签就行。html已经写好了,有兴趣的可以学一学。我们启动项目,在浏览器里访问。

@RequestMapping(path = "/index",method = RequestMethod.GET)
    public String getIndexPage(Model model){
        //查询10条数据
        List<DiscussPost> list=discussPostService.findDiscussPosts(0,0,10);
        //用Map把post和user装到一起
        List<Map<String,Object>> discussPosts=new ArrayList<>();
        //遍历post,用post里的id查询user
        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);
                discussPosts.add(map);
            }
        }
        //把我们准备好的数据传给model
        model.addAttribute("discussPosts",discussPosts);
		//返回模板
        return "/index";
    }

img

第二个任务

完成第一个任务后,在这基础上完成分页的功能,我们可以自己封装一个分页类,提高代码的复用。在entity包下创建Page类。使用idea生成get和set方法,这里我们需要修改一下生成的set方法,判断一下传入的数据是否合理。比如setLimit方法,我规定limit必须大于1小于100。

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


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

另外,还需要自定义一些方法。

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

    /*
     *获取总页数
     */
    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;
    }

然后对controller进行一些改造。

@RequestMapping(path = "/index",method = RequestMethod.GET)
    public String getIndexPage(Model model, Page page){

        //方法调用之前,Spring MVC会自动实例化Model和Page,并讲Page注入Model
        //所以在thymeleaf中可以直接访问page对象中的数据
        page.setRows(discussPostService.findDiscussPostRows(0));
        page.setPath("/index");


        List<DiscussPost> list=discussPostService.findDiscussPosts(0,page.getOffset(),page.getLimit());

img

那么至此,首页完成了。

标签:仿牛,int,userId,private,limit,客网,import,public,首页
来源: https://www.cnblogs.com/nevererror/p/community.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有