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

news2024/11/23 11:49:14

开发流程

一次请求过程

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

社交创新的先锋:探秘Facebook背后的故事与智慧

起源与初创阶段 Facebook的故事始于2004年&#xff0c;由马克扎克伯格&#xff08;Mark Zuckerberg&#xff09;、埃迪华索伦&#xff08;Eduardo Saverin&#xff09;、安德鲁麦克卡拉姆&#xff08;Andrew McCollum&#xff09;、克里斯休斯&#xff08;Chris Hughes&#x…

Java进程CPU高负载排查

Java进程CPU高负载排查步骤_java进程cpu使用率高排查_YouluBank的博客-CSDN博客 【问题定位】使用arthas定位CPU高的问题_arthas cpu高_秋装什么的博客-CSDN博客 CPU飙升可能原因 CPU 上下文切换过多。 对于 CPU 来说&#xff0c;同一时刻下每个 CPU 核心只能运行-个线程&…

JAVA实战开源项目:生活废品回收系统(Vue+SpringBoot)

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、研究内容三、界面展示3.1 登录注册3.2 资源类型&资源品类模块3.3 回收机构模块3.4 资源求购/出售/交易单模块3.5 客服咨询模块 四、免责说明 一、摘要 1.1 项目介绍 生活废品回收系统是可持续发展的解决方案&#xff0c;旨在鼓…

最新APP开发趋势,探索2024年的创新与挑战

2024年&#xff0c;移动应用市场仍然是创新与变革的焦点。随着技术的不断发展和用户需求的不断变化&#xff0c;APP开发行业也在不断演进。本文将深入探讨2024年最新的APP开发趋势&#xff0c;以及所带来的创新与挑战&#xff0c;并介绍虎克技术公司提出的解决方案。 1. 强调用…

AIGC笔记--Maya提取和修改FBX动作文件

目录 1--Maya数据解析 2--FBX SDK导出6D数据 3--6D数据映射和Maya可视化 完整项目代码&#xff1a;Data-Processing/FBX_SDK_Maya 1--Maya数据解析 在软件Maya中直接拖入FBX文件&#xff0c;可以播放和查看人体各个骨骼关节点的数据&#xff1a; 对于上图来说&#xff0c;…

【傻瓜文档】鼎利测试软件Pilot Pioneer-① Pioneer界面介绍

Pioneer界面分布 工具栏 自定义快速访问工具栏 根据需求&#xff0c;自行制定工具栏选项 菜单栏 文件 语言 配置 工具 工具栏的补充内容&#xff0c;常用的有&#xff1a;合并/分割数据、GPS轨迹补偿等等。 帮助

亿发定制:中小型生产制造工厂为什么需要建设企业信息化管理?

随着互联网行业的迅猛发展&#xff0c;越来越多的加工制造业企业将互联网作为核心枢纽&#xff0c;这一关键核心枢纽即为企业信息化管理。 在企业信息化管理中&#xff0c;主要包括三个关键方面&#xff1a;企业变革过程管理、企业运作管理&#xff0c;以及信息技术、信息资源…

【YUNBEE云贝技术分享】如何定位postgreSQL数据库中未被使用过的索引

注: 本文为云贝教育 刘峰 原创&#xff0c;请尊重知识产权&#xff0c;转发请注明出处&#xff0c;不接受任何抄袭、演绎和未经注明出处的转载。 前言 在生产环境上&#xff0c;由于不规范的优化措施&#xff0c;数据库中可能存在大量的索引&#xff0c;并且相当一部分的索引…

jeecgboot 开放页面权限,免登录访问

前端需要配置路由和添加白名单 1、配置路由 2、 在permission.js里&#xff0c;把刚才的路由添加到白名单 3、 后端需要把该页面涉及到的接口排除权限拦截 比如我这个页面涉及到两个接口&#xff1a; 那么就在后端的excludeUrls把这两个接口加进去。 前端后端都设置好了&…

idea实现ssh远程连接服务器

1. 首先&#xff0c;打开idea&#xff0c;点击左上角File->settings 2. 点击tools->SSH Configurations->填写必要的信息&#xff0c;Host就是访问服务器的ip地址&#xff0c;Username就是服务器的用户账户&#xff0c;比如root&#xff0c;Password账户对应的密码&am…

智慧城市与绿色出行:共同迈向低碳未来

随着城市化进程的加速&#xff0c;交通拥堵、空气污染、能源消耗等问题日益凸显&#xff0c;智慧城市与绿色出行成为了解决这些问题的关键途径。智慧城市利用信息技术手段&#xff0c;实现城市各领域的智能化管理和服务&#xff0c;而绿色出行则强调低碳、环保的出行方式&#…

【Golang】golang使用三方SDK操作容器指南

【Golang】golang使用三方SDK操作容器指南 大家好 我是寸铁&#x1f44a; 总结了一篇 golang使用三方SDK操作容器✨ 喜欢的小伙伴可以点点关注 &#x1f49d; 这应该是目前全网最全golang使用三方SDK操作容器的指南了✌️ CreateConfig 主要是创建容器的配置信息&#xff0c;常…

【Java从发入门到精通】Java StringBuffer 和 StringBuilder 类

Java StringBuffer 和 StringBuilder 类 当对字符串进行修改的时候&#xff0c;需要使用 StringBuffer 和 StringBuilder 类。 和 String 类不同的是&#xff0c;StringBuffer 和 StringBuilder 类的对象能够被多次的修改&#xff0c;并且不产生新的未使用对象。 在使用 Stri…

#QT(QSpinBox,QDoubleSpinBox)

1.IDE&#xff1a;QTCreator 2.实验:实现一个计价工具&#xff0c;进制转换工具。 教程来自&#xff1a;阿西拜编程 QT C 5.9 3.记录 设置进制的第二种方法 ui->hex_tx->setDisplayIntegerBase(16); //设置显示进制为16进制 4.代码 widget.cpp #include "wi…

NOIP2018-S-DAY1-3-赛道修建(洛谷P5021)的题解

目录 题目 原题描述&#xff1a; 题目描述 输入格式 输出格式 输入输出样例 主要思路&#xff1a; check&#xff1a; 真正的code: 原题描述&#xff1a; 题目描述 C 城将要举办一系列的赛车比赛。在比赛前&#xff0c;需要在城内修建 条赛道。 C 城一共有 个路…

天梯赛的赛场安排(Python)

作者 陈越 单位 浙江大学 天梯赛使用 OMS 监考系统&#xff0c;需要将参赛队员安排到系统中的虚拟赛场里&#xff0c;并为每个赛场分配一位监考老师。每位监考老师需要联系自己赛场内队员对应的教练们&#xff0c;以便发放比赛账号。为了尽可能减少教练和监考的沟通负担&#…

打造私人云笔记,创造舒适的写作空间

搭建Minio 图片文件服务器 &#xff08;树莓派4B搭建Minio公网云服务器用nps内网穿透&#xff09;Typora 安装客户端 --> 可以利用免费gitee管理文档利用Typora 图像自定义文件上传功能 Minio强大的API功能 一、树莓派4B 64bit raspberry 操作系统 Docker Minio 图片文件…

CentOS本地部署Tale博客并结合内网穿透实现公网访问本地网站

文章目录 前言1. Tale网站搭建1.1 检查本地环境1.2 部署Tale个人博客系统1.3 启动Tale服务1.4 访问博客地址 2. Linux安装Cpolar内网穿透3. 创建Tale博客公网地址4. 使用公网地址访问Tale 前言 今天给大家带来一款基于 Java 语言的轻量级博客开源项目——Tale&#xff0c;Tale…

Python 配置信息的添加和获取

1.效果如下&#xff1a; 2.代码如下&#xff1a; from configparser import ConfigParser import threadingclass Config():_instance_lock threading.Lock()classmethoddef instance(cls, *args, **kwargs):if not hasattr(Config, "_instance"):with Config._ins…

ELK 基本操作

文章目录 1.Elasticsearch-head2.Kibana2.1.功能简介2.2.Management2.3.Discover2.4.Dev Tools 开源中间件 # Elastic Stackhttps://iothub.org.cn/docs/middleware/ https://iothub.org.cn/docs/middleware/elk/elk-use/1.Elasticsearch-head 2.Kibana 2.1.功能简介 2.2.Man…