MP实战系列之实体类讲解

Posted 挑战者V

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MP实战系列之实体类讲解相关的知识,希望对你有一定的参考价值。

首先说一句,mybatis plus实在太好用了!

mybaits plus的实体类:

以我博客的用户类作为讲解

package com.blog.entity;

import com.baomidou.mybatisplus.annotations.TableField;
import com.baomidou.mybatisplus.annotations.TableId;
import com.baomidou.mybatisplus.annotations.TableLogic;
import com.baomidou.mybatisplus.annotations.TableName;
import com.baomidou.mybatisplus.enums.IdType;

import java.io.Serializable;
import java.util.Date;

/**
 * 
 * 
 * @author youcong
 * @email ${email}
 * @date 2018-04-21 15:27:01
 */
@TableName("user")
public class UserEntity implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * 用户ID
     */
    @TableId(type=IdType.AUTO)
    private Integer user_id;
    /**
     * 用户名
     */
    private String username;
    /**
     * 性别
     */
    private String sex;
    /**
     * 电话
     */
    private String phone;
    /**
     * 密码
     */
    private String password;
    /**
     * 等级
     */
    private Integer level;
    /**
     * 用户创建时间
     */
    @TableField(value="create_time")
    private String createTime;
    /**
     * 邮箱
     */
    private String email;
    /**
     * 登录标识
     */
    private Integer logo;

    /**
     * 设置:用户ID
     */
    public void setUserId(Integer user_id) {
        this.user_id = user_id;
    }
    /**
     * 获取:用户ID
     */
    public Integer getUserId() {
        return user_id;
    }
    /**
     * 设置:用户名
     */
    public void setUsername(String username) {
        this.username = username;
    }
    /**
     * 获取:用户名
     */
    public String getUsername() {
        return username;
    }
    /**
     * 设置:性别
     */
    public void setSex(String sex) {
        this.sex = sex;
    }
    /**
     * 获取:性别
     */
    public String getSex() {
        return sex;
    }
    /**
     * 设置:电话
     */
    public void setPhone(String phone) {
        this.phone = phone;
    }
    /**
     * 获取:电话
     */
    public String getPhone() {
        return phone;
    }
    /**
     * 设置:密码
     */
    public void setPassword(String password) {
        this.password = password;
    }
    /**
     * 获取:密码
     */
    public String getPassword() {
        return password;
    }
    /**
     * 设置:等级
     */
    public void setLevel(Integer level) {
        this.level = level;
    }
    /**
     * 获取:等级
     */
    public Integer getLevel() {
        return level;
    }
    /**
     * 设置:用户创建时间
     */
    public void setCreateTime(String createTime) {
        this.createTime = createTime;
    }
    /**
     * 获取:用户创建时间
     */
    public String getCreateTime() {
        return createTime;
    }
    /**
     * 设置:邮箱
     */
    public void setEmail(String email) {
        this.email = email;
    }
    /**
     * 获取:邮箱
     */
    public String getEmail() {
        return email;
    }
    /**
     * 设置:登录标识
     */
    public void setLogo(Integer logo) {
        this.logo = logo;
    }
    /**
     * 获取:登录标识
     */
    public Integer getLogo() {
        return logo;
    }
}

 

上述的注解什么意思,为什么用,我在第一篇MP实战中提过也加以描述说过。不过,今天我还是要强调一下,@TableName该注解用英文翻译就是"表名"的意思,通常在这里面写实体对应的表名,方便映射。大家还记得hibernate吗?hibernate中有个配置文件叫:hibernater-cfg.xml,该配置文件主要配置hibernate的数据源和实体映射扫描等等,这个实体映射扫描,就是通过注解,之前是每个实体对应的xml文件,而在这个xml文件中配置实体对应表的属性。后来hibernate进行升级了,如果是每一个实体对应一个xml文件,随着项目越来越大,xml文件管理起来也是个问题,于是注解,应需而生。

大家可以参考我的关于spring+hibernate+springmvc框架搭建的例子,看其中有一个实体就是通过注解的形式映射。这个与mybatis plus实体注解也是一个意思,并无多大差异。下面贴个代码方便讲解:

package com.ssh.entity;

import lombok.Data;

import javax.persistence.*;

/**
 * Created by XRog
 * On 2/2/2017.2:03 PM
 */
@Data
@Entity
@Table(name = "Person")
public class Person {

    @Id
    @GeneratedValue
    private Long id;

    @Column(name = "created")
    private Long created = System.currentTimeMillis();

    @Column(name = "username")
    private String username;

    @Column(name = "address")
    private String address;

    @Column(name = "phone")
    private String phone;

    @Column(name = "remark")
    private String remark;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Long getCreated() {
        return created;
    }

    public void setCreated(Long created) {
        this.created = created;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getRemark() {
        return remark;
    }

    public void setRemark(String remark) {
        this.remark = remark;
    }
    
    
}

这是hibernate的实体注解, @Data : 注解在类上, 为类提供读写属性, 此外还提供了 equals()、hashCode()、toString() 方法

                                             @Entity 对实体注释。任何Hibernate映射对象都要有这个注释

              @Table 的意思与mybatis plus中的@TableName意思是一样的

                                             @Id和@GeneratedValue是对主键的标识,这里与mybatis plus中的@TableId意思也是一样的

                                             @Column 意思就如其名,标识列的,在属性上打上该注解,使其与数据表中的字段名进行映射,而mybatis plus这里的@TableField虽有映射的意思,但是还有其他的意思,

                                     比如mybatis中,为什么要用resultType?为什么要用resultMap?原因很简单,一句话即可解释,当实体属性与表的字段名一致时,自动映射,当不一致时,需手动映射。

                                           @TableFiled在此就有这个作用

@TableName的源码如下:

/**
 * Copyright (c) 2011-2014, hubin ([email protected]).
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.baomidou.mybatisplus.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * <p>
 * 数据库表相关
 * </p>
 *
 * @author hubin
 * @since 2016-01-23
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface TableName {

    /**
     * <p>
     * 实体对应的表名
     * </p>
     */
    String value() default "";

    /**
     * <p>
     * 实体映射结果集
     * </p>
     */
    String resultMap() default "";

}

这里对@Retention和@Target做简单的说明:

元数据

也叫元注解,是放在被定义的一个注解类的前面 ,是对注解一种限制。

谈下这两个: @Retention 和 @Target  

@Retention :用来说明该注解类的生命周期。它有以下三个参数:

RetentionPolicy.SOURCE  : 注解只保留在源文件中

RetentionPolicy.CLASS  : 注解保留在class文件中,在加载到JVM虚拟机时丢弃

RetentionPolicy.RUNTIME  : 注解保留在程序运行期间,此时可以通过反射获得定义在某个类上的所有注解。

@Target :  用来说明该注解可以被声明在那些元素之前。

ElementType.TYPE:说明该注解只能被声明在一个类前。

ElementType.FIELD:说明该注解只能被声明在一个类的字段前。

ElementType.METHOD:说明该注解只能被声明在一个类的方法前。

ElementType.PARAMETER:说明该注解只能被声明在一个方法参数前。

ElementType.CONSTRUCTOR:说明该注解只能声明在一个类的构造方法前。

ElementType.LOCAL_VARIABLE:说明该注解只能声明在一个局部变量前。

ElementType.ANNOTATION_TYPE:说明该注解只能声明在一个注解类型前。

ElementType.PACKAGE:说明该注解只能声明在一个包名前。

 

@TableId源码:

/**
 * Copyright (c) 2011-2014, hubin ([email protected]).
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.baomidou.mybatisplus.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import com.baomidou.mybatisplus.enums.IdType;

/**
 * <p>
 * 表主键标识
 * </p>
 *
 * @author hubin
 * @since 2016-01-23
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface TableId {

    /**
     * <p>
     * 字段值(驼峰命名方式,该值可无)
     * </p>
     */
    String value() default "";

    /**
     * <p>
     * 主键ID
     * </p>
     * {@link IdType}
     */
    IdType type() default IdType.NONE;

}

@TableId中有这么几个属性,其中用的比较多的就是属Type

Type常用的枚举有:

AUTO 主键自增

ID_WORKER

INPUT 主键以输入的方式

NONE 默认一般是自增

UUID UUID方式

我个人用的比较多,一个是AUTO,另外一个是UUID,这两个能满足大多数的项目需求

 

@TableFied源码:

/**
 * Copyright (c) 2011-2014, hubin ([email protected]).
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.baomidou.mybatisplus.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import com.baomidou.mybatisplus.enums.FieldFill;
import com.baomidou.mybatisplus.enums.FieldStrategy;

/**
 * <p>
 * 表字段标识
 * </p>
 *
 * @author hubin sjy tantan
 * @since 2016-09-09
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface TableField {

    /**
     * <p>
     * 字段值(驼峰命名方式,该值可无)
     * </p>
     */
    String value() default "";

    /**
     * <p>
     * 当该Field为类对象时, 可使用#{对象.属性}来映射到数据表.
     * </p>
     * <p>
     * 支持:@TableField(el = "role, jdbcType=BIGINT)<br>
     * 支持:@TableField(el = "role, typeHandler=com.baomidou.xx.typehandler.PhoneTypeHandler")
     * </p>
     */
    String el() default "";

    /**
     * <p>
     * 是否为数据库表字段
     * </p>
     * <p>
     * 默认 true 存在,false 不存在
     * </p>
     */
    boolean exist() default true;

    /**
     * <p>
     * 字段验证策略
     * </p>
     * <p>
     * 默认 非 null 判断
     * </p>
     */
    FieldStrategy strategy() default FieldStrategy.NOT_NULL;

    /**
     * <p>
     * 字段自动填充策略
     * </p>
     */
    FieldFill fill() default FieldFill.DEFAULT;
}

@TableField是比较常用的注解,有的时候觉得ajax要传实体(这个实体包含其它实体类属性),通常规范的做法是写个dto,直接传输,一来复用方便,二来简洁清楚,我们开发中通常不推荐一个实体中嵌入其他实体的属性,但是有的时候,人有点懒,需求有点变态,为了加快速度,就直接在一个实体中,写其他实体属性。

这就好比,在一个html页面中,建议写外部js和css,一来规范,二来方便管理,三来复用,不过规范通常是让人痛苦的,不过对于时常变更的项目需求而言是快乐的,因为代码规范不乱,但是对于小公司而言,有的时候为了加快项目进度,不管三七二十一,行内样子能解决,绝对不用外部,最后一个页面内置一大堆css,js,而且html标签中又嵌入一大堆css标签或者js函数等,等到要优化时,有种想骂人的冲动。

题外话就不多说了,总而言之,规范开发虽然是痛苦,但是对于未来是很有益的,坚持规范,做一个代码洁癖的人!目前我还是不符合。至少我还是与前者所说的,占了一半。深刻的体会到,代码不规范,乱七八糟带来的影响。@TableField中的exist属性就是为了当你的实体包含其它实体时,可以指定它,默认为true,需要指定为false,true的意思是该字段在数据表中存在,false是不存在,通常的话,如果你的自动生成查,查所有,而不使用setSqlSelect()方法指定具体的字段时,如果你的实体中包含其它属性,但又没有使用exist时,会出现找不到列异常。避免该异常的方法就是指定exist为false,不过开发过程中,不管怎么样建议使用setSqlSelect()方法,因为sql优化。调用该方法指明需要字段就是进行最简单的sql优化。一个个简单的sql优化,对于一个系统还是很有威力的。

当然使用@TableField的场景是当你的实体属性与数据表不一致时,进行手动映射,如果一致,就会自动映射。

 

以上是关于MP实战系列之实体类讲解的主要内容,如果未能解决你的问题,请参考以下文章

MP实战系列之封装方法讲解

MP实战系列之DAO讲解

MP实战系列(十三)之批量修改操作(前后台异步交互)

Mybatis系列之实战篇(中)

Mybatis系列之实战篇(中)

NLP屠夫系列- NER之实战BILSTM