preface

Generally speaking, a service system rarely uses physical deletion for operations on tables. Therefore, when a table is being created, a delete status is added by default for logical deletion. If the data has been deleted, it will not be displayed on the service system. Therefore, it is necessary to add the undeleted condition to each query condition. It is really inconvenient to manually add the condition for each query. Take a look at the generic Mapper, a persistence framework that supports logical deletion.

The mapper logic is deleted

Mapper logical delete configuration is relatively simple, just need to add @logicDELETE annotation on the logical delete field. LogicDelete in tk. Mybatis. Mapper. The annotation.

Example Configuration:

@LogicDelete(isDeletedValue=1,notDeletedValue=2)
private Integer isDeleted;
Copy the code
field type describe
isDeletedValue int Deleted value, default 1
notDeletedValue int Undeleted value, default 0

Query example:

sysUserMapper.selectAll();
Copy the code

Query automatically built SQL:

SELECT id,user_name,real_name,avatar,email,mobile_phone,telephone,password.salt,sex,is_locked,create_time,update_time,is_deleted FROM sys_user WHERE is_deleted = 2 
Copy the code

Enumeration type specification

We do development often encounter this problem: the database field certain values are fixed a few values, standard practice is the direct deposit type int, then business code defining constants or enumeration class, this way is also pretty good actually, but requires human to maintain constant class or enumeration, a bit not convenient. Let’s talk about what we do in this framework.

Look at the table:

CREATE TABLE `sys_user` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'primary key',
  `user_name` varchar(32) NOT NULL COMMENT 'Username',
  `real_name` varchar(32) DEFAULT NULL COMMENT 'name',
  `avatar` varchar(200) DEFAULT NULL COMMENT 'avatar',
  `email` varchar(64) DEFAULT NULL COMMENT 'email',
  `mobile_phone` varchar(11) DEFAULT NULL COMMENT 'Mobile phone Number',
  `telephone` varchar(20) DEFAULT NULL COMMENT 'phone',
  `password` varchar(40) DEFAULT NULL COMMENT 'password',
  `salt` varchar(10) DEFAULT NULL COMMENT 'salt',
  `sex` int(6) unsigned DEFAULT '1' COMMENT 'gender (1 - > | MALE MALE, FEMALE 2 - > | FEMALE, 3 - > | UNKNOWN UNKNOWN)',
  `is_locked` tinyint(1) unsigned DEFAULT '2' COMMENT 'whether the lock (1 - > has targeted | YES, 2 - > unlocked | NO)',
  `create_time` datetime DEFAULT NULL COMMENT 'Creation time',
  `update_time` datetime DEFAULT NULL COMMENT 'Update Time',
  `is_deleted` tinyint(1) unsigned DEFAULT '1' COMMENT 'whether delete (1 - > not delete | NO, 2 - > deleted | YES)'.PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT COMMENT='users';
Copy the code

From the table above, we can see that the annotations for three fields are different from the others: SEX, is_locked, and IS_deleted. This comment is my own specification. Let me elaborate here.

Dictionary (name, unique code)

name key Enumeration class
gender sys_user_sex SysUser.SexEnum
Whether the lock sys_user_is_locked SysUser.IsLockedEnum
Whether or not to delete sys_user_is_deleted SysUser.IsDeletedEnum

Note: Whether schema can define only one global YES_NO ->YesNoEnum

The name is the comment, and the unique encoding is the table name _ field

Dictionary entries (name, unique code, value)

Take gender:

The name of the The only coding value
male MALE 1
female female 2
The unknown UNKNOWN 3

Once the metadata is present in the comment, the code generator takes care of generating the code, as described later in the code generator section.

Start coding

The directory structure

List only files that need to be added or modified

├ ─ ─ mldong - admin management end interface ├ ─ ─ SRC/main/Java └ ─ ─ the mldong. Modules. Sys └ ─ ─ service service layer └ ─ ─ impl └ ─ ─ SysUserServiceImpl └ ─ ─ SRC /main/ Resources ├─ ├─ ├─ class exercises, ├─ class Exercises, exercises, exercises, exercises, exercises, exercises, exercises, exercises SRC /main/ Java ├─ com.ml.base ├─ CodeFlag. Java ├─ com.ml.base ├─ code Flag CodedEnumTypeHandle. Java └ ─ ─ YesNoEnum. Java └ ─ ─ the mldong. Modules. Sys. Entity └ ─ ─ SysUser, JavaCopy the code

Document describing

  • mldong-mapper/src/main/java/com/mldong/annotation/DictEnum.java

Define annotations, like ErrEnum before it, to scan into memory for subsequent queries and dictionary interfaces. The modified files should be in the MLDong-Framework layer, but there are not many of them, so they will be in the MLDong-Mapper layer for now. The reason why it is not placed in mlDong-common layer is that mlDong-Mapper will be introduced later in MLDong-common, and modules cannot depend on each other. So…

package com.mldong.annotation;

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

/** * dictionary enumeration class annotations to facilitate collection of * for use as dictionaries@author mldong
 *
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface DictEnum {
	/** * name *@return* /
	String name(a);
	/** ** Unique identifier *@return* /
	String key(a);
}
Copy the code
  • mldong-mapper/src/main/java/com/mldong/base/CodedEnum.java

Dictionary code interface, and provides a value to enumeration method

package com.mldong.base;

import java.util.Arrays;
import java.util.Optional;

public interface CodedEnum {
    int getValue(a);
    String getName(a);
    public static<E extends Enum<? > & CodedEnum>Optional<E> codeOf(Class<E> enumClass, int code) {
        returnArrays.stream(enumClass.getEnumConstants()).filter(e -> e.getValue() == code).findAny(); }}Copy the code
  • mldong-mapper/src/main/java/com/mldong/base/CodedEnumTypeHandle.java
package com.mldong.base;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Optional;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedTypes;
/** * mybatis enumeration class *@author mldong
 *
 * @param <E>
 */
@MappedTypes({CodedEnum.class})
public class CodedEnumTypeHandler<E extends Enum<? > &CodedEnum> extends BaseTypeHandler<E> {
    private Class<E> type;

    public CodedEnumTypeHandler(Class<E> type) {
        if (type == null) {
            throw new IllegalArgumentException("Type argument cannot be null");
        }
        this.type = type;
    }

	@Override
	public void setNonNullParameter(PreparedStatement ps, int i, E parameter,
			JdbcType jdbcType) throws SQLException {
		if (parameter == null) {
            ps.setNull(i, Types.TINYINT);
        } else{ ps.setInt(i, parameter.getValue()); }}@Override
	public E getNullableResult(ResultSet rs, String columnName)
			throws SQLException {
		int columnValue = rs.getInt(columnName);
        return rs.wasNull() ? null : enumOf(columnValue);
	}

	@Override
	public E getNullableResult(ResultSet rs, int columnIndex)
			throws SQLException {
		int columnValue = rs.getInt(columnIndex);
        return rs.wasNull() ? null : enumOf(columnValue);
	}

	@Override
	public E getNullableResult(CallableStatement cs, int columnIndex)
			throws SQLException {
		int columnValue = cs.getInt(columnIndex);
        return cs.wasNull() ? null : enumOf(columnValue);
	}
    private E enumOf(int code) {
        final Optional<E> codedEnumOpt = CodedEnum.codeOf(type, code);
        if (codedEnumOpt.isPresent()) {
            return codedEnumOpt.get();
        } else {
            throw new IllegalArgumentException("Cannot convert " + code + " to " + type.getSimpleName() + " by code value."); }}}Copy the code
  • mldong-mapper/src/main/java/com/mldong/base/YesNoEnum.java

Yes or no model, corresponding, such as: whether to delete (1 – > not delete | no, 2 – > deleted | yes)

package com.mldong.base;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
/**
 * yes_no
 * @author mldong
 *
 */
public enum YesNoEnum implements CodedEnum{
	/**
	 * 是
	 */
	YES(1."Yes"),
	/**
	 * 否
	 */
	NO(2."No." ");private int value;
	private String name;
	/** ** not deleted */
	public final static int Y=1;
	/** ** deleted */
	public final static int N=2;
	@JsonCreator
    public static YesNoEnum forValue(int value) {
        return CodedEnum.codeOf(YesNoEnum.class, value).get();

    }
	YesNoEnum(int value, String name) {
		this.value = value;
		this.name = name;
	}
	@JsonValue
	public int getValue(a) {
		return value;
	}
	public String getName(a) {
		returnname; }}Copy the code
  • mldong-mapper/src/main/java/com/mldong/modules/sys/entity/SysUser.java

The entity class is modified accordingly

package com.mldong.modules.sys.entity;

import io.swagger.annotations.ApiModelProperty;

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

import javax.persistence.Id;
import javax.persistence.Table;

import tk.mybatis.mapper.annotation.LogicDelete;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import com.mldong.annotation.DictEnum;
import com.mldong.base.CodedEnum;
import com.mldong.base.YesNoEnum;
/** * User table entity *@author mldong
 *
 */
@Table(name="sys_user")
public class SysUser implements Serializable{
	/ * * * * /
	private static final long serialVersionUID = -2687095050668229447L;
	@Id
	@ApiModelProperty(value="Primary key")
	private Long id;
	@ApiModelProperty(value="Username")
	private String userName;
	@ApiModelProperty(value="Name")
	private String realName;
	@ApiModelProperty(value="Avatar")
	private String avatar;
	@ApiModelProperty(value="Email")
	private String email;
	@ApiModelProperty(value="Mobile phone Number")
	private String mobilePhone;
	@ApiModelProperty(value="Contact Number")
	private String telephone;
	@ApiModelProperty(value="Password")
	private String password;
	@ApiModelProperty(value="Salt")
	private String salt;
	@ApiModelProperty(value="Gender")
	private Integer sex;
	@ApiModelProperty(value="Locked or not locked")
	private YesNoEnum isLocked;
	@ApiModelProperty(value="Creation time")
	private Date createTime;
	@ApiModelProperty(value="Update Time")
	private Date updateTime;
	@LogicDelete(isDeletedValue=YesNoEnum.Y,notDeletedValue=YesNoEnum.N)
	@ApiModelProperty(value="Delete or not")
	private YesNoEnum isDeleted;
	/ / get the set slightly
	@DictEnum(name="Gender", key="sys_user_sex")
	public enum SexEnum implements CodedEnum {
		
		/ * * * * /
		MALE(1."Male"),
		/ * * * female * /
		FEMALE(2."Female"),
		/** * unknown */
		UNKNOWN(3."Unknown"),;private int value;
		private String name;
		@JsonCreator // STR ->json, value->enums
	    public static SexEnum forValue(int value) {
	        return CodedEnum.codeOf(SexEnum.class, value).get();

	    }
		SexEnum(int value, String name) {
			this.value = value;
			this.name = name;
		}
		@JsonValue // json-> STR, enums->value
		public int getValue(a) {
			return value;
		}
		public String getName(a) {
			returnname; }}}Copy the code
  • mldong-admin/src/main/java/com/mldong/modules/sys/service/impl/SysUserServiceImpl.java

The corresponding add and delete methods need to be modified

package com.mldong.modules.sys.service.impl;

import java.util.Date;
import java.util.List;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import tk.mybatis.mapper.entity.Condition;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.mldong.base.YesNoEnum;
import com.mldong.common.base.CommonPage;
import com.mldong.modules.sys.dto.SysUserParam;
import com.mldong.modules.sys.entity.SysUser;
import com.mldong.modules.sys.mapper.SysUserMapper;
import com.mldong.modules.sys.service.SysUserService;
/** * User management services *@author mldong
 *
 */
@Service
public class SysUserServiceImpl implements SysUserService{
	@Autowired
	private SysUserMapper sysUserMapper;
	@Override
	public int save(SysUserParam param) {
		Date now = new Date();
		SysUser user = new SysUser();
		BeanUtils.copyProperties(param, user);
		user.setCreateTime(now);
		user.setUpdateTime(now);
		user.setIsDeleted(YesNoEnum.NO);
		return sysUserMapper.insertSelective(user);
	}

	@Override
	public int update(SysUserParam param) {
		Date now = new Date();
		SysUser user = new SysUser();
		BeanUtils.copyProperties(param, user);
		user.setUpdateTime(now);
		return sysUserMapper.updateByPrimaryKeySelective(user);
	}

	@Override
	public int remove(List<Long> ids) {
		Date now = new Date();
		SysUser upUser = new SysUser();
		upUser.setIsDeleted(YesNoEnum.YES);
		upUser.setUpdateTime(now);
		Condition condition = new Condition(SysUser.class);
		condition.createCriteria().andIn("id", ids);
		return sysUserMapper.updateByConditionSelective(upUser, condition);
	}

	@Override
	public SysUser get(Long id) {
		return sysUserMapper.selectByPrimaryKey(id);
	}
	@Override
	public CommonPage<SysUser> list(SysUserParam param, int pageNum, int pageSize) {
		Page<SysUser> page = PageHelper.startPage(pageNum, pageSize,true);
		SysUser user = new SysUser();
		BeanUtils.copyProperties(param, user);
		sysUserMapper.select(user);
		returnCommonPage.toPage(page); }}Copy the code
  • mldong-admin/src/main/java/resources/application.yml

Configure default – enum – type – handler

# mybatis configure mybatis: type-aliases-package: com.mldong.modules.*.mapper.*,com.mldong.modules.*.dao.*,com.mldong.modules.*.repo.* mapper-locations: classpath*:mapper/*/*.xml,classpath*:dao/*/*.xml,classpath*:repo/*/*.xml configuration: map-underscore-to-camel-case: true default-enum-type-handler: com.mldong.base.CodedEnumTypeHandlerCopy the code

Start running the project

MldongAdminApplication.java

Right-click ->Run As -> Java Application

Access to demonstrate

slightly

Project source code address

  • The back-end

Gitee.com/mldong/mldo…

  • The front end

Gitee.com/mldong/mldo…

Related articles

Create a suitable for their own rapid development framework – the pilot

Build a suitable for their own rapid development framework – back-end scaffolding

Build a fast development framework for yourself – integrated Mapper

Build a fast development framework for yourself – integration with Swaggerui and KNIfe4J

Build a suitable for their own rapid development framework – universal class packaging unified result return, unified exception handling

Create a quick development framework for yourself – business error code specifications and practices

Build a quick development framework for yourself – framework layering and CURD sample