Day17:开发流程、开发社区首页、项目的调试、版本控制

开发流程

一次请求过程

image

先开发DAO,再开发service,再开发controller

开发社区首页的分布实现

显示前10个帖子

创建帖子数据表

CREATE TABLE `discuss_post` (
  `id` int NOT NULL AUTO_INCREMENT,
  `user_id` varchar(45) DEFAULT NULL,
  `title` varchar(100) DEFAULT NULL,
  `content` text,
  `type` int DEFAULT NULL COMMENT '0-普通; 1-置顶;',
  `status` int DEFAULT NULL COMMENT '0-正常; 1-精华; 2-拉黑;',
  `create_time` timestamp NULL DEFAULT NULL,
  `comment_count` int DEFAULT NULL,
  `score` double DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `index_user_id` (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=281 DEFAULT CHARSET=utf8mb3
  • AUTO_INCREMENT:自增id

开发DAO数据访问层

  1. 创建与表变量相同的实体类:
public class DiscussPost {
    private int id;
    private int userId;
    private String title;
    private String content;

    private int type;
    private int status;
    private java.util.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 +
                '}';
    }
}

(记得设置getter和setter和to_String方法。)

  1. 创建DiscussPostMapper接口:
@Mapper
public interface DiscussPostMapper {
    //userId为0时,表示查询所有用户的帖子,如果不为0,表示查询指定用户的帖子
    //offset表示起始行号,limit表示每页最多显示的行数
    List<DiscussPost> selectDiscussPosts(int userId, int offset, int limit);

    //查询帖子的行数
    //userId为0时,表示查询所有用户的帖子
    int selectDiscussPostRows(@Param("userId") int userId);
    //@param注解用于给参数取别名,拼到sql语句中,如果只有一个参数,并且在<if>标签里,则必须加别名
    
}
  1. 配置DiscussPost-Mapper.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.newcoder.community.dao.DiscussPostMapper">
    <sql id="selectFields">
        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>
  • 用标签定义反复被复用的字段;
  • resultType=“DiscussPost”,如果是自己定义的需要注明,像int之类的不需要;
  • <if test = >标签标识满足条件则把其中的sql拼上;
  1. 编写测试类对我们之前配置的mapper进行测试:
@Test
    public void testSelectPosts() {
        List<DiscussPost> list = discussPostMapper.selectDiscussPosts(149, 0, 10);
        for(DiscussPost post : list) {
            System.out.println(post);
        }

        int rows = discussPostMapper.selectDiscussPostRows(149);
        System.out.println(rows);
//        System.out.println(discussPostMapper.selectDiscussPostRows(149));
    }

开发Service业务层

  1. 创建DiscussPostService类:
@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);
    }


}

两个方法,一个找帖子列表,一个找帖子数。

  • 注意Autowared把对应的Mapper注入。
  1. 考虑我们的业务需求,最后id肯定不会呈现在界面上,因此需要通过user_id查找到名字。这里直接写进SQL里不容易封装,因此选择创建一个UserService组件对User进行操作。
@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

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

}
  • 这里的selectById是我们之前写过的一个方法,通过id查User。

开发Controller层

  1. 创建HomeController返回索引index(html文件在templates/index.html下)
@Controller
public class HomeController {
    @Autowired
    private UserService userService;

    @Autowired
    private DiscussPostService discussPostService;

    @RequestMapping(path = "/index", method = RequestMethod.GET)
    public String getIndexPage(Model model) {
        //先查前10个帖子
        List<DiscussPost> list = discussPostService.findDiscussPosts(0,0,10);
        List<Map<String, Object>> discussPosts = new ArrayList<>();
        if(list != null) {
            for (DiscussPost post : list) {
                Map<String, Object> map = new java.util.HashMap<>();
                map.put("post", post);
                map.put("user", userService.findUserById(post.getUserId()));
                discussPosts.add(map);
            }
        }
        model.addAttribute("discussPosts", discussPosts);
        return "/index";
    }
  1. 修改index.html,将其中的静态文字修改为动态的ThymeLeaf:
<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
	<link rel="icon" href="/Users/iris/items/my_maven/community/src/main/resources/static/img/error.png"/>
	<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" crossorigin="anonymous">
	<link rel="stylesheet" th:href="@{/css/global.css}" />
	<title>牛客网-首页</title>
</head>
<body>
	<div class="nk-container">
		<!-- 头部 -->
		......
		<!-- 内容 -->
		<div class="main">
                ......
				<!-- 帖子列表 -->
				<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>
	
			</div>
		</div>

		
	<script src="https://code.jquery.com/jquery-3.3.1.min.js" crossorigin="anonymous"></script>
	<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" crossorigin="anonymous"></script>
	<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" crossorigin="anonymous"></script>
	<script th:src="@{/js/global.js}"></script>
	<script th:src="@{js/index.js}"></script>
</body>
</html>

  • xmlns引入thymeleaf
  • th:each=“map:{discussPosts}” 用循环显示discussPosts中的内容。
  • utext:可以把转义字符正常显示。
  • map.user.getHeaderUrl相当于:map.get(“user”)->User->user.getHeaderUrl()

实现分页功能

明确需求:在底端实现分页效果。

  1. 创建Page实体类:
package com.newcoder.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;
    }

    //获取当前页的起始行(用于数据库查询)
    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;
        }
    }

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

    //获取终止页码
    public int getTo(){
        int from = current + 2;
        return from > getTotal() ? getTotal(): from;
    }

}

  • 这里还需要一些方法得到起始页码和终止页码。
  1. 修改HomeController:
@RequestMapping(path = "/index", method = RequestMethod.GET)
    public String getIndexPage(Model model, Page page) {
        //方法调用前,Spring会自动把page注入给model,所以html中可以直接访问page的数据。
        //先查前10个帖子
        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 java.util.HashMap<>();
                map.put("post", post);
                map.put("user", userService.findUserById(post.getUserId()));
                discussPosts.add(map);
            }
        }
        model.addAttribute("discussPosts", discussPosts);

        return "/index";
  • 在controller中给总帖子数和path赋值。
  • 然后通过discussPostService对象取DiscussPost数组
  • 遍历数组,找到post和user的hashmap
  • 添加到model中
  1. 修改index.html
<!-- 分页 -->
  <nav class="mt-5" th:if="${page.rows>0}">
      <ul class="pagination justify-content-center">
          <li class="page-item">
              <a class="page-link" th:href="@{${page.path}(current=1)}">首页</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>

(太复杂了草,我服了)

项目的调试

响应状态码

Table

Status Code

Description

中文含义

200

OK

请求成功

201

Created

已创建

204

No Content

无内容

301

Moved Permanently

永久移动

302

Found

重定向

400

Bad Request

请求错误

401

Unauthorized

未授权

403

Forbidden

禁止

404

Not Found

未找到

500

Internal Server Error

内部服务器错误

  • 重定向:服务器建议浏览器重新访问别的并给状态码302。(比如登陆和注册产生重定向)

image

断点调试-服务端

  • debug模式,浏览器访问到才会卡住。
  • F8逐行调试,F7进入内部,F9继续执行直到下一个断点
  • shift + F7跳出。

断电调试-客户端

  • 浏览器F12。
  • 前端的,后面再说

Spring日志

  • 默认工具:logback
  • 设置日志级别,并将日志输出到不同的终端。(级别从小到大)

image

  • 在application.propertities中:
# logger
logging.level.com.newcoder.community=debug
  • 指定日志存放在哪个文件:
logging.file.name=community.log
  • 实际开发:按照不同级别存放到不同的log,文件大小到一定程度时进行拆分。

使用Git进行版本控制

Git简介

# 账号配置
git config --list
git config --global user.name "lihonghe"
git config --global user.email "lihonghe@nowcoder.com"

  # 本地仓库
git init
git status -s
git add *
git commit -m '...'
# 生成秘钥
ssh-keygen -t rsa -C "lihonghe@nowcoder.com"
# 推送已有项目
git remote add origin https://git.nowcoder.com/334190970/Test.git git push -u origin master
# 克隆已有仓库
git clone https://git.nowcoder.com/334190970/Test.git

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/450917.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用Java的等待/通知机制实现一个简单的阻塞队列

Java的等待/通知机制 Java的等待通知机制是多线程间进行通信的一种方式。 有三个重要的方法&#xff1a;wait()&#xff0c;notify() 和以及notifyAll() wait()&#xff1a;该方法用于让当前线程&#xff08;即调用该方法的线程&#xff09;进入等待状态并且释放掉该对象上的…

SpringBoot中配置nacos

SpringBoot中配置nacos 在SpringBoot中使用nacos一定要注意name&#xff0c;使用openfeign特别要注意这个点。 spring:application:name: item-service需要的依赖包 config需要引入的包 <dependency><groupId>com.alibaba.cloud</groupId><artifactId…

搜索引擎:引擎霸屏推广的未来趋势解读-华媒舍

1. 引擎霸屏推广 引擎霸屏推广是一种广告推广策略&#xff0c;通过借助搜索引擎的广告服务&#xff0c;让广告展示在用户搜索关键词时的首页位置&#xff0c;以吸引潜在客户点击进入宣传页面。这种推广方式具有精准定位和较高的曝光率&#xff0c;对于产品推广和品牌塑造非常有…

IT驻场外包能提供哪些类型的服务?

随着信息技术的飞速发展&#xff0c;IT驻场外包作为一种高效的企业服务模式&#xff0c;正逐渐成为企业提升效率和削减成本的首选。这种外包形式将专业的IT人员直接派驻到客户现场&#xff0c;为企业提供全方位的技术支持和服务。本文将深入研究IT驻场外包所能提供的多种服务类…

51单片机基础篇系列-超声波测距

&#x1f308;个人主页&#xff1a;会编辑的果子君 &#x1f4ab;个人格言:“成为自己未来的主人~” HC-SR04产品特点 典型工作用电压&#xff1a;5V 超小静态工作电流&#xff1a;小于2mA 感应角度&#xff1a;不大于15度 探测距离&#xff1a;2cm-400cm 高精度&#…

新一代国产人工心脏推出,《2024心衰器械白皮书》重磅发布

2024年3月2日&#xff0c;永仁心医疗“EVA-Pulsar™新品发布会”在京举办。在国内外众多领域知名专家、投资人、企业家的共同见证下&#xff0c;永仁心最新一代EVA-Pulsar™人工心脏&#xff08;心室辅助装置&#xff09;重磅发布。 这款人工心脏集长期植入、超小体积、脉动血…

求最大公约数

本期介绍&#x1f356; 主要介绍&#xff1a;求两数的最大公约数&#xff0c;通过辗转相除法计算。 文章目录 1. 求最大公约数2. 遍历法3. 辗转相除法 1. 求最大公约数 题目&#xff1a;给定两个数&#xff0c;求这两个数的最大公约数。   最大公约数&#xff1a;指两个或多个…

MySQL--执行一条 select 语句,期间发生了什么?

执行一条 SQL 查询语句&#xff0c;期间发生了什么&#xff1f; 连接器&#xff1a;建立连接&#xff0c;管理连接、校验用户身份&#xff1b;查询缓存&#xff1a;查询语句如果命中查询缓存则直接返回&#xff0c;否则继续往下执行。MySQL 8.0 已删除该模块&#xff1b;解析 …

AI“造神运动”终结,杀死,重生

AGI回归本质&#xff0c;百亿美金创业机会涌现。 “专注AI技术迭代会让我焦虑&#xff0c;关注业务我不会焦虑&#xff0c;有些问题十年前存在十年后还在&#xff0c;我现在就明确不卷模型&#xff0c;只思考如何让产品能自我‘造血’。” 一位正卷在AI创业洪流里的硅谷创业者…

Qt对象树

对象树 1.QLabel* label new QLabal(this) 这个代码在new了之后没有释放&#xff0c;不会造成内存泄漏。 原因是这个对象是挂到了对象树上。 qt就是设计了一个n叉树&#xff0c;将各种元素组织起来了。 例如以下图 通过树形结构&#xff0c;就把界面上显示的这些控件对象…

韶音运动耳机好用吗?南卡、墨觉、韶音骨传导耳机三款全面评测

音乐是我生活中不可或缺的调味品&#xff0c;它伴随着我度过了无数个清晨的慢跑以及夜晚的悠闲散步。但是传统入耳式耳机总是让我感到不适&#xff0c;虽然它有着不错的降噪能力&#xff0c;但是很容易忽视周围环境的安全&#xff0c;而且运动的时候老容易掉。然后我遇到了骨传…

新质生产力浪潮下,RPA如何成为助力先锋?

新质生产力浪潮下&#xff0c;RPA如何成为助力先锋&#xff1f; 在数字化、智能化的今天&#xff0c;“新质生产力”一词越来越频繁地出现在我们的视野中。那么&#xff0c;究竟什么是新质生产力&#xff1f;它与我们又有什么关系&#xff1f;更重要的是&#xff0c;在这一浪潮…

【动态规划】代码随想录算法训练营第四十六天 |139.单词拆分,关于多重背包,你该了解这些! ,背包问题总结篇!(待补充)

139.单词拆分 1、题目链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 2、文章讲解&#xff1a;代码随想录 3、题目&#xff1a; 给定一个非空字符串 s 和一个包含非空单词的列表 wordDict&#xff0c;判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词…

LeetCode:206.反转链表

206. 反转链表 解题过程 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val val; }* ListNode(int val, ListNode next) { this.val val; this.next next; …

【C++】C++学习前言

C前言与发展 一.什么是C二.C的发展史三.C的重要性 一.什么是C C语言是结构化和模块化的语言&#xff0c;适合处理较小规模的程序。对于复杂的问题&#xff0c;规模较大的程序&#xff0c;需要高度的抽象和建模时&#xff0c;C语言则不合适。为了解决软件危机&#xff0c; 20世纪…

2023年中国抗DDoS市场规模现状及竞争格局,公有云抗DDoS是主要增长点

分布式拒绝服务&#xff08;DDoS&#xff09;是在DoS基础之上产生的一种新的攻击方式&#xff0c;具有多对一的攻击模式。它通过制造伪造的流量&#xff0c;使得被攻击的服务器、网络链路或是网络设备&#xff08;如防火墙、路由器等&#xff09;负载过高&#xff0c;无法处理正…

NUMA架构

UMA架构 在单cpu的时代&#xff0c;cpu与内存的交互需要通过北桥芯片来完成。cpu通过前端总线(FSB&#xff0c; front Side Bus)连接到北桥芯片&#xff0c;由北桥芯片连接到内存&#xff08;内存控制器是集成在北桥芯片里的&#xff09;。为了提升性能&#xff0c;cpu的频率不…

2024中国(京津冀)太阳能光伏推进大会暨展览会

2024年中国(京津冀)太阳能光伏推进大会暨展览会是一个旨在促进太阳能光伏产业发展的重要会议和展览会。该活动将在中国的京津冀地区举行&#xff0c;旨在汇聚全球太阳能光伏领域的专业人士、政府代表、企业家和科研人员&#xff0c;共同探讨太阳能光伏技术的最新进展和未来发展…

PWARL CTF and others

title: 一些复杂点的题目 date: 2024-03-09 16:05:24 tags: CTF 2024年3月9日 今日习题完成&#xff1a; 1.BUU [网鼎杯 2020 半决赛]AliceWebsite 2.[RoarCTF 2019]Online Proxy 3.[Polar CTF]到底给不给flag呢 4.网鼎杯 2020 总决赛]Game Exp [RoarCTF 2019]Online Proxy …

适合上班族的副业:steam游戏搬砖1天3小时,月入8K

互联网新时代&#xff0c;做副业的人越来越多。如果能充分利用下班后的时间&#xff0c;还真能赚到不少钱。steam游戏搬砖项目就是这样一个非常适合上班的副业&#xff0c;只要用心去操作&#xff0c;一个月至少收入两三千&#xff0c;多的轻松上万。 steam游戏搬砖项目其实做的…