Java Web 项目学习(一) 开发社区首页

(一)DAO定义Mapper (Mybatis中的三步走)

  1. 实体类entity包下
    package com.myproject.community.entity;
    
    import java.util.Date;
    
    public class DiscussPost {
        private int id;
        private int userId;//外键
        private String title;
        private String content;
        private int type;
        private int status;
        private Date createTime;
        private int commentCount;
        private double score;
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public int getUserId() {
            return userId;
        }
    
        public void setUserId(int userId) {
            this.userId = userId;
        }
    
        public String getTitle() {
            return title;
        }
    
        public void setTitle(String title) {
            this.title = title;
        }
    
        public String getContent() {
            return content;
        }
    
        public void setContent(String content) {
            this.content = content;
        }
    
        public int getType() {
            return type;
        }
    
        public void setType(int type) {
            this.type = type;
        }
    
        public int getStatus() {
            return status;
        }
    
        public void setStatus(int status) {
            this.status = status;
        }
    
        public Date getCreateTime() {
            return createTime;
        }
    
        public void setCreateTime(Date createTime) {
            this.createTime = createTime;
        }
    
        public int getCommentCount() {
            return commentCount;
        }
    
        public void setCommentCount(int commentCount) {
            this.commentCount = commentCount;
        }
    
        public double getScore() {
            return score;
        }
    
        public void setScore(double score) {
            this.score = score;
        }
    
        @Override
        public String toString() {
            return "DiscussPost{" +
                    "id=" + id +
                    ", userId=" + userId +
                    ", title='" + title + '\'' +
                    ", content='" + content + '\'' +
                    ", type=" + type +
                    ", status=" + status +
                    ", createTime=" + createTime +
                    ", commentCount=" + commentCount +
                    ", score=" + score +
                    '}';
        }
    }
    View Code
  2. Mapper接口DAO包下
    package com.myproject.community.dao;
    
    import com.myproject.community.entity.DiscussPost;
    import org.apache.ibatis.annotations.Mapper;
    import org.apache.ibatis.annotations.Param;
    
    import java.util.List;
    
    @Mapper
    public interface DiscussPostMapper {
        //分页查询数据,查询的可能是多条信息,因此返回的是一个集合
    
        //userID针对个性化,搜索我查找的帖子,首页不会传Id,因此其实实现的是一个动态的sql
        //考虑到未来支持分页的可能性,mysql的分页十分简洁,加一个limit + 起始行行号offset  +  分页展示多少条数据limit
        List<DiscussPost> selectDiscussPosts (int userId, int offset, int limit);
    
        //为了显示页码(查询的总条数/分页展示数据的条数limit),因此定义函数查询总的数据条数。同样动态sql
        //参数之前加注解 @Param("") 起别名,如果只有一个参数,并且在<if>中使用,则必须要有别名
        // 若需要动态的拼一个条件(动态sql),且需要用的这个参数,并且方法有且只有一个参数,则必须要起别名!
        int selectDiscussPostRows(@Param("userId") int userId);
    
    
    }
    View Code
  3. 配置文件xml,resource/mapper下
    <?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.project.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">
                user_id=#{userId}
            </if>
            order by type desc ,create_time desc
            limit #{offset}, #{limit}
        </select>
    
        <select id="selectDiscussPostRows">
            select count (id)
            from  discuss_post
            where status != 2
            <if test="userId !=0">
                user_id=#{userId}
            </if>
        </select>
    </mapper>
    View Code

     

(二)Service依赖DAO   @Service  私有变量中声明对应Mapper,@Autowired  

DiscussPostService
package com.myproject.community.service;

import com.myproject.community.dao.DiscussPostMapper;
import com.myproject.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);
    }

}
View Code
UserService
package com.myproject.community.service;

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

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

    //根据用户id查询用户名
    public User findUserById(int id){
        return userMapper.selectById(id);
    }

}
View Code

 

(三)Controller依赖Service  @Controller   私有变量中声明对应Service,@Autowired (具体见Spring Ioc)

  • 注解  @RequestMapping(path = "/index",method = RequestMethod.GET) 
  • 成员函数,在函数体内,要将结果放入model中。
       public String getIndexPage(Model model){
             List <> discussPosts;
             ..............
            //将追踪的,要给页面展示的结果放到model中 model.addAttribute(起名字,对应的值)
            model.addAttribute("discussPosts",discussPosts);
            return "/index";
        }    

  先写内容

package com.myproject.community.controller;

import com.myproject.community.entity.DiscussPost;
import com.myproject.community.entity.Page;
import com.myproject.community.entity.User;
import com.myproject.community.service.DiscussPostService;
import com.myproject.community.service.UserService;
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 org.springframework.web.bind.annotation.ResponseBody;

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

@Controller
public class HomeController {
    @Autowired
    private UserService userService;
    @Autowired
    private DiscussPostService discussPostService;



    @RequestMapping(path = "/index",method = RequestMethod.GET)
    public String getIndexPage(Model model, Page page){
        List<DiscussPost> list = discussPostService.findDiscussPosts(0,0,0);
        //查到的数据只是UserId,而我们需要对应的名字,因此新建一个list,针对每一个DiscussPost,根据id查到User,组装数据
        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);
                discussPosts.add(map);
            }

        }
        //将追踪的,要给页面展示的结果放到model中 model.addAttribute(起名字,对应的值)
        model.addAttribute("discussPosts",discussPosts);
        return "/index";
    }

}
View Code

  再补写分页情况(增加Page实体,修改controller)

controller

 @RequestMapping(path = "/index",method = RequestMethod.GET)
    public String getIndexPage(Model model, Page page){
        page.setRows(discussPostService.findDiscussPostRows(0));
        page.setPath("/index");
        List<DiscussPost> list = discussPostService.findDiscussPosts(0,page.getOffset(),page.getLimit());
        //查到的数据只是UserId,而我们需要对应的名字,因此新建一个list,针对每一个DiscussPost,根据id查到User,组装数据
        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);
                discussPosts.add(map);
            }

        }
        //将追踪的,要给页面展示的结果放到model中 model.addAttribute(起名字,对应的值)
        model.addAttribute("discussPosts",discussPosts);
        //可以不用写。调用方法栈,SpringMVC会自动实例化Model和Page,并将Page注入Model
        //所以在thymeleaf中可以直接访问Page对象的数据
        //model.addAttribute("page",page)
        return "/index";
    }
View Code

Page

package com.myproject.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;
    }

    /**
     * 获取总页数
     */
    public int getTotal(){
        // row/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;
        return  to > getTotal() ? getTotal() :to;

    }


}
View Code

 

(四)找对应的html文件,进行修改。(采用thymeleaf模板)

  • 在html标签添加 <html lang="en" xmlns:th="http://www.thymeleaf.org"> 
  • 对于相对路径  <link rel="stylesheet" th:href="@{/css/global.css}" /> 告诉th模板语言,去static静态目录下找/css/global.css
  • 模板语言变量采用 ${} 表示
  • 循环  th:each="map:${discussPosts}" 
  • 条件 th:if="${map.post.type==1}" ,只有条件成立时,才会显示。map.post.type其实是通过thymeleaf调用的map.key(post)找到对应的value值post.调用post.getType()方法得到值。
  • text和utext的区别,utext可针对转移字符以常人理解的方式显示,text以转义字符的形式显示。
  • datas格式 <b th:text="${#dates.format(map.post.createTime,'yyyy-MM-dd HH:mm:ss')}"> thymeleaf自带的格式化方式。
  •  index?current=1&limit=10 动态的书写方式为 
    <a class="page-link" th:href="@{${page.path}(current=1,limit=10)}">首页</a>
  • 当既还有静态又含有动态变量时,用 |静    动 | 把他们框住,后面条件判断相等添加disabled <li th:class="|page-item ${page.current==page.total?'disabled':''}|"> 
  • thymeleaf自带 #numbers。sequence(a,b) 返回从a开始到b结束的连续的自然数。因为整体函数用 ${}表示了,所以a,b必为变量。不用加 用 ${} 。同时 i 为循环变量
     <li th:class="|page-item ${i==page.current?'active':''}|" th:each="i:${#numbers.sequence(page.from,page.to)}">  

 对应帖子的修改

<!-- 帖子列表 -->
                <ul class="list-unstyled">
                    <li class="media pb-3 pt-3 mb-3 border-bottom" th:each="map:${discussPosts}">
                        <a href="site/profile.html">
                            <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 href="#" 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">赞 11</li>
                                    <li class="d-inline ml-2">|</li>
                                    <li class="d-inline ml-2">回帖 7</li>
                                </ul>
                            </div>
                        </div>                        
                    </li>
                </ul>
View Code

效果如图: 

 

 

对应分页的修改

<!-- 分页 -->
                <!-- 没事有数据不显示 -->
                <nav class="mt-5" th:if="${page.rows>0}">
                    <ul class="pagination justify-content-center">
                        <li class="page-item">
                            <!-- index?current=1&limit=5 -->
                            <a class="page-link" th:href="@{${page.path}(current=1,limit=10)}">首页</a>
                        </li>
                        <li th:class="|page-item ${page.current==1? 'disabled': ''}|">
                            <a class="page-link" th:href="@{${page.path}(current=${page.current-1})}">上一页</a></li>
                        <li th:class="|page-item ${i==page.current?'active':''}|" th:each="i:${#numbers.sequence(page.from,page.to)}">
                        <a class="page-link" href="#" th:text="${i}">1</a>
                        </li>
                        <li th:class="|page-item ${page.current==page.total?'disabled':''}|">
                            <a class="page-link" th:href="@{${page.path}(current=${page.current+1})}">下一页</a>
                        </li>
                        <li class="page-item">
                            <a class="page-link" th:href="@{${page.path}(current=${page.total})}">末页</a>
                        </li>
                    </ul>
                </nav>
            </div>
        </div>
View Code

 效果如图:

 

各种细节

  • 帖子表包含用户主键字段,名为user_id,在查询帖子的方法上,有参数userId。要求参数不为0时,将其拼入到where子句中,用以筛选用户。下列拼写动态SQL的语法
    注意:test里面使用的是userId,而不是${userId!=0})————当时上课直接照着老师敲的。${}是模板thymeleaf的标志,用在动态的HTML中。而这是动态的xml文件,
        <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>
    </select>

 

  • 在java中与数据库连接的DAO层的Mapper,必须注解@Param("")   来起别名的情况:
    需要动态的拼一个条件(动态sql),且需要用的这个参数,并且方法有且只有一个参数,则必须要起别名! 

    • 动态sql
    • 只有一个参数,并且在<if>中使用

    针对上面的userId

    @Mapper
    public interface DiscussPostMapper {
        int selectDiscussPostRows(@Param("userId") int userId);
    }

     

  • 在XML中,参数不是java自带的,而是bean中的需要写parameterType。
    <insert id="insertUser" parameterType="User" keyProperty="id">
            insert into user (<include refid="insertFields"></include>)
            values (#{username}, #{password}, #{salt}, #{email}, #{type}, #{status}, #{activationCode}, #{headerUrl}, #{createTime})
    </insert>

     

  • 在下HTML中,为了正确格式化发布日期,应该填写 th:text=${#date.format(createTime, ‘yyyy-MM-dd HH:mm:ss’)}

 

——————————————————————————————————————————————————————————————————

链接:https://pan.baidu.com/s/1Q6JAwcraaJWpXDObYv2r6A
提取码:vmrq
复制这段内容后打开百度网盘手机App,操作更方便哦

posted @ 2021-05-22 09:42  白清欢  阅读(118)  评论(0编辑  收藏  举报