第1章 初识Spring Boot,开发社区首页(下)

6. 开发社区首页

image-20220704160449355

浏览器在给服务器发送请求时,首先发送给 Controller 然后 Controller 调 Service,然后 Service 调 DAO,所以我们开发的时候建议先开发 DAO,然后开发 Service,最后开发 controller。

1. 开发DAO

社区首页需要用到的数据库表

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

image-20220704161016924

本次开发用到的类在下面图中显示

image-20220705130814494

首先需要建立一个与该表对应的实体类DiscussPost

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;              // 分数/热度
	
  	// get、set、toString方法为了以免影响阅读就没粘,实际开发时是有的
}

接下来开发DAO接口:DiscussPostMapper

@Mapper
public interface DiscussPostMapper {

    List<DiscussPost> selectDiscussPosts(int userId, int offset, int limit);      // 分页查询
    /*
    实现功能:分页查询
    参数1:userId   参数2:从第几条数据开始展示   参数3:每页展示几条数据
    这里要说一下,这个功能之一是展示首页的帖子,其实我们只需要查询所有数据然后分页就好了不需要传 userId,
    但是以后我们开发的时候有一个我的主页的功能,里面显示的都是我们自己的帖子,我们可以通过
    传 userId 展示自己发布过的所有帖子,所以为了以后开发方便,还是建议加上 userId
    具体实现展示首页帖子时 userId 传0, mapper配置文件处会进行修改,userId为0时查询所有帖子
     */

    int selectDiscussPostRows(@Param("userId") int userId);
    /*
    实现功能:查询数据库中有多少条数据
    参数1:userId
    在展示社区首页的时候,有一个页码,总共有多少页是由总数据条数和每页显示多少条数据决定的,我们可以把每页显示的
    数据条数固化下来,然后我们只需要一个方法查询一下数据库中总共有多少条数据。
    同样在查询社区首页数据时userId传入0,在mapper配置文件中处理时直接查询所有
    补充:@Param 注解用于给参数起别名,在mapper配置文件的动态sql中可以使用这个别名
         如果某个方法只有一个参数,并且在<if>里(动态sql)使用,则必须用@Param注解给这个参数起别名

     */

}
# 补充:@Param注解
这个注解是给这个参数起一个别名,在mapper配置文件中写sql时就可以用这个别名,
另外:如果mapper配置文件中需要用到动态sql并且需要用到这个参数,并且这个方法
只有一个参数,这个时候,这个参数一定要加上@Param注解起别名,否则会报错。

接下来我们要创建这个DAO接口对应的mapper配置文件: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.nowcoder.community.dao.DiscussPostMapper">

    <sql id="selectFields" >
        id, user_id, title, content, type, status, create_time, comment_count, score
    </sql>
    <select id="selectDiscussPosts" resultType="com.nowcoder.community.entity.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="Integer">
        select count(id)
        from discuss_post
        where status != 2
        <if test="userId!=0">
            and user_id = #{userId}
        </if>
    </select>

</mapper>
  • 拉黑帖子不能展示(status = 2 表示拉黑帖子)

image-20220704211725052

因为mapper配置文件中的sql很容易写错,所以开发完dao之后建议在测试类中测试一下dao接口是否开发成功。

2. 业务层

接下来开发业务层service

DiscussPostService:

@Service
public class DiscussPostService {

    @Autowired
    private DiscussPostMapper discussPostMapper;

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

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

}
我们查到的是userId,但是社区首页显示的肯定不是userId,而是user的用户名,我们可以
直接在mapper配置文件中的sql进行关联查询,也可以在得到DiscussPost后根据userId单独
地查一下user的用户名,把查到的user和DiscussPost组合到一起返回给页面。这里我们采用
第二种,虽然第二种看起来比较麻烦,但是未来使用redis缓存一些数据的时候会比较方便,性能
比较高。所以我们就需要一种方法根据userId到user,那这个方法写到DiscussPostService就
不合适了,因为是跟user有关的操作,所以我们需要新建一个service即UserService,那
UserService肯定需要用到UserDAO接口,但是这个接口已经写过了,所以我们只需要写UserService
就可以了。

UserService:

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

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

接下来将需要用到的一些静态资源、模板文件粘贴到项目中去

image-20220704225333751

3. 表现层

接下来我们来开发视图层,首先来开发视图层:

注:如果controller类上不加访问路径,那访问的时候就不需要写类的路径了,直接写方法的路径就可以了

@Controller
public class HomeController {

    @Autowired
    private DiscussPostService discussPostService;

    @Autowired
    private UserService userService;

    @RequestMapping(path = "/index", method = RequestMethod.GET)
    public String getIndexPage(Model model){
        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 HashMap<>();
                map.put("post", post);
                User user = userService.findUserById(post.getUserId());
                map.put("user", user);
                discussPosts.add(map);
            }
        }
        model.addAttribute("discussPosts", discussPosts);
        return "/index";            // 返回templates目录下的index.html
    }

}

image-20220705093836320

接下来就是修改与这个controller相关的thymeleaf模板了 index.html

# 注:将html改成themeleaf模板一定要修改第二行为
<html lang="en" xmlns:th="http://www.thymeleaf.org">

与帖子相关的themeleaf模板的部分内容

<!-- 帖子列表 -->
<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:text="${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>
# 小知识补充:
th:text     里面的内容会原样输出
th:utext    里面如果有转义字符会转义后再输出

image-20220705082952846

image-20220705083113349

image-20220705095238742

实际效果:

image-20220705095732141

接下来我们来开发一下分页组件:

分页对应的实体类:Page

public class Page {

    // 当前页码
    private int current = 1;        // 默认为1
    // 每页显示的条数
    private int limit = 10;         // 默认为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;
    }


}

另外,我们还需要将前面的HomeController中的查询方法修改一下(参数另加了分页类):

@Controller
public class HomeController {

    @Autowired
    private DiscussPostService discussPostService;

    @Autowired
    private UserService userService;

    @RequestMapping(path = "/index", method = RequestMethod.GET)
    public String getIndexPage(Model model, Page page){
        // 方法调用前,SpringMVC会自动实例化Model和Page,并将Page注入Model
        // 所以,在thymeleaf中可以直接访问Page中的数据,不需要再将Page添加到Model里面了
        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);
                discussPosts.add(map);
            }
        }
        model.addAttribute("discussPosts", discussPosts);
        return "/index";            // 返回templates目录下的index.html
    }

}

最后我们要修改index.html模板中的分页的内容

如果标签里面的内容是动态的话,一定要在标签的前面加上 th:

<!-- 分页 -->
<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" th:href="@{${page.path}(current=${i})}" 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>

image-20220705132207650

将测试,功能成功实现

下面是相关截图

image-20220705132250530

image-20220705132301999

7.项目调试技巧

image-20220705162214824

状态码

常见状态码:

image-20220705175813332

成功响应

200 OK

请求成功。成功的含义取决于 HTTP 方法:

  • GET: 资源已被提取并在消息正文中传输。
  • HEAD: 实体标头位于消息正文中。
  • PUT or POST: 描述动作结果的资源在消息体中传输。
  • TRACE: 消息正文包含服务器收到的请求消息。

另外,这里介绍一下重定向:

image-20220705180630598

比如说浏览器请求删除,然后服务器执行删除操作之后应该返回给浏览器什么界面呢,应该返回查询结果以便查看请求删除数据是否被删除,这个时候的话让服务器的 “删除” 操作去调用 “查询” 操作的话是不合适的,因为这是两个业务,之间不应该产生耦合,这个时候服务器会传给浏览器一个状态码并附加一个路径,然后浏览器通过这个路径调 “查询” 方法,服务器再去执行 “查询方法“ 然后返回结果给浏览器。这就是重定向,这种方式比起 controller之间 互相调用降低了耦合。


重定向消息

303 See Other

服务器发送此响应,以指示客户端通过一个 GET 请求在另一个 URI 中获取所请求的资源。

客户端响应

404 Not Found

服务器找不到请求的资源。在浏览器中,这意味着无法识别 URL。在 API 中,这也可能意味着端点有效,但资源本身不存在。服务器也可以发送此响应,而不是 403 Forbidden,以向未经授权的客户端隐藏资源的存在。这个响应代码可能是最广为人知的,因为它经常出现在网络上。

服务端响应

500 Internal Server Error

服务器遇到了不知道如何处理的情况。

501 Not Implemented

服务器不支持请求方法,因此无法处理。服务器需要支持的唯二方法(因此不能返回此代码)是 GET and HEAD.

502 Bad Gateway

此错误响应表明服务器作为网关需要得到一个处理这个请求的响应,但是得到一个错误的响应。

服务端调试

向下执行一行 按:F8

进入当前行所调的方法内部 按:F7

如果想要直接跳转到下一个断点 按:Alt + F9 (注:如果没有下一个断点直接执行到底)

image-20220705200954403

image-20220705201207436

客户端调试

客户端调试就是 js 调试,就是打断点调试

客户端的代码运行在浏览器上,我们想给客户端打断点应该在哪打呢

向下执行一行 F10

进入到某一个方法内部 F11

执行到下一个断点 F8

image-20220705202959111

设置日志级别

https://logback.qos.ch

image-20220705204303467

trace 、debug、info、warn、error

严重性越来越高,级别越来预高

比如启用了 info 级别,只有 info 、warn、error级别会被打印出来,trace、debug会被忽视

使用测试类

接下来用测试类使用一下日志

在配置文件里声明一下启用什么级别的日志

在 application.properties 配置文件中加上下面这句话(意思是启用 debug 级别以上的日志都打印出来)

# logger
logging.level.com.nowcoder.community=debug

image-20220706094619177

要记录日志,首先要记得实例化记录日志的接口Logger

@SpringBootTest
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = CommunityApplication.class)
public class LoggerTests {

    private static final Logger logger = LoggerFactory.getLogger(LoggerTests.class);

    @Test
    public void testLogger(){
        System.out.println(logger.getName());       // 这个只是看一下Logger的名字,并不是日志

        logger.debug("debug log");
        logger.info("info log");
        logger.warn("warn log");
        logger.error("error log");
    }
}

image-20220706092724007

# 注意
按理说 debug 级别的话 trace 级别的日志是不会输出的,但是我所执行的程序里面 debug 日志级别trace 级别
的日志却输出了,其他日志级别的倒是遵循高日志输出。

测试结果:

image-20220706094738524

将日志存到指定的文件

上面这种方式是将日志打印在控制台上,这种方式只要程序关闭日志就不会留存下来。所以为了能够长久的保存这些日志,便于对日志的分析,我们经常需要另外把日志存到指定的文件里,下面演示一下

我们只需要在 application.properties 配置文件中配置指定路径即可

logging.file.name=d:/work/data/nowcoder/community.log

image-20220706100346536

执行测试代码之后

image-20220706100442572

上面这种日志打印到文件中的方式比较简单,实际上在应用当中还会做的比这个更复杂一点。

简单的打到一个 log 文件里,这个文件可能会非常的大,而且这个文件里面会混杂着各种级别的日志,不方便我们去做分析。我们在实际开发的过程中往往是把日志按照不同的级别存到不同的文件里,这样的话如果只想分析 “错误”,就看 error.log,最好是一个文件达到一定的空间后,再拆分出另外一个文件,接下来演示一下

想达到上面的效果,我们需要写一个 log 所对应的xml文件 logback-spring.xml ,且xml文件必须是这个名字,这个文件比较复杂,用的时候直接粘到项目里,会改就行了,把 logback-spring.xml 配置文件放到 resources 根路径下(注:这个日志配置文件必须叫这个名字,且放在resources 目录下)

使用下面的配置文件配置日志就不需要在 application.properties 配置文件中配置日志了

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <contextName>community</contextName>
    <property name="LOG_PATH" value="D:/work/data"/>
    <property name="APPDIR" value="community"/>

    <!-- error file -->
    <appender name="FILE_ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_PATH}/${APPDIR}/log_error.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_PATH}/${APPDIR}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>5MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <append>true</append>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%d %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
            <charset>utf-8</charset>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>error</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- warn file -->
    <appender name="FILE_WARN" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_PATH}/${APPDIR}/log_warn.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_PATH}/${APPDIR}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>5MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <append>true</append>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%d %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
            <charset>utf-8</charset>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>warn</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- info file -->
    <appender name="FILE_INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_PATH}/${APPDIR}/log_info.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_PATH}/${APPDIR}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>5MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <append>true</append>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%d %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
            <charset>utf-8</charset>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>info</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- console -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
            <charset>utf-8</charset>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>debug</level>
        </filter>
    </appender>

    <logger name="com.nowcoder.community" level="debug"/>

    <root level="info">
        <appender-ref ref="FILE_ERROR"/>
        <appender-ref ref="FILE_WARN"/>
        <appender-ref ref="FILE_INFO"/>
        <appender-ref ref="STDOUT"/>
    </root>

</configuration>

image-20220706105552317

image-20220706110245779

image-20220706110958678

上面的文件在使用到自己项目的时候需要改动的地方就是上面的路径包名

接下来运行一个测试类测试一下

image-20220706111728427

总结

在开发程序的时候,如果发现有问题,首先应该 1. 看状态码,大概定位一下是服务器端还是客户端有问题,
然后通过断点去跟踪或者去看一 2. 看这个日志,当然能看日志就先看日志,日志还是找不到问题就 3.跟踪一下。

8.版本控制

image-20220706161928761

http://git-scm.com

认识Git并安装

认识Git

image-20220706162909417

# 版本控制作用
通过版本控制可以对代码做一个备份
版本控制会将代码的每一次变更记录下来,假如这一代版本改坏了,可以通过历史记录恢复到上一代版本
另外还可以通过版本控制让团队之间互相协作(一个人将代码上传到版本控制服务器,其他人可以下载代码去看去改)

下载及安装Git

image-20220706163148528

image-20220706163200679

image-20220706163221266

下载完成之后是一个 exe 文件,安装即可

安装的时候可以选择自己想要安装的位置,其他的一路默认就可以。

image-20220706165613226

安装完成之后

image-20220706165848357

注意, Git Bash虽然输入的是Linux命令行,但是在windows环境下也可以使用(我估计后台会进行一个转化)

Git常用命令
# 账号配置
git config --list
git config --global user.name "xxx"              设置用户名
git config --global user.email "xxx@xxx.com"     设置邮箱地址

# 本地仓库
git init                           将当前目录配置成git仓库,信息记录在隐藏的.git文件夹中
git status -s                      查看仓库状态
git add XX 												 将XX文件添加到暂存区
git add *                          将所有文件添加到暂存区
git commit -m ‘...’                给自己看的“备注信息":将暂存区的内容提交到当前分支

注:git reset .                    清空暂存区的文件

# 生成秘钥
ssh-keygen -t rsa -C "lihonghe@nowcoder.com"    后面加的是本地的的邮箱地址

# 推送已有项目								
git remote add origin https://git.nowcoder.com/334190970/Test.git  
将本地仓库关联到远程仓库,origin表示后面那个网址的远程仓库的别名

git push -u origin master  		
将本地代码推送到名为 origin 的远程仓库的 master 分支

# 克隆已有仓库
git clone https://git.nowcoder.com/334190970/Test.git 
将后面的远程仓库地址下的文件下载到当前目录下

接下来我们来介绍一下windows环境下 Git 的常用命令

# windows环境下 Git 的常用命令
git version        查看 Git 的版本

打开上面windows环境下的Git软件

image-20220706170320090

先看一下 git version 命令查看Git版本

image-20220706170558910

在本地仓库中使用Git

首先演示一下在本地仓库中怎么使用git去管理项目中的代码

因为要把代码传到仓库里去,它得能识别你是谁,所以首先需要对 Git 进行一个配置,你要告诉这个 Git 我的用户名是谁,我的邮箱是谁,这两个都需要配,首先使用下面命令查看当前已有配置:

git config --list             查看当前已有配置

image-20220706173139120

可以看到上面没有用户名的配置也没有邮箱的配置,接下来我们来配置用户名和邮箱

git config --global user.name "lubing"    配置用户名   
git config --global user.email "958691367@qq.com"  设置全局邮箱地址

可以看到执行上述命令后配置中多了用户名和密码

image-20220706173911639

现在就可以利用Git去管理我们的代码了

比如现在有一套代码需要把它存到本地仓库里去

要管理哪套代码,需要先cd到项目目录下

image-20220706182817978

然后我们需要去做一个初始化表示这个项目需要交给 Git 去管理

git init

这个命令会导致 Git 在项目目录下创建一个隐藏的目录(了解)

image-20220706183104283

然后可以使用下面命令去查看管理的这套代码的状态

git status 

image-20220706183400434

然后我们需要把它们添加到我们的本地仓库中去

git add *.xml		将所有的以.xml为后缀的文件添加到本地仓库中去
git add *.java  将所有的以.java为后缀的文件添加到本地仓库中去
git add *       将所有文件添加到本地仓库中去

image-20220706183924770

上面只是临时的加进去了,还没有正式的提交,所以我们还需要提交以后才能在仓库里进行永久的存储

git commit -m 'Test1'

-m 后面单引号的内容表示备注

image-20220706184358241

然后接下来我们修改一下 mavendemo1 项目的内容,然后再使用 git status 命令

image-20220706184956795

远程仓库演示Git

接下来演示在本地仓库中的代码(已经提交过的代码)传到远程仓库上去

远程仓库有很多,比如 GitHub、Gitee ·····,其中牛客也有远程仓库,接下来演示如何把代码传到牛客的远程仓库上去。

Git 为了传代码安全,避免这个代码被偷,它在传输的时候采用 SSL 安全连接,安全的方式去传输,所以
我们需要首先配置一下秘钥,这样才可以使用这种安全传输方式。

创建秘钥
ssh-keygen -t rsa -C "958691367@qq.com"     

后面加的是Git账户的邮箱,敲完这个命令以后会有一些询问要把生成的秘钥存到哪里去,不用管,一路
回车即可(这个秘钥只需要生成一次在远程仓库中配置即可,之后就不需要配置了)

image-20220706211127391

接下来需要去远程仓库的界面做一个配置,把秘钥添加到远程仓库中去,这样远程仓库才能接收我们传的代码。

image-20220706211657842

image-20220706211814282

首先我们要在远程仓库里自己建一个项目(仓库),我们的代码要传到这个项目里

image-20220706212006846

image-20220706212254223

image-20220706213156154

之后我们需要在里面获取远程仓库的地址并将其复制下来

image-20220706213506177

首先我们需要在本地关联一下远程仓库(给上面的仓库起个别名,以后再去访问远程仓库用别名而不是每次都用上面的网址,不好记)

git remote add origin https://git.acwing.com/Lb/mavendemo2.git
将本地仓库关联到远程仓库,origin 表示后面那个网址的远程仓库的别名

git push -u origin master  		
将本地代码推送到名为 origin 的远程仓库的 master 分支

image-20220706214028916

之后需要输入邮箱和密码(在哪个平台就输入哪个远程仓库托管平台的邮箱和密码)

image-20220706215246014

注:因为牛客平台服务器问题,我上传到了其他平台,上传之后截图

image-20220706221506548

然后我们还有一个需求,比如我们远程仓库本来就有一个项目,我们想把它下载到本地好去学习。

image-20220706222104800

我们首先要 cd 到我们想要把这个项目存在哪里(不需要使用 git init 设置为仓库),然后执行下面命令(后面接的链接就是上面我们复制的 克隆的地址,建议使用 HTTPS 克隆,SSH 克隆不好使)

git clone https://git.acwing.com/Lb/mavendemo1.git

image-20220706223646028

成功下载(注意在下载的时候只会下载 main 分支下的内容)

IDEA演示Git

接下来我们演示在 IDEA 怎么去配怎么去管理git管理代码,这样就不用写命令了,传上去很方便

首先要在 IDEA 中配置一下Git,因为 IDEA 不知道你的远程仓库放在哪,你要告诉它。

image-20220706224007133

之后点击 Apply 应用就好。

之后我们需要把这个项目初始化一下,然后把这个项目添加到本地仓库中去,然后再推送到远程仓库中去,和刚才的命令行操作是一样的,只不过这里是通过点按钮的方式。

image-20220706224437404

image-20220706224523457

image-20220706224756930

然后会出来一个框框,让选择提交的文件

image-20220706225145656

要想把本地仓库中的文件传到远程仓库,我们要在远程仓库建一个项目。

image-20220706225654559

image-20220706230126901

image-20220706230333823

image-20220706230448300

image-20220706230526482

image-20220706230715303

最后补充一点:

GitHub 上传文件的最大大小是 100 M,如果大小超过这个限制,会出现未知的错误。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值