美文网首页
2020-01-17 从零开始用Spring Boot开发一个个

2020-01-17 从零开始用Spring Boot开发一个个

作者: NoelleMu | 来源:发表于2020-01-17 17:12 被阅读0次

    实体类

    根据需求,我们可以抽象出以下实体类:

    • 文章类(Article)
    • 分类类(Type)
    • 标签类(Tag)
    • 评论类(Comment)
    • 用户类(User)

    实体关系

    不是很会画ER图,就画张草图简单示意一下:

    可能有人会问了,为什么博客和用户之间没有关系呢?其实很简单,就是因为这个网站真正可以发布文章的只有我一个人,用户只是用来发表评论的,所以用户和博客(文章)之间不需要建立关系。

    实体类

    重构之后我们没有选择MongoDB,而是用了MySQL——原因也只有一个:成熟,解决方案多。而且数据量其实不是很大,关系也不是很复杂,这种情况下用MySQL不会带来特别大的麻烦。

    实体类其实没有太多好讲的,主要是在实体关系这方面需要多关注一些。

    文章

    这次使用@NotNull@NotEmpty注解加上了判空操作,避免因为参数校验不足而产生一个NullPointerException把后端代码整炸了。

    使用懒加载是为了提高性能。

    这次遵循阿里Java编码规范,使用文档注释来写每个字段的注释。

    Lombok还是要用的,对提高开发效率有很高的帮助。

    @Temporal注解可以用于指定时间的格式,这里就用TIMESTAMP时间戳类型了。

    文章内容这个字段需要使用TEXT类型,使用方法就是加上两个注解:@Lob@Column,并且指定它为TEXT类型。

    /**
     * 文章实体类
     *
     * @author jiangwen
     */
    @Data
    @NoArgsConstructor
    @Accessors(chain = true)
    @ToString
    @Entity
    @Table(name = "wendev_article")
    public class Article {
        /**
         * 主键,值为自动生成
         */
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
    
        /**
         * 文章标题
         */
        @NotNull(message = "标题不能为空")
        @NotEmpty(message = "标题不能为空字符串")
        @Column
        private String title;
    
        /**
         * 文章内容,因为太长所以映射为TEXT类型
         */
        @NotNull(message = "文章内容不能为空")
        @NotEmpty(message = "文章内容不能为空字符串")
        @Lob
        @Column(columnDefinition = "TEXT")
        private String content;
    
        /**
         * 文章阅读量
         */
        @Column
        private Integer views;
    
        /**
         * 是否已发布
         * 这其实是一个保留字段,目前还用不到
         */
        @Column
        private Boolean published;
    
        /**
         * 是否开启评论功能
         */
        @Column
        private Boolean commentEnabled;
    
        /**
         * 文章的创建时间
         */
        @Column
        @Temporal(TemporalType.TIMESTAMP)
        private Date createTime;
    
        /**
         * 文章的更新时间
         */
        @Column
        @Temporal(TemporalType.TIMESTAMP)
        private Date updateTime;
    
        /**
         * 该文章所属的类型
         */
        @ManyToOne
        private Type type;
    
        /**
         * 该文章所拥有的标签,设置级联新增
         */
        @ManyToMany(cascade = {CascadeType.PERSIST}, fetch = FetchType.LAZY)
        private List<Tag> tags = new ArrayList<>();
    
        /**
         * 该文章对应的评论
         */
        @OneToMany(mappedBy = "article", fetch = FetchType.LAZY)
        private List<Comment> comments = new ArrayList<>();
    
        /**
         * 乐观锁
         */
        @Version
        private Long version;
    }
    
    

    用户

    为了以后可能对接Spring Security而保留了一个role字段。

    /**
     * @author jiangwen
     */
    @Data
    @NoArgsConstructor
    @Accessors(chain = true)
    @ToString
    @Entity
    @Table(name = "wendev_user")
    public class User {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
    
        @Column
        @NotNull(message = "用户名不能为空")
        @NotEmpty(message = "用户名不能为空字符串")
        private String username;
    
        @Column
        @NotNull(message = "用户昵称不能为空")
        @NotEmpty(message = "用户昵称不能为空字符串")
        private String nickname;
    
        @Column
        @NotNull(message = "邮箱不能为空")
        @NotEmpty(message = "邮箱不能为空字符串")
        private String email;
    
        @Column
        @NotNull(message = "密码不能为空")
        @NotEmpty(message = "密码不能为空字符串")
        private String password;
    
        /**
         * 用户权限
         * 这个字段是为了以后可能对接Spring Security保留的
         */
        @Column
        @NotNull(message = "用户角色不能为空")
        @NotEmpty(message = "用户角色不能为空字符串")
        private String role;
    
        @Temporal(TemporalType.TIMESTAMP)
        private Date createTime;
    
        @Temporal(TemporalType.TIMESTAMP)
        private Date updateTime;
    
        /**
         * 该用户所发表的全部评论
         */
        @OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
        private List<Comment> comments = new ArrayList<>();
    
        @Version
        private Long version;
    }
    
    

    文章类型

    类型与文章是一对多关系,由类型端来维护。

    /**
     * 文章类型实体类
     *
     * @author jiangwen
     */
    @Data
    @NoArgsConstructor
    @Accessors(chain = true)
    @ToString
    @Entity
    @Table(name = "wendev_type")
    public class Type {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
    
        /**
         * 类型名称
         */
        @NotNull(message = "类型名称不能为空")
        @NotEmpty(message = "类型名称不能为空字符串")
        @Column
        private String name;
    
        /**
         * 该分类下属的文章
         * 关系的被维护端
         */
        @OneToMany(mappedBy = "type", fetch = FetchType.LAZY)
        private List<Article> articles = new ArrayList<>();
    
        @Version
        private Long version;
    }
    
    

    文章标签

    标签与文章有多对多关系,由标签端来维护。

    /**
     * 文章标签实体类
     *
     * @author jiangwen
     */
    @Data
    @NoArgsConstructor
    @Accessors(chain = true)
    @ToString
    @Entity
    @Table(name = "wendev_tag")
    public class Tag {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
    
        /**
         * 拥有该tag的文章列表
         * 关系的维护端
         */
        @ManyToMany(mappedBy = "tags", fetch = FetchType.LAZY)
        private List<Article> articles = new ArrayList<>();
    
        /**
         * 标签名称
         */
        @Column
        @NotNull(message = "标签名称不能为空")
        @NotEmpty(message = "标签类型不能为空")
        private String name;
    
        @Version
        private Long version;
    }
    
    

    评论

    评论也没什么好说的。但是由于它有一个自关联一对多的关系,所以需要注意一下。

    其实也没有什么好注意的,当成两个实体类来写就行了。

    /**
     * @author jiangwen
     */
    @Data
    @NoArgsConstructor
    @Accessors(chain = true)
    @ToString
    @Entity
    @Table(name = "wendev_comment")
    public class Comment {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
    
        /**
         * 该评论的发表者
         */
        @ManyToOne
        private User user;
    
        /**
         * 该评论所属于的文章
         */
        @ManyToOne
        private Article article;
    
        /**
         * 该评论下的子评论
         */
        @OneToMany(mappedBy = "parentComment", fetch = FetchType.LAZY)
        private List<Comment> replyComments = new ArrayList<>();
    
        /**
         * 该评论的父评论
         */
        @ManyToOne
        private Comment parentComment;
    
        @Column
        @NotNull(message = "评论内容不能为空")
        @NotEmpty(message = "评论内容不能为空字符串")
        private String content;
    
        @Temporal(TemporalType.TIMESTAMP)
        private Date createTime;
    
        @Version
        private Long version;
    }
    
    

    这样实体类和实体关系就构建完成了。

    启动项目让JPA帮我们创建好表,再从DataGrip里查看一下表关系图就可以很清楚地看出这些实体类之间的关系了:

    wendev_article_tags是维护文章与标签多对多关系的关联表,是自动帮我们创建好的。当然也可以在实体类里使用@JoinTable指定它的信息。

    相关文章

      网友评论

          本文标题:2020-01-17 从零开始用Spring Boot开发一个个

          本文链接:https://www.haomeiwen.com/subject/xrcqzctx.html