文章目录
- 1.sun-user引入依赖
- 2.标准三层架构EasyCode模板
- 1.Mapper.xml
- 2.Mapper.java
- 3.Req.java
- 4.Vo.java
- 5.Dto.java
- 6.Po.java
- 7.Service.java
- 8.ServiceImpl.java
- 9.Convert.java
- 10.Controller.java
- 11.PageInfo.java
- 12.PageResult.java
- 13.SunPageHelper.java
- 3.mapstruct常用操作
- 1.基本映射
- 2.**自定义属性映射**
- 3.**自定义属性类型转换**
- 4.**映射集合**
- 5.**继承映射**
- 6.**嵌套对象映射**
- 7.自定义default方法进行映射
- **1.使用 default 方法进行映射的步骤**
- 1.**定义映射接口**:
- 2.**使用** **@Mapper** **注解**:
- 3.**实现** **default** **方法**:
- 2.实例
- 1.假设我们有以下源对象和目标对象
- 2.**创建映射接口**
- 3.**解释**
- 4.**使用映射器**
1.sun-user引入依赖
<!-- fastjson --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.24</version></dependency><!-- mapstruct --><dependency><groupId>org.mapstruct</groupId><artifactId>mapstruct</artifactId><version>1.4.2.Final</version></dependency><dependency><groupId>org.mapstruct</groupId><artifactId>mapstruct-processor</artifactId><version>1.4.2.Final</version></dependency>
2.标准三层架构EasyCode模板
1.Mapper.xml
##定义全局逻辑删除字段名称
#set($deleteColumnName = "is_deleted")
##定义全局逻辑删除字段的删除值和未删除值
#set($deleteColumnValue = 1)
#set($notDeletedColumnValue = 0)##引入mybatis支持
$!{mybatisSupport.vm}##设置保存名称与保存位置
$!callback.setFileName($tool.append($!{tableInfo.name}, "Mapper.xml"))
$!callback.setSavePath($tool.append($modulePath, "/src/main/resources/mapper"))##拿到主键
#if(!$tableInfo.pkColumn.isEmpty())#set($pk = $tableInfo.pkColumn.get(0))
#end<?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="$!{tableInfo.savePackageName}.mapper.$!{tableInfo.name}Mapper"><resultMap type="$!{tableInfo.savePackageName}.entity.po.$!{tableInfo.name}Po" id="$!{tableInfo.name}Map"><id property="$!pk.name" column="$!pk.obj.name"/>
#foreach($column in $tableInfo.fullColumn)#if($column.name != $pk.name)<result property="$!column.name" column="$!column.obj.name"/>#end
#end</resultMap><!--根据主键查询一条记录--><select id="queryById" resultMap="$!{tableInfo.name}Map">select #allSqlColumn()from $!{tableInfo.obj.name}where $!pk.obj.name = #{$!pk.name}and $!deleteColumnName = $notDeletedColumnValue</select><!--分页查询指定行数据--><select id="queryPage" resultMap="$!{tableInfo.name}Map">select #allSqlColumn()from $!{tableInfo.obj.name}<where>
#foreach($column in $tableInfo.fullColumn)<if test="po.$!column.name != null#if($column.type.equals('java.lang.String')) and po.$!column.name != ''#end">and $!column.obj.name = #{po.$!column.name}</if>
#endand $!deleteColumnName = $notDeletedColumnValue</where>limit #{offset}, #{pageSize}</select><!--根据条件查询记录--><select id="queryAllByLimit" resultMap="$!{tableInfo.name}Map">select #allSqlColumn()from $!{tableInfo.obj.name}<where>
#foreach($column in $tableInfo.fullColumn)<if test="po.$!column.name != null#if($column.type.equals('java.lang.String')) and po.$!column.name != ''#end">and $!column.obj.name = #{po.$!column.name}</if>
#endand $!deleteColumnName = $notDeletedColumnValue</where></select><!--根据条件统计总行数--><select id="count" resultType="java.lang.Integer">select count(1)from $!{tableInfo.obj.name}<where>
#foreach($column in $tableInfo.fullColumn)<if test="po.$!column.name != null#if($column.type.equals('java.lang.String')) and po.$!column.name != ''#end">and $!column.obj.name = #{po.$!column.name}</if>
#endand $!deleteColumnName = $notDeletedColumnValue</where></select><!--新增一条记录--><insert id="insert" keyProperty="$!pk.name" useGeneratedKeys="true">insert into $!{tableInfo.obj.name}(#foreach($column in $tableInfo.otherColumn)$!column.obj.name#if($foreach.hasNext), #end#end)values (#foreach($column in $tableInfo.otherColumn)#{$!column.name}#if($foreach.hasNext), #end#end)</insert><!--批量新增多条记录--><insert id="insertBatch" keyProperty="$!pk.name" useGeneratedKeys="true">insert into $!{tableInfo.obj.name}(#foreach($column in $tableInfo.otherColumn)$!column.obj.name#if($foreach.hasNext), #end#end)values<foreach collection="entities" item="entity" separator=",">(#foreach($column in $tableInfo.otherColumn)#{entity.$!column.name}#if($foreach.hasNext), #end#end)</foreach></insert><!--插入记录,如果主键冲突,则变为更新记录--><insert id="insertOrUpdateBatch" keyProperty="$!pk.name" useGeneratedKeys="true">insert into $!{tableInfo.obj.name}(id, #foreach($column in $tableInfo.otherColumn)$!column.obj.name#if($foreach.hasNext), #end#end)values<foreach collection="entities" item="entity" separator=",">(#{entity.id}, #foreach($column in $tableInfo.otherColumn)#{entity.$!column.name}#if($foreach.hasNext), #end#end)</foreach>on duplicate key update
#foreach($column in $tableInfo.otherColumn)$!column.obj.name = values($!column.obj.name)#if($foreach.hasNext),#end
#end</insert><!--根据主键修改数据--><update id="updateById">update $!{tableInfo.obj.name}<set>
#foreach($column in $tableInfo.otherColumn)<if test="$!column.name != null#if($column.type.equals('java.lang.String')) and $!column.name != ''#end">$!column.obj.name = #{$!column.name},</if>
#end</set>where $!pk.obj.name = #{$!pk.name}and $!deleteColumnName = $notDeletedColumnValue</update><!--根据主键批量更新记录--><update id="updateBatchById"><foreach collection="list" item="item" index="index" open="" close="" separator=";">update $!{tableInfo.obj.name}<set>
#foreach($column in $tableInfo.otherColumn)<if test="item.$!column.name != null#if($column.type.equals('java.lang.String')) and item.$!column.name != ''#end">$!column.obj.name = #{item.$!column.name},</if>
#end</set>where $!pk.obj.name = #{item.$!pk.name}and $!deleteColumnName = $notDeletedColumnValue</foreach></update><!--根据主键逻辑删除单个记录--><update id="logicDeleteById">update $!{tableInfo.obj.name}set $!deleteColumnName = $deleteColumnValuewhere $!pk.obj.name = #{$!pk.name}and $!deleteColumnName = $notDeletedColumnValue</update><!--根据主键批量逻辑删除记录--><update id="logicDeleteBatchById">update $!{tableInfo.obj.name}set $!deleteColumnName = $deleteColumnValuewhere $!pk.obj.name in<foreach collection="list" item="id" open="(" separator="," close=")">#{id}</foreach>and $!deleteColumnName = $notDeletedColumnValue</update>
</mapper>
2.Mapper.java
## 设置保存名称与保存位置
$!callback.setFileName($tool.append($!{tableInfo.name}, "Mapper.java"))
$!callback.setSavePath($tool.append($modulePath, "/src/main/java/$!{tableInfo.savePackageName.replace('.','/')}/mapper"))## 拿到主键
#if(!$tableInfo.pkColumn.isEmpty())#set($pk = $tableInfo.pkColumn.get(0))
#end## 生成文件头
package $!{tableInfo.savePackageName}.mapper;import $!{tableInfo.savePackageName}.entity.po.$!{tableInfo.name}Po;
import org.apache.ibatis.annotations.Param;import java.util.List;/*** ($!{tableInfo.name})表数据库访问层** @author $!{author}* @since $!{time.currTime("yyyy-MM-dd HH:mm:ss")}*/
public interface $!{tableInfo.name}Mapper {/*** 通过ID查询单条数据** @param id 主键* @return 实例对象*/$!{tableInfo.name}Po queryById($!{pk.shortType} id);/*** 分页查询** @param po 查询条件* @param offset 偏移量:计算公式 (pageNo - 1) * pageSize* @param pageSize 页面大小* @return 对象列表*/List<$!{tableInfo.name}Po> queryPage(@Param("po") $!{tableInfo.name}Po po, @Param("offset") Integer offset, @Param("pageSize") Integer pageSize);/*** 根据条件查询记录** @param po 查询条件* @return 对象列表*/List<$!{tableInfo.name}Po> queryAllByLimit(@Param("po") $!{tableInfo.name}Po po);/*** 统计总行数** @param po 查询条件* @return 总行数*/Integer count($!{tableInfo.name}Po po);/*** 新增数据** @param po 实例对象(会封装新增的id)* @return 影响行数*/int insert($!{tableInfo.name}Po po);/*** 批量新增数据(MyBatis原生foreach方法)** @param entities 实例对象列表(会封装新增的id)* @return 影响行数*/int insertBatch(@Param("entities") List<$!{tableInfo.name}Po> entities);/*** 批量新增或按主键更新数据(MyBatis原生foreach方法)** @param entities 实例对象列表* @return 影响行数* @throws org.springframework.jdbc.BadSqlGrammarException 入参是空List的时候会抛SQL语句错误的异常,请自行校验入参*/int insertOrUpdateBatch(@Param("entities") List<$!{tableInfo.name}Po> entities);/*** 根据id修改数据** @param po 实例对象* @return 影响行数*/int update($!{tableInfo.name}Po po);/*** 通过主键删除数据** @param id 主键* @return 影响行数*/int deleteById($!{pk.shortType} id);}
3.Req.java
## 引入宏定义
$!{define.vm}## 设置保存名称与保存位置
$!callback.setFileName($tool.append($!{tableInfo.name}, "Req.java"))
$!callback.setSavePath($tool.append($tableInfo.savePath, "/entity/req"))## 拿到主键
#if(!$tableInfo.pkColumn.isEmpty())#set($pk = $tableInfo.pkColumn.get(0))
#end## 包声明和导入
#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.entity.req;
#endimport $!{tableInfo.savePackageName}.entity.page.PageInfo;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
## 检查是否包含 Date 类型的字段
#set($containsDate = false)
#foreach($column in $tableInfo.fullColumn)#if($tool.getClsNameByFullName($column.type) == "Date")#set($containsDate = true)#break#end
#end
## 如果包含 Date 类型的字段,导入 java.util.Date
#if($containsDate)
import java.util.Date;
#end/*** $!{tableInfo.comment}($!{tableInfo.name})Req实体类:接受前端请求** @author $!author* @since $!time.currTime()*/
@Data
@Accessors(chain = true) // 支持链式调用
public class $!{tableInfo.name}Req extends PageInfo implements Serializable {private static final long serialVersionUID = 1L;#foreach($column in $tableInfo.fullColumn)## 添加字段注释#if($column.comment)/*** $column.comment*/#endprivate $!{tool.getClsNameByFullName($column.type)} $!{column.name};#end
}
4.Vo.java
## 引入宏定义
$!{define.vm}## 设置保存名称与保存位置
$!callback.setFileName($tool.append($!{tableInfo.name}, "Vo.java"))
$!callback.setSavePath($tool.append($tableInfo.savePath, "/entity/vo"))## 拿到主键
#if(!$tableInfo.pkColumn.isEmpty())#set($pk = $tableInfo.pkColumn.get(0))
#end## 包声明和导入
#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.entity.vo;
#endimport lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
## 检查是否包含 Date 类型的字段
#set($containsDate = false)
#foreach($column in $tableInfo.fullColumn)#if($tool.getClsNameByFullName($column.type) == "Date")#set($containsDate = true)#break#end
#end
## 如果包含 Date 类型的字段,导入 java.util.Date
#if($containsDate)
import java.util.Date;
#end/*** $!{tableInfo.comment}($!{tableInfo.name})VO实体类:封装后端给前端的响应** @author $!author* @since $!time.currTime()*/
@Data
@Accessors(chain = true) // 支持链式调用
public class $!{tableInfo.name}Vo implements Serializable {private static final long serialVersionUID = 1L;#foreach($column in $tableInfo.fullColumn)## 添加字段注释#if($column.comment)/*** $column.comment*/#endprivate $!{tool.getClsNameByFullName($column.type)} $!{column.name};#end
}
5.Dto.java
## 引入宏定义
$!{define.vm}## 设置保存名称与保存位置
$!callback.setFileName($tool.append($!{tableInfo.name}, "Dto.java"))
$!callback.setSavePath($tool.append($tableInfo.savePath, "/entity/dto"))## 拿到主键
#if(!$tableInfo.pkColumn.isEmpty())#set($pk = $tableInfo.pkColumn.get(0))
#end## 包声明和导入
#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.entity.dto;
#endimport $!{tableInfo.savePackageName}.entity.page.PageInfo;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
## 检查是否包含 Date 类型的字段
#set($containsDate = false)
#foreach($column in $tableInfo.fullColumn)#if($tool.getClsNameByFullName($column.type) == "Date")#set($containsDate = true)#break#end
#end
## 如果包含 Date 类型的字段,导入 java.util.Date
#if($containsDate)
import java.util.Date;
#end/*** $!{tableInfo.comment}($!{tableInfo.name})Dto实体类:service层的入参,由Req转换而来** @author $!author* @since $!time.currTime()*/
@Data
@Accessors(chain = true) // 支持链式调用
public class $!{tableInfo.name}Dto extends PageInfo implements Serializable {private static final long serialVersionUID = 1L;#foreach($column in $tableInfo.fullColumn)## 添加字段注释#if($column.comment)/*** $column.comment*/#endprivate $!{tool.getClsNameByFullName($column.type)} $!{column.name};#end
}
6.Po.java
## 引入宏定义
$!{define.vm}## 设置保存名称与保存位置
$!callback.setFileName($tool.append($!{tableInfo.name}, "Po.java"))
$!callback.setSavePath($tool.append($tableInfo.savePath, "/entity/po"))## 拿到主键
#if(!$tableInfo.pkColumn.isEmpty())#set($pk = $tableInfo.pkColumn.get(0))
#end## 包声明和导入
#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.entity.po;
#endimport lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
## 检查是否包含 Date 类型的字段
#set($containsDate = false)
#foreach($column in $tableInfo.fullColumn)#if($tool.getClsNameByFullName($column.type) == "Date")#set($containsDate = true)#break#end
#end
## 如果包含 Date 类型的字段,导入 java.util.Date
#if($containsDate)
import java.util.Date;
#end/*** $!{tableInfo.comment}($!{tableInfo.name})PO实体类** @author $!author* @since $!time.currTime()*/
@Data
@Accessors(chain = true) // 支持链式调用
public class $!{tableInfo.name}Po implements Serializable {private static final long serialVersionUID = 1L;#foreach($column in $tableInfo.fullColumn)## 添加字段注释#if($column.comment)/*** $column.comment*/#endprivate $!{tool.getClsNameByFullName($column.type)} $!{column.name};#end
}
7.Service.java
## 引入宏定义
$!{define.vm}## 设置保存名称与保存位置
$!callback.setFileName($tool.append($!{tableInfo.name}, "Service.java"))
$!callback.setSavePath($tool.append($tableInfo.savePath, "/service"))## 拿到主键
#if(!$tableInfo.pkColumn.isEmpty())#set($pk = $tableInfo.pkColumn.get(0))
#end## 包声明和导入
#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.service;
#endimport $!{tableInfo.savePackageName}.entity.dto.$!{tableInfo.name}Dto;
import $!{tableInfo.savePackageName}.entity.page.PageResult;
import $!{tableInfo.savePackageName}.entity.vo.$!{tableInfo.name}Vo;/*** $!{tableInfo.comment}($!{tableInfo.name})service接口** @author $!author* @since $!time.currTime()*/
public interface $!{tableInfo.name}Service {/*** 分页查询** @param $!{tool.uncapitalize($!{tableInfo.name})}Dto 筛选条件* @return 查询结果*/PageResult<$!{tableInfo.name}Vo> queryByPage($!{tableInfo.name}Dto $!{tool.uncapitalize($!{tableInfo.name})}Dto);}
8.ServiceImpl.java
## 引入宏定义
$!{define.vm}## 设置保存名称与保存位置
$!callback.setFileName($tool.append($!{tableInfo.name}, "ServiceImpl.java"))
$!callback.setSavePath($tool.append($tableInfo.savePath, "/service/impl"))## 拿到主键
#if(!$tableInfo.pkColumn.isEmpty())#set($pk = $tableInfo.pkColumn.get(0))
#end## 包声明和导入
#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.service.impl;
#endimport $!{tableInfo.savePackageName}.convert.$!{tableInfo.name}Convert;
import $!{tableInfo.savePackageName}.entity.dto.$!{tableInfo.name}Dto;
import $!{tableInfo.savePackageName}.entity.page.PageResult;
import $!{tableInfo.savePackageName}.entity.page.SunPageHelper;
import $!{tableInfo.savePackageName}.entity.po.$!{tableInfo.name}Po;
import $!{tableInfo.savePackageName}.entity.vo.$!{tableInfo.name}Vo;
import $!{tableInfo.savePackageName}.mapper.$!{tableInfo.name}Mapper;
import $!{tableInfo.savePackageName}.service.$!{tableInfo.name}Service;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;/*** $!{tableInfo.comment}($!{tableInfo.name})service实现类** @author $!author* @since $!time.currTime()*/
@Service("$!tool.firstLowerCase($!{tableInfo.name})Service")
public class $!{tableInfo.name}ServiceImpl implements $!{tableInfo.name}Service {@Resourceprivate $!{tableInfo.name}Mapper $!tool.firstLowerCase($!{tableInfo.name})Mapper;/*** 分页查询** @param $!tool.firstLowerCase($!{tableInfo.name})Dto 筛选条件,需要携带pageNo和pageSize以及查询条件* @return 分页结果*/@Overridepublic PageResult<$!{tableInfo.name}Vo> queryByPage($!{tableInfo.name}Dto $!tool.firstLowerCase($!{tableInfo.name})Dto) {// 将dto转换为po$!{tableInfo.name}Po $!tool.firstLowerCase($!{tableInfo.name})Po = $!{tableInfo.name}Convert.INSTANCE.convertDtoToPo($!tool.firstLowerCase($!{tableInfo.name})Dto);// 使用 SunPageHelper 执行分页操作PageResult<$!{tableInfo.name}Po> paginate = SunPageHelper.paginate($!tool.firstLowerCase($!{tableInfo.name})Dto.getPageNo(), $!tool.firstLowerCase($!{tableInfo.name})Dto.getPageSize(),() -> $!tool.firstLowerCase($!{tableInfo.name})Mapper.count($!tool.firstLowerCase($!{tableInfo.name})Po),(offset, size) -> $!tool.firstLowerCase($!{tableInfo.name})Mapper.queryPage($!tool.firstLowerCase($!{tableInfo.name})Po, offset, size));// 将po转换为voPageResult<$!{tableInfo.name}Vo> $!tool.firstLowerCase($!{tableInfo.name})VoPageResult = $!{tableInfo.name}Convert.INSTANCE.convertPageResult(paginate);return $!tool.firstLowerCase($!{tableInfo.name})VoPageResult;}}
9.Convert.java
## 引入宏定义
$!{define.vm}## 设置保存名称与保存位置
$!callback.setFileName($tool.append($!{tableInfo.name}, "Convert.java"))
$!callback.setSavePath($tool.append($tableInfo.savePath, "/convert"))## 拿到主键
#if(!$tableInfo.pkColumn.isEmpty())#set($pk = $tableInfo.pkColumn.get(0))
#end## 包声明和导入
#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.convert;
#endimport $!{tableInfo.savePackageName}.entity.dto.$!{tableInfo.name}Dto;
import $!{tableInfo.savePackageName}.entity.page.PageResult;
import $!{tableInfo.savePackageName}.entity.po.$!{tableInfo.name}Po;
import $!{tableInfo.savePackageName}.entity.req.$!{tableInfo.name}Req;
import $!{tableInfo.savePackageName}.entity.vo.$!{tableInfo.name}Vo;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;/*** Description: $!{tableInfo.name}(转换器)* @Author $!{author}* @Create $!time.currTime()* @Version 1.0*/
@Mapper
public interface $!{tableInfo.name}Convert {// 生成一个具体的对象逻辑$!{tableInfo.name}Convert INSTANCE = Mappers.getMapper($!{tableInfo.name}Convert.class);// ============================== Req与Dto的转换 ==============================$!{tableInfo.name}Dto convertReqToDto($!{tableInfo.name}Req $!{tool.uncapitalize($!{tableInfo.name})}Req);$!{tableInfo.name}Req convertDtoToReq($!{tableInfo.name}Dto $!{tool.uncapitalize($!{tableInfo.name})}Dto);// ============================== Req与Dto的转换 ==============================// ============================== Dto与Po的转换 ==============================$!{tableInfo.name}Dto convertPoToDto($!{tableInfo.name}Po $!{tool.uncapitalize($!{tableInfo.name})}Po);$!{tableInfo.name}Po convertDtoToPo($!{tableInfo.name}Dto $!{tool.uncapitalize($!{tableInfo.name})}Dto);// ============================== Dto与Po的转换 ==============================// ============================== Po与Vo的转换 ==============================$!{tableInfo.name}Vo convertPoToVo($!{tableInfo.name}Po $!{tool.uncapitalize($!{tableInfo.name})}Po);$!{tableInfo.name}Po convertVoToPo($!{tableInfo.name}Vo $!{tool.uncapitalize($!{tableInfo.name})}Vo);List<$!{tableInfo.name}Vo> convertPoToVoList(List<$!{tableInfo.name}Po> $!{tool.uncapitalize($!{tableInfo.name})}PoList);List<$!{tableInfo.name}Po> convertVoToPoList(List<$!{tableInfo.name}Vo> $!{tool.uncapitalize($!{tableInfo.name})}VoList);// ============================== Po与Vo的转换 ==============================// ============================== PageResult的转换 ==============================default PageResult<$!{tableInfo.name}Vo> convertPageResult(PageResult<$!{tableInfo.name}Po> pageResultPo) {if (pageResultPo == null) {return null;}List<$!{tableInfo.name}Vo> voList = convertPoToVoList(pageResultPo.getResult());return new PageResult.Builder<$!{tableInfo.name}Vo>().pageNo(pageResultPo.getPageNo()).pageSize(pageResultPo.getPageSize()).total(pageResultPo.getTotal()).result(voList).build();}// ============================== PageResult的转换 ==============================
}
10.Controller.java
## 引入宏定义
$!{define.vm}## 设置保存名称与保存位置
$!callback.setFileName($tool.append($!{tableInfo.name}, "Controller.java"))
$!callback.setSavePath($tool.append($tableInfo.savePath, "/controller"))## 拿到主键
#if(!$tableInfo.pkColumn.isEmpty())#set($pk = $tableInfo.pkColumn.get(0))
#end## 包声明和导入
#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.controller;
#endimport com.alibaba.fastjson.JSON;
import com.sunxiansheng.response.Result;
import $!{tableInfo.savePackageName}.convert.$!{tableInfo.name}Convert;
import $!{tableInfo.savePackageName}.entity.dto.$!{tableInfo.name}Dto;
import $!{tableInfo.savePackageName}.entity.page.PageResult;
import $!{tableInfo.savePackageName}.entity.req.$!{tableInfo.name}Req;
import $!{tableInfo.savePackageName}.entity.vo.$!{tableInfo.name}Vo;
import $!{tableInfo.savePackageName}.service.$!{tableInfo.name}Service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;/*** $!{tableInfo.comment}($!{tableInfo.name})控制层** @author $!author* @since $!time.currTime()*/
@RestController
@RequestMapping("/$tool.hump2Underline($tool.firstLowerCase($tableInfo.name)).replace('_', '/')")
@Slf4j
public class $!{tableInfo.name}Controller {/*** 服务对象*/@Resourceprivate $!{tableInfo.name}Service $!tool.firstLowerCase($tableInfo.name)Service;/*** 分页查询数据** @param req 筛选条件* @return 查询结果*/@GetMapping("/queryPage")public Result<PageResult<$!{tableInfo.name}Vo>> queryByPage(@RequestBody $!{tableInfo.name}Req req) {try {// 打印日志if (log.isInfoEnabled()) {log.info("分页查询数据入参{}", JSON.toJSONString(req));}// ============================== Preconditions 参数校验 ==============================// ============================== Preconditions 参数校验 ==============================// 将req转换为dto(如果req的字段符合service层的规范,不转也可以)$!{tableInfo.name}Dto $!{tool.firstLowerCase($tableInfo.name)}Dto = $!{tableInfo.name}Convert.INSTANCE.convertReqToDto(req);// 调用service层PageResult<$!{tableInfo.name}Vo> $!{tool.firstLowerCase($tableInfo.name)}VoPageResult = this.$!{tool.firstLowerCase($tableInfo.name)}Service.queryByPage($!{tool.firstLowerCase($tableInfo.name)}Dto);return Result.ok($!{tool.firstLowerCase($tableInfo.name)}VoPageResult);} catch (Exception e) {// 打印error日志log.error("分页查询数据!错误原因{}", e.getMessage(), e);return Result.fail(e.getMessage());}}
}
11.PageInfo.java
##定义初始变量
#set($className = "PageInfo")
##设置回调
$!callback.setFileName($className + ".java")
$!callback.setSavePath($tool.append($tableInfo.savePath, "/entity/page"))
##包名
#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.entity.page;#endimport java.util.Objects;/*** Description: 分页请求的入参* @Author $!author* @Create $!time.currTime()* @Version 1.1*/
public class $className {private Integer pageNo = 1;private Integer pageSize = 20;public Integer getPageNo() {return (pageNo == null || pageNo < 1) ? 1 : pageNo;}public Integer getPageSize() {return (pageSize == null || pageSize < 1) ? 20 : pageSize;}public $className setPageNo(Integer pageNo) {this.pageNo = pageNo;return this;}public $className setPageSize(Integer pageSize) {this.pageSize = pageSize;return this;}@Overridepublic int hashCode() {return Objects.hash(pageNo, pageSize);}@Overridepublic String toString() {return "$className{" +"pageNo=" + pageNo +", pageSize=" + pageSize +'}';}
}
12.PageResult.java
##定义初始变量
#set($className = "PageResult")
##设置回调
$!callback.setFileName($className + ".java")
$!callback.setSavePath($tool.append($tableInfo.savePath, "/entity/page"))
##包名
#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.entity.page;#endimport java.util.Collections;
import java.util.List;import static java.util.Objects.requireNonNull;/*** Description: 分页返回的实体* @Author $!author* @Create $!time.currTime()* @Version 1.1*/
public class $className<T> {// 当前页码,默认为1private Integer pageNo = 1;// 每页显示的记录数,默认为20private Integer pageSize = 20;// 总记录条数private Integer total = 0;// 总页数private Integer totalPages = 0;// 当前页的记录列表private List<T> result = Collections.emptyList();// 表示当前页是从分页查询结果的第几条记录开始,下标从1开始private Integer start = 1;// 表示当前页是从分页查询结果的第几条记录结束,下标从1开始private Integer end = 0;// 私有构造函数,使用Builder创建实例private $className(Builder<T> builder) {this.pageNo = builder.pageNo;this.pageSize = builder.pageSize;this.total = builder.total;this.result = builder.result;calculateTotalPages();calculateStartAndEnd();}// Builder 模式实现public static class Builder<T> {private Integer pageNo = 1;private Integer pageSize = 20;private Integer total = 0;private List<T> result = Collections.emptyList();public Builder<T> pageNo(Integer pageNo) {this.pageNo = requireNonNull(pageNo, "Page number cannot be null");return this;}public Builder<T> pageSize(Integer pageSize) {this.pageSize = requireNonNull(pageSize, "Page size cannot be null");return this;}public Builder<T> total(Integer total) {this.total = requireNonNull(total, "Total count cannot be null");return this;}public Builder<T> result(List<T> result) {this.result = requireNonNull(result, "Result list cannot be null");return this;}public $className<T> build() {return new $className<>(this);}}// 计算总页数private void calculateTotalPages() {if (this.pageSize > 0) {this.totalPages = (this.total / this.pageSize) + (this.total % this.pageSize == 0 ? 0 : 1);} else {this.totalPages = 0;}}// 计算起始和结束位置private void calculateStartAndEnd() {if (this.pageSize > 0) {this.start = (this.pageNo - 1) * this.pageSize + 1;this.end = Math.min(this.pageNo * this.pageSize, this.total);} else {this.start = 1;this.end = this.total;}}// 获取当前页的起始位置public Integer getStart() {return start;}// 获取每页记录数public Integer getPageSize() {return pageSize;}// 获取当前页码public Integer getPageNo() {return pageNo;}// 获取总记录条数public Integer getTotal() {return total;}// 获取总页数public Integer getTotalPages() {return totalPages;}// 获取当前页的记录列表public List<T> getResult() {return result;}// 获取当前页的结束位置public Integer getEnd() {return end;}@Overridepublic String toString() {return "$className{" +"pageNo=" + pageNo +", pageSize=" + pageSize +", total=" + total +", totalPages=" + totalPages +", result=" + result +", start=" + start +", end=" + end +'}';}
}
13.SunPageHelper.java
##定义初始变量
#set($className = "SunPageHelper")
##设置回调
$!callback.setFileName($className + ".java")
$!callback.setSavePath($tool.append($tableInfo.savePath, "/entity/page"))
##包名
#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.entity.page;#endimport java.util.List;
import java.util.function.BiFunction;
import java.util.function.Supplier;/*** Description: 分页逻辑封装* @Author $!author* @Create $!time.currTime()* @Version 1.0*/
public class $className {/*** 执行分页操作* @param pageNo 页码* @param pageSize 每页记录数* @param totalSupplier 获取总记录条数的逻辑* @param recordsSupplier 获取记录列表的逻辑* @param <T> 记录的类型* @return 分页结果*/public static <T> PageResult<T> paginate(int pageNo, int pageSize,Supplier<Integer> totalSupplier,BiFunction<Integer, Integer, List<T>> recordsSupplier) {// 计算总记录数int total;try {total = totalSupplier.get();} catch (Exception e) {throw new RuntimeException("Failed to get total count", e);}// 如果总记录数为0,返回空的 PageResultif (total == 0) {return new PageResult.Builder<T>().pageNo(pageNo).pageSize(pageSize).total(total).result(Collections.emptyList()) // 空列表.build();}// 计算 offset,表示从第几条记录开始查询int offset = calculateOffset(pageNo, pageSize);// 获取当前页的记录列表List<T> records;try {records = recordsSupplier.apply(offset, pageSize);} catch (Exception e) {throw new RuntimeException("Failed to get records", e);}// 使用 Builder 模式创建 PageResult 对象并返回return new PageResult.Builder<T>().pageNo(pageNo).pageSize(pageSize).total(total).result(records).build();}/*** 计算分页的 offset* @param pageNo 页码* @param pageSize 每页记录数* @return offset*/public static int calculateOffset(int pageNo, int pageSize) {// offset 计算公式:(当前页码 - 1) * 每页记录数return (pageNo - 1) * pageSize;}
}
3.mapstruct常用操作
1.基本映射
- 自动映射具有相同名称和类型的属性
@Mapper
public interface UserMapper {UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);UserDTO toDTO(UserEntity entity);UserEntity toEntity(UserDTO dto);
}
2.自定义属性映射
- 使用 @Mapping 注解来处理属性名称不同的情况
@Mapper
public interface UserMapper {@Mapping(source = "fullName", target = "name")UserDTO toDTO(UserEntity entity);@Mapping(source = "name", target = "fullName")UserEntity toEntity(UserDTO dto);
}
3.自定义属性类型转换
- 使用自定义方法来处理不同类型的属性
@Mapper
public interface UserMapper {@Mapping(source = "age", target = "age", qualifiedByName = "stringToInt")UserDTO toDTO(UserEntity entity);@Mapping(source = "age", target = "age", qualifiedByName = "intToString")UserEntity toEntity(UserDTO dto);default int stringToInt(String age) {return Integer.parseInt(age);}default String intToString(int age) {return Integer.toString(age);}
}
4.映射集合
- 映射集合类型,如 List、Set 等
@Mapper
public interface UserMapper {List<UserDTO> toDTOList(List<UserEntity> entities);List<UserEntity> toEntityList(List<UserDTO> dtos);
}
5.继承映射
- 如果映射对象之间存在继承关系,MapStruct 也能处理这些情况。只要属性名称和类型相同,MapStruct 就会自动映射这些属性
public class BaseSource {private String id;// getters and setters
}public class Source extends BaseSource {private String name;private int age;// getters and setters
}public class BaseTarget {private String id;// getters and setters
}public class Target extends BaseTarget {private String name;private int age;// getters and setters
}@Mapper
public interface MyMapper {MyMapper INSTANCE = Mappers.getMapper(MyMapper.class);Target toTarget(Source source);
}
6.嵌套对象映射
- 对于嵌套对象映射,MapStruct 可以自动映射嵌套对象的属性,只要属性名称和类型相同
public class Address {private String street;private String city;// getters and setters
}public class Source {private String name;private Address address;// getters and setters
}public class Target {private String name;private Address address;// getters and setters
}@Mapper
public interface MyMapper {MyMapper INSTANCE = Mappers.getMapper(MyMapper.class);Target toTarget(Source source);
}
7.自定义default方法进行映射
1.使用 default 方法进行映射的步骤
1.定义映射接口:
首先,创建一个映射接口,并定义默认方法。
2.使用 @Mapper 注解:
在映射接口上使用 @Mapper 注解,指定接口为 MapStruct 映射器。
3.实现 default 方法:
在映射接口中实现 default 方法,以处理需要自定义逻辑的映射。
2.实例
1.假设我们有以下源对象和目标对象
public class Source {private String name;private String address;// getters and setters
}public class Target {private String name;private String address;private String formattedAddress;// getters and setters
}
2.创建映射接口
@Mapper
public interface MyMapper {MyMapper INSTANCE = Mappers.getMapper(MyMapper.class);// 映射 Source 到 TargetTarget toTarget(Source source);// 默认方法,用于格式化地址default String formatAddress(String address) {if (address == null) {return "Address not provided";}return "Formatted: " + address;}// 使用 @AfterMapping 注解在映射后调用默认方法@AfterMappingdefault void handleFormattedAddress(@MappingTarget Target target, Source source) {target.setFormattedAddress(formatAddress(source.getAddress()));}
}
3.解释
• toTarget 方法:这是一个简单的映射方法,将 Source 映射到 Target。
• formatAddress 方法:这是一个 default 方法,用于格式化地址。
• handleFormattedAddress 方法:使用 @AfterMapping 注解在映射后调用 formatAddress 方法,将格式化后的地址设置到目标对象中。
4.使用映射器
public class Main {public static void main(String[] args) {Source source = new Source();source.setName("John Doe");source.setAddress("123 Main St");Target target = MyMapper.INSTANCE.toTarget(source);System.out.println("Name: " + target.getName());System.out.println("Address: " + target.getAddress());System.out.println("Formatted Address: " + target.getFormattedAddress());}
}