• (仿牛客论坛项目)01 - 开发社区首页



    前言

    第一个大的项目,具体其中的技术细节就不做笔记了,需要的可以自己去牛客官网学习;不过其中没有具体讲这个技术细节,只是教会你该怎么用;
    视频链接:https://www.nowcoder.com/study/live/246


    1、做项目的步骤

    1. 需求;
    2. 抽取实体,建数据库,建表,给表中添加一些测试数据;
    3. 根据数据库的表建立 pojo/entity 类;(下面所有的 pojo 类都忽略 get/set 方法
    4. 分步实现功能:DAO -> Service 层 -> Controller 层 -> html 静态页面

    注意:

    • 所有的数据库表和静态页面可以从官网获取。

    2、开发社区首页功能分步

    在这里插入图片描述
    一些前期的准备工作,顺便测试一下数据库连接:

    2.1 User 类

    1. 根据数据库表建立的 pojo 类,采用驼峰映射法,配置文件中已经开启了驼峰映射,mybatis.configuration.mapUnderscoreToCamelCase=true
    public class User {
        private int id;
        private String username;
        private String password;
        private String salt;
        private String email;
        private int type;
        private int status;
        private String activationCode;
        private String headerUrl;
        private Date createTime;
    
        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", username='" + username + '\'' +
                    ", password='" + password + '\'' +
                    ", salt='" + salt + '\'' +
                    ", email='" + email + '\'' +
                    ", type=" + type +
                    ", status=" + status +
                    ", activationCode='" + activationCode + '\'' +
                    ", headerUrl='" + headerUrl + '\'' +
                    ", createTime=" + createTime +
                    '}';
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    2.2 UserMapper 接口

    1. 定义一些 DAO 层要用到的和数据库交互的增删改查方法;
    2. 上面加上 @Mapper 注解将当前类标识为一个 mapper 接口;
    @Mapper
    public interface UserMapper {
        User selectById(int id);
    
        //根据用户名来查询,用户名是唯一的
        User selectByName(String username);
    
        User selectByEmail(String email);
    
        int insertUser(User user);
    
        //以id为条件更新一些参数:状态、头像路径、密码
        int updateStatus(int id, int status);
    
        int updateHeader(int id, String headerUrl);
    
        int updatePassword(int id, String password);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    2.3 UserMapper 映射文件

    1. 具体的实现 DAO 层功能的文件,namespace 中接口的全类名不能写错;
    <?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.UserMapper">
    
        <sql id="insertFields">
            username, password, salt, email, type, status, activation_code, header_url, create_time
        </sql>
    
        <sql id="selectFields">
            id, username, password, salt, email, type, status, activation_code, header_url, create_time
        </sql>
    
        <select id="selectById" resultType="User">
            select
            <include refid="selectFields"></include>
            from user
            where id = #{id}
        </select>
    
        <select id="selectByName" resultType="User">
            select
            <include refid="selectFields"></include>
            from user
            where username = #{username}
        </select>
    
        <select id="selectByEmail" resultType="User">
            select
            <include refid="selectFields"></include>
            from user
            where email = #{email}
        </select>
    
        <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>
    
        <update id="updateStatus">
            update user
            set status = #{status}
            where id = #{id}
        </update>
    
        <update id="updateHeader">
            update user
            set header_url = #{headerUrl}
            where id = #{id}
        </update>
    
        <update id="updatePassword">
            update user
            set password = #{password}
            where id = #{id}
        </update>
    </mapper>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    2.4 编写测试类

    1. 编写测试类,测试和数据库连接是否有问题,能否正确从数据库获取数据;
    @SpringBootTest
    public class MapperTests {
        @Autowired
        private UserMapper userMapper;
    
        @Test
        public void testSelectUser() {
            User user = userMapper.selectById(101);
            System.out.println(user);
    
            user = userMapper.selectByName("liubei");
            System.out.println(user);
    
            user = userMapper.selectByEmail("nowcoder101@sina.com");
            System.out.println(user);
        }
    
        @Test
        public void testInsertUser() {
            User user = new User();
            user.setUsername("test");
            user.setPassword("123456");
            user.setSalt("abc");
            user.setEmail("test@qq.com");
            user.setHeaderUrl("http://www.nowcoder.com/101.png");
            user.setCreateTime(new Date());
    
            int rows = userMapper.insertUser(user);
            System.out.println(rows);
            System.out.println(user.getId());
        }
    
        @Test
        public void updateUser() {
            int rows = userMapper.updateStatus(150, 1);
            System.out.println(rows);
    
            rows = userMapper.updateHeader(150, "http://www.nowcoder.com/102.png");
            System.out.println(rows);
    
            rows = userMapper.updatePassword(150, "hello");
            System.out.println(rows);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    3、开发社区首页,显示前10个帖子

    3.1 DiscussPost 类

    1. 完全对应表 discuss_post 来建立;
    2. 这里的 userId 不要写成 User 实体类,后面在 Controller 类中进行关联即可,否则要在 Mapper 映射类中进行多对一关系映射,不利于后面实现 Redis 存储。
    /**
     * 对应表discuss_post
     */
    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;
    
        @Override
        public String toString() {
            return "DiscussPost{" +
                    "id=" + id +
                    ", userId=" + userId +
                    ", title='" + title + '\'' +
                    ", content='" + content + '\'' +
                    ", type=" + type +
                    ", status=" + status +
                    ", createTime=" + createTime +
                    ", commentCount=" + commentCount +
                    ", score=" + score +
                    '}';
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    3.2 DiscussPostMapper 接口

    1. 实现查询所有帖子功能;
    2. 考虑到之后要实现登录之后显示我的帖子功能,所以这里添加一个条件userId,并且使用动态 sql 来实现拼接;
    3. 考虑到之后可能要分页显示,所以形参中加上 offset-偏移量 和 limit-每页显示多少帖子 数据;
    @Mapper
    public interface DiscussPostMapper {
        //查询所有帖子,要实现登录之后显示我的帖子,也要实现分页显示的功能
        List<DiscussPost> selectAllDiscussPosts(int userId,int offset,int limit);
    
        //查询一共有多少条数据
        // @Param注解用于给参数取别名,如果只有一个参数,并且在<if>里使用,则必须加别名.
        int selectDiscussPostRows(@Param("userId") int userId);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    注意:

    • @Param 注解用于给参数取别名,如果只有一个参数,并且在 sql 动态拼接中即 <if> 标签里使用,则必须加别名。

    3.3 DiscussPostMapper 映射文件

    1. 尽量在 sql 语句中不要使用 * 来显示查询数据,要使用字段,sql 优化之一;
    2. 在映射文件中将所有的增查的 sql 字段提取出来作为一个公用的 sql 语句,这样之后想修改查询的字段的时候,一处修改,处处生效;
    3. 要注意标签内部的语句都是 sql 字段,标签中对应的都是 java 类,包括 #{java属性} 中使用的也是 java 某实体类中对应的属性名称。
    <?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>
        <!--List<DiscussPost> selectAllDiscussPosts(int userId,int offset,int limit);-->
        <select id="selectAllDiscussPosts" 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>
    
        <!--int selectDiscussPostRows(@Param("userId") int userId);-->
        <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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    解释:

    • 如果你从一开始

    3.4 编写测试类

    @SpringBootTest
    public class DiscussPostTest {
        @Autowired
        private DiscussPostMapper discussPostMapper;
    
        //用户输入为null表示首页展示
        @Test
        public void testSelectAllDiscussPosts(){
            List<DiscussPost> discussPosts = discussPostMapper.selectAllDiscussPosts(0, 0, 10);
            discussPosts.forEach(System.out::println);
        }
    
        @Test
        public void testSelectDiscussPostRows(){
            int discussPostRows = discussPostMapper.selectDiscussPostRows(0);
            System.out.println(discussPostRows);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    3.5 UserService 层

    1. 查询出所有的帖子之后,在主页要显示每个帖子对应的用户头像,所以还要将用户信息查询出来;
    @Service
    public class UserServiceImpl implements UserService {
        @Autowired
        private UserMapper userMapper;
    
        @Override
        public User findUserById(int id) {
            return userMapper.selectById(id);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    3.6 HomeController 层

    1. 显示前 10 个帖子:先实现查询10条数据,查询所有帖子的 userId 对应的 User 数据, 将所有的 User 和 DiscussPost 中的 userId 关联起来;
    2. 将帖子放在作用域中,返回视图名称,这里返回视图名称是给 thymeleaf 模板解析的,所以会自动加上试图前缀和视图后缀;
    @Controller
    public class HomeController {
        @Autowired
        private DiscussPostService discussPostService;
    
        @Autowired
        private UserService userService;
    
        //实现主页功能
        @RequestMapping(value = "/index", method = RequestMethod.GET)
        public String index(Model model) {
            List<DiscussPost> list = discussPostService.findDiscussPosts(0, 0, 10);
            //使用一个map容器将所有的User和DiscussPost中的userId关联起来
            List<Map<String, Object>> discussPosts = new ArrayList<>();
            if (list != null) {
                for (DiscussPost discussPost : list) {
                    HashMap<String, Object> map = new HashMap<>();
                    map.put("discussPost", discussPost);
                    //根据userId获取User对象
                    User user = userService.findUserById(discussPost.getUserId());
                    map.put("user", user);
                    //将这一对关联的对象放进list集合中
                    discussPosts.add(map);
                }
            }
            model.addAttribute("discussPosts", discussPosts);
            return "index";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    3.7 修改 index.html 文件

    1. 将文件引用路径改成 thymeleaf 格式的;

      1. 在 html 表头标签加上:xmlns:th="http://www.thymeleaf.org"

      2. 引入外部 css 样式加上:th:href="@{/css/global.css}"

    2. 处理帖子列表部分的内容:

      • 遍历所有的帖子:th:each="map:${discussPosts}"
      • 显示用户头像:th:src="${map.user.headerUrl}"
      • 显示帖子title:有可能会包含转义字符的情况下使用 th:utext 标签,th:utext="${map.discussPost.title}"
      • 判断是否是置顶类型,也就是type==1,th:if="${map.discussPost.type==1}"
      • 判断是否是精华帖子,th:if="${map.discussPost.status==1}"
      • 修改帖子的作者:th:utext="${map.user.username}"
      • 修改帖子发布时间:th:text="${map.discussPost.createTime}"

    注意:

    • 修改时间显示格式:th:text="${#dates.format(xxx.xxx.xxx,'yyyy-MM-dd HH:mm:ss')}"这种方法只能修改 Date 格式的日期,不能修改 LocalDateTime 格式(新日期)的数据);
    <!-- 帖子列表 -->
    <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.discussPost.title}">备战春招,面试刷题跟他复习,一个月全搞定!</a>
    				<span class="badge badge-secondary bg-primary" th:if="${map.discussPost.type==1}">置顶</span>
    				<span class="badge badge-secondary bg-danger" th:if="${map.discussPost.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.discussPost.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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    3.8 访问首页

    1. 访问 http://localhost:8080/community/index,观看是否可以显示正确的首页数据(10 条数据);

    在这里插入图片描述

    3.9 错误信息及问题解决

    问题一:将所有的 User 和 DiscussPost 关联起来有两种方法

    一种是在查询 sql 语句的时候关联查询用户,可以使用 association 处理一对多关系,也可以使用分步查询;

    1. 如果在开始新建 pojo 类的时候就将 userId 定义成 User 实体类,那么这里涉及到,JavaBean实体类怎么处理外键
    2. 对于一个实体类的属性是另一个实体类的时候,在编写 mapper 映射文件的时候需要涉及到实体类属性的参数设置,Mybatis mapper层 同时传入实体类和单独的参数

    另外一种是在 HomeController 中单独的针对每个 DiscussPost,根据 userId 获取用户数据,并将他们关联起来;使用第二种,后面使用 redis 的时候更方便

    4、开发分页组件,分页显示所有帖子

    4.1 Page 组件

    1. 这里使用的时候直接复制粘贴即可,其实已经有封装好的分页插件可以使用;
    /**
     * 封装分页相关的信息.
     */
    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;
        }
    
        /**
         * 获取总页数
         * @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;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93

    4.2 HomeController 层

    1. 实现分页功能:getIndexPage(Model model,Page page)方法,设置总页数,设置复用的路径,将查找的数据变成所有的数据,而不是固定的10条
    2. 方法调用前,SpringMVC会自动实例化 Model 和 Page,并且将 page 注入 Model 中(不需要像 discussPosts 一样需要我们手动放入),所以 thymeleaf 可以直接访问 Page 对象中的数据;
    //实现主页功能
    @RequestMapping(value = "/index", method = RequestMethod.GET)
    public String index(Model model, Page page) {
        //插入分页功能
        //设置总共页数,初始页面,是不存在用户信息的
        page.setRows(discussPostService.findDiscussPostRows(0));
        //设置复用的路径,这个是给浏览器发送请求用的,所以要加上/
        page.setPath("/index");
    
    
        List<DiscussPost> list = discussPostService.findDiscussPosts(0, page.getOffset(), page.getLimit());
        //使用一个map容器将所有的User和DiscussPost中的userId关联起来
        List<Map<String, Object>> discussPosts = new ArrayList<>();
        if (list != null) {
            for (DiscussPost discussPost : list) {
                HashMap<String, Object> map = new HashMap<>();
                map.put("discussPost", discussPost);
                //根据userId获取User对象
                User user = userService.findUserById(discussPost.getUserId());
                map.put("user", user);
                //将这一对关联的对象放进list集合中
                discussPosts.add(map);
            }
        }
        model.addAttribute("discussPosts", discussPosts);
        return "index";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    4.3 修改 index.html 页面

    1. 处理分页的逻辑:(之后所有页面的分页逻辑都可以复用
    2. 如果一个帖子都没有的话,不显示页码,有帖子才显示分页逻辑:th:if="${page.rows>0}"
    3. 修改首页和末页逻辑: th:href="@{${page.path}(current=1)}",这里传送的请求其实就是: /index?current=1
    4. 修改上一页下一页逻辑:th:href="@{${page.path}(current=${page.total})}"
    5. 遍历显示中间的页码,生成从 page.from 到 page.to 之间的连续的一个数组:th:each="i:${#numbers.sequence(page.from,page.to)}",跳转到对应页面:th:href="@{${page.path}(current=${i})}"
    6. 当前在首页时候上一页不可点,末页的时候下一页不可点:th:class="|page-item ${page.current==1?'disabled':''}|"
    7. 当前在第几页,这个页码上高亮,通过 class 中的 active 效果来实现:th:class="|page-item ${i==current?'active':''}|"
    <!-- 分页 -->
    <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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    4.4 访问首页

    1. 访问 http://localhost:8080/community/index,观看是否可以显示正确的显示所有分页数据;

    在这里插入图片描述

    在这里插入图片描述

    5、错误排查

    5.1 由于低版本 Spring 不支持高版本 JDK 报错

    一开始用的是 5.3.4 版本,发现会报错:初学Spring遇到Unsupported class file major version 61 错误

    5.2 @RunWith 注解找不到

    找不到 @RunWith 注解,高版本取消了这个注解,直接使用@SpringBootTest 注解就可以了,@RunWith注解找不到,怎么办?

    5.3 想访问一个 servlet 却变成了下载一个东西,竟然只是写错了 text

    访问一个页面,发送请求,没有得到想象中的响应页面,原因是粗心错误:访问一个servlet却直接下载文件

    6、常用注解和命令

    6.1 SpringBoot 常用注解

    1. @SpringBootApplication:定义主程序
    2. @SpringBootConfiguration:当前类当作一个配置文件
    3. @EnableAutoConfiguration:允许配置文件的自动装配
    4. @ComponentScan:自动扫描配置类所在的包以及所有子包下的bean
    5. 四个注解可以将一个类当成一个bean被扫描:@Component,@Controller,@Service,@Repository
    6. 在测试类中测试使用IOC容器,需要使用注解@ContextConfiguration(classes = CommunityApplication.class),这个测试类要implements ApplicationContextAware,重写其中的setApplicationContext方法
    7. @Primary:当使用 @Autowired 来根据类型进行属性注入的时候,或者 IOC 容器根据类型来进行 getBean() 装配的时候,优先被提取的类
    8. @Repository("helloDao"):字符串中定义bean的名字,默认是首字母小写的类名
    9. @PostConstruct:在类的构造器之后执行
    10. @PreDestroy:在类的销毁之前执行
    11. @Scope(value = "prototype"):定义多例bean

    6.2 注意 MVC 框架三层和服务器三层组件的区别

    在这里插入图片描述

    • 服务器三层组件:表现层、业务层、数据层;
    • SpringMVC 框架三层:Model、View、Controller,是表现层的一个框架;

    6.3 request 常用的获取方法

    1. 获取请求方法、路径、请求头(先获取所有的键值对,然后根据键值遍历获取值)、请求参数
    request.getMethod()
    request.getServletPath()
    request.getHeaderNames();request.getHeader(name);
    request.getParameter("code")
    
    • 1
    • 2
    • 3
    • 4

    6.4 数据库的命令行操作

    1. 数据库访问:mysql -uroot -p,输入这个之后回车输入密码是隐藏的;
    2. 修改密码:alter user root@localhost identified by 'abc123';,不要忘记最后的分号;
    3. 创建一个新的数据库:create database communtiy;
    4. 展示数据库列表:show databases;
    5. 删除数据库:drop database communtiy;
    6. 修改当前使用的数据库:use community;

    6.5 MySQL 8.0 数据库中时间需要注意的点

    1. MySQL8.0 之后数据库 DataTime 类型的字段,对应 java 类发生了改变,由原来对应的 Date 类变成了变成了 LocalDateTime;
    2. timestamp 对应的还是 Data 类。
  • 相关阅读:
    颠覆传统有线通讯,虹科IO-Link wireless解决方案让智能机床的旋转部件实现可靠低延迟无线通信
    Python-关于模块导入的细节和坑
    前端框架 ng 环境配置
    Linux基础——账号、群组管理
    ROS学习总结十七:自定义消息的使用
    什么是CSS的外边距重叠?
    SAP入门到放弃系列之QM物料主数据&检验类型设置
    【数据通信】具有路由 WSN 模拟器的随机方式移动(Matlab代码实现)
    Springboot项目:连接mysql数据库,使用aop进行日志捕获
    鸿蒙OS应用开发初体验
  • 原文地址:https://blog.csdn.net/qq_42148002/article/details/125536184