com.poyee.base 包是 Poyee Checklist 项目的核心基础框架,提供了一套完整的分层架构实现,包括控制层(Controller)、服务层(Service)、数据访问层(Mapper)以及相关的数据传输对象(DTO)、请求对象(Req)和实体对象(Entity)。该框架采用了面向对象的设计思想,通过抽象基类和泛型机制,实现了代码复用和业务逻辑的统一管理。
BaseController
BaseController 是所有控制器的基类,提供了通用的请求处理和日志记录功能。
public abstract class BaseController<S extends BaseService<T, R>, T extends BaseReq, R extends BaseDto> {
@Autowired
protected S baseService;
// 日志记录
public void console(String label, Object obj) { ... }
// 分页查询
public Result<R> listPage(T req, boolean checkUser) { ... }
// 详情查询
public Result<R> info(Integer id) { ... }
// 获取请求对象
public HttpServletRequest getRequest() { ... }
}
BaseService 接口
BaseService 接口定义了服务层的通用方法,包括查询、分页、计数等操作。
public interface BaseService<T extends BaseReq, R extends BaseDto> extends IService<R> {
Result<R> listPage(T req, boolean checkUser);
List<R> selectJoinAllList(MPJLambdaWrapper<R> wrapper, T req);
QueryWrapper<R> checkWrapper(T req, boolean checkUser);
Long selectCount(MPJLambdaWrapper<R> wrapper);
List<R> getAllList(T req, boolean checkUser);
Result<R> info(Integer id);
Result<R> getOne(T req);
Result<R> getOneDto(T req);
UserInfo getUserInfo();
<Q extends BaseReq> IPage<R> ipage(MPJLambdaWrapper<R> wrapper, Q req);
<Q extends BaseReq> Result<R> ipageResult(MPJLambdaWrapper<R> wrapper, Q req);
MPJLambdaWrapper<R> mpjWrapper(Object req);
MPJLambdaWrapper<R> mpjWrapper(Object req, String alias);
MPJLambdaWrapper<R> mpjWrapper(MPJLambdaWrapper<R> mpjLambdaWrapper, Object req, String alias);
}
BaseServiceImpl 实现类
BaseServiceImpl 是 BaseService 接口的实现类,提供了各种通用方法的具体实现。
public class BaseServiceImpl<M extends IBaseMapper<R>, T extends BaseReq, R extends BaseDto>
extends ServiceImpl<M, R> implements BaseService<T, R> {
// 检查用户权限
public <P extends BaseReq> void checkAndSetUserId(P p) { ... }
// 分页查询
@Override
public Result<R> listPage(T req, boolean checkUser) { ... }
// 获取单条数据
@Override
public Result<R> info(Integer id) { ... }
// 构建查询条件
@Override
public QueryWrapper<R> checkWrapper(T req, boolean checkUser) { ... }
// 构建MPJ查询条件
@Override
public MPJLambdaWrapper<R> mpjWrapper(Object req) { ... }
}
IBaseMapper 接口
IBaseMapper 接口继承了 MyBatis-Plus 的 BaseMapper 和 MPJBaseMapper,提供了基础的数据库操作方法。
public interface IBaseMapper<T> extends BaseMapper<T>, MPJBaseMapper<T> {
// 基础方法由 BaseMapper 和 MPJBaseMapper 提供
}
IBaseProvider 接口
IBaseProvider 接口定义了动态 SQL 构建的方法,用于复杂查询场景。
public interface IBaseProvider<T extends BaseReq, R extends BaseDto> {
List<Map<String, Object>> selectListMap(@Param("req") T req, @Param("clazz") Class<R> clazz);
long pageCount(String sql);
List<Map<String, Object>> page(String sql);
Map<String, Object> selectOneMap(@Param("req") T req, @Param("clazz") Class<R> clazz);
Map<String, Object> selectByIdMap(@Param("id") Serializable id, @Param("clazz") Class<R> clazz);
Map<String, Object> selectSumMap(@Param("req") T req, @Param("clazz") Class<R> clazz);
int save(T req);
int update(T req);
}
BaseProvider 实现类
BaseProvider 是 IBaseProvider 接口的抽象实现,提供了 SQL 构建的核心功能。
public abstract class BaseProvider {
// 数据库操作类型
public DbMethodEnums dbMethod;
// 表计数器
public int tableCount = 0;
// 是否分页
public boolean isPage = false;
// 存储 insert
public Object insert;
// 记录 UPDATE
public Object update;
// 记录 SELECT
public Object select;
// 主表信息
public TableInfo superTable;
// 分页查询
public MPage mPage;
// 标记是否前端传排序字段
public boolean isFrontSort = false;
// 分页查询
public String pageCountSql;
// 记录 INSERT key-value(线程安全)
public final Map<String, Object> insertMap = new HashMap<>();
// 记录 UPDATE key-value(线程安全)
public final Map<String, Object> updateMap = new HashMap<>();
// 存储表信息的映射(线程安全)
public final Map<String, TableInfo> tableInfos = new ConcurrentHashMap<>();
// 记录 WHERE 条件(线程安全)
public final List<WhereInfo> whereInfos = new CopyOnWriteArrayList<>();
// 记录 SELECT 列(线程安全)
public final List<String> selectColumns = new CopyOnWriteArrayList<>();
// 记录 LEFT JOIN 信息(线程安全)
public final List<LeftJoinInfo> leftJoinInfos = new CopyOnWriteArrayList<>();
// 记录 ORDER BY 信息(线程安全)
// ...
}
BaseReq 是所有请求对象的基类,提供了分页、排序等通用参数。
@Data
public class BaseReq {
@ApiModelProperty(hidden = true)
@TableField(exist = false)
public static List<String> types = Arrays.asList("pageNo", "pageSize", "sidx", "sord", "orderBy", "limit", "desensit");
@ApiModelProperty(value = "页码,查询时使用", notes = "查询时使用", reference = "1", example = "1")
@TableField(exist = false)
private Integer pageNo = 1;
@ApiModelProperty(value = "每页数量,查询时使用", notes = "查询时使用", reference = "10", example = "10")
@TableField(exist = false)
private Integer pageSize = 10;
@ApiModelProperty(value = "排序字段,查询时使用", notes = "查询时使用", reference = " createTime ")
@TableField(exist = false)
private String sidx;
@ApiModelProperty(value = "排序规则,查询时使用", notes = "查询时使用", reference = " ase ")
@TableField(exist = false)
private String sord;
@ApiModelProperty(hidden = true)
@TableField(exist = false)
private String orderBy;
@ApiModelProperty(hidden = true)
@TableField(exist = false)
private Integer limit;
public Integer getLimit() {
return (pageNo - 1) * pageSize;
}
}
BaseDto 是所有数据传输对象的基类,通常包含实体的基本属性和一些扩展属性。
@Data
public class BaseDto {
// 基础属性
}
BaseEntity 是所有实体对象的基类,提供了分页、排序等通用参数。
@Data
public class BaseEntity {
@ApiModelProperty(hidden = true)
@TableField(exist = false)
public static List<String> types = Arrays.asList("pageNo", "pageSize", "sidx", "sord", "orderBy", "limit", "desensit");
@ApiModelProperty(value = "页码,查询时使用", notes = "查询时使用", reference = "1")
@TableField(exist = false)
private Integer pageNo = 1;
@ApiModelProperty(value = "每页数量,查询时使用", notes = "查询时使用", reference = "10")
@TableField(exist = false)
private Integer pageSize = 10;
@ApiModelProperty(value = "排序字段,查询时使用", notes = "查询时使用", reference = " createTime ")
@TableField(exist = false)
private String sidx;
@ApiModelProperty(value = "排序规则,查询时使用", notes = "查询时使用", reference = " ase ")
@TableField(exist = false)
private String sord;
@ApiModelProperty(hidden = true)
@TableField(exist = false)
private String orderBy;
@ApiModelProperty(hidden = true)
@TableField(exist = false)
private Integer limit;
public static boolean notIn(String type) {
return !types.contains(type);
}
public Integer getLimit() {
return (pageNo - 1) * pageSize;
}
}
Result 是统一的响应结果对象,用于封装接口返回数据。
@Data
@ApiModel("通用返回结果")
@JsonIgnoreProperties(ignoreUnknown = true)
public class Result<T> implements Serializable {
@ApiModelProperty("是否成功")
private boolean success;
@ApiModelProperty("状态码")
private Integer code;
@ApiModelProperty("返回消息")
private String msg;
@ApiModelProperty("返回数据")
private T data;
@ApiModelProperty("总记录数")
private Long total;
// 静态工厂方法
public static Result ok() { ... }
public static <R extends BaseDto> Result<R> ok(R data) { ... }
public static Result error(String msg) { ... }
public static Result error(Integer code, String msg) { ... }
public static <R extends BaseDto> Result<R> page(IPage<R> iPage) { ... }
// ...
}
UserInfo 封装了当前登录用户的信息,用于权限控制和数据过滤。
@Data
@ToString
public class UserInfo implements Serializable {
// 用户ID
private Integer id;
// 用户ID
private String userId;
// 用户头像
private String avatar;
// 角色编码
private String roleCode;
// 角色编码
private String role;
// 请求时间
private Long iat;
// 过期时间
private Long exp;
// 名称
private String displayName;
// ...
// 商家ID
private Integer merchantId;
// 商家头像
private String merchantAvatar;
// 商家名称
private String merchantName;
// 数据权限
private DataAuth dataAuth;
// 是否是商家
private boolean merchant;
// ...
// 判断是否有合作伙伴角色权限
public boolean hasPartnerRoleAuth(Roles role) { ... }
}
i18n 注解
i18n 注解用于标记需要国际化的字段、方法或类。
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface i18n {
boolean value() default true;
String sheetName() default "";
I18nFormat[] format() default {};
}
I18nUtils 工具类
I18nUtils 提供了获取国际化消息的方法。
@Configuration
public class I18nUtils {
// 定义占位符的正则表达式模式
private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("\\{(\\d+)\\}");
private MessageProperties messageProperties;
// 存储消息的Map,键是消息键,值是包含语言和消息的Map
private static Map<String, Map<String, String>> messages;
// 初始化国际化工具类,并加载消息属性
@Autowired
public I18nUtils(MessageProperties messageProperties) { ... }
// 根据枚举和参数获取国际化消息
public static String get(I18nMessageEnums i18n, Object... args) { ... }
// ...
}
I18nMessageEnums 枚举
I18nMessageEnums 定义了系统中所有的国际化消息。
@Getter
public enum I18nMessageEnums {
// 请求成功
SUCCESS("success", "成功", "zh"),
// 请求失败
REQUEST_ERROR("request_error", "请求失败", "zh"),
// 无权操作
NO_PERMISSION("no_permission", "无权操作{0}", "zh"),
// ...
private String code; // 多语言标识
private String message; // 默认信息
private String lang; // 默认语言
I18nMessageEnums(String code, String message, String lang) { ... }
}
ServletUtils 提供了获取请求、响应、会话以及用户信息的方法。
public class ServletUtils {
// 获取请求对象
public static HttpServletRequest getRequest() { ... }
// 获取响应对象
public static HttpServletResponse getResponse() { ... }
// 获取会话对象
public static HttpSession getSession() { ... }
// 获取用户信息
public static UserInfo getUserInfo() { ... }
// 判断是否国际版
public static boolean isI18n() { ... }
// 判断接口是否支持国际版
public static boolean isI18nSupport() { ... }
// ...
}
Select 注解
Select 注解用于指定查询字段。
@Select(table = UserEntity.class, fieldName = "username", distinct = true)
private String username;
Where 注解
Where 注解用于指定查询条件。
@Where(fieldName = "status", operator = EQ)
private String status;
LeftJoin 注解
LeftJoin 注解用于指定左连接查询。
@LeftJoin(table = RoleEntity.class, leftTable = UserEntity.class, fieldName = "id", leftFieldName = "roleId")
private String roleName;
OrderBy 注解
OrderBy 注解用于指定排序字段。
@OrderBy(fieldName = "createTime", sort = "DESC")
private String createTime;
@Slf4j
@Api(value = "球队基础信息管理", tags = "球队基础信息管理")
@RestController
@RequestMapping("/api/v1/teamInfo")
public class TeamBaseInfoController extends BaseController<TeamBaseInfoService, TeamBaseInfoReq, TeamBaseInfoDto> {
@ApiOperation(value = "详情", notes = "详情")
@ApiResponses({
@ApiResponse(code = 200, message = "返回结果:")
})
@Log(title = "详情", businessType = BusinessType.UPDATE)
@UserLoginToken(faceVerify = false, roles = {Roles.ADMIN, Roles.SHIPPING, Roles.CUSTOMER})
@i18n(format = {I18nFormat.SEARCH}) // 支持国际化
@PostMapping("/detail/{id}")
public Result<TeamBaseInfoDto> detail(@PathVariable("id") Long id) {
return baseService.detail(id);
}
}
public interface TeamBaseInfoService extends BaseService<TeamBaseInfoReq, TeamBaseInfoDto> {
Page<TeamInfoPageDto> page(TeamInfoPageReq req);
Result add(TeamInfoCreateReq req);
Result update(TeamInfoUpdateReq req);
Result delete(RemoveInfoReq req);
List<TeamBaseInfoDto> searchTeamInfosByTeamSimpleName(TeamBaseInfoReq req);
List<TeamBaseInfoDto> getByIds(List<Long> ids);
}
@Slf4j
@Service
public class TeamBaseInfoServiceImpl extends BaseServiceImpl<TeamBaseInfoMapper, TeamBaseInfoReq, TeamBaseInfoDto> implements TeamBaseInfoService {
@Override
public Result add(TeamInfoCreateReq req) {
// 格式化简称
String simpleName = ObjectUtil.getSimpleName(req.getNameEn());
// 查询是否已经存在该名称
TeamBaseInfoDto dto = (TeamBaseInfoDto) baseMapper.selectOne(
new TeamBaseInfoReq(req.getSport(), simpleName), TeamBaseInfoDto.class);
if (Objects.nonNull(dto) && Objects.nonNull(dto.getId())) {
return Result.error(I18nUtils.get(DATA_EXIST, req.getNameEn()));
}
req.setSimpleName(simpleName);
return Result.ret(baseMapper.insert(req));
}
@Override
public Result update(TeamInfoUpdateReq req) {
// 实现更新逻辑
// ...
return Result.ret(baseMapper.updateById(dto));
}
// 其他方法实现
// ...
}
public interface TeamBaseInfoMapper extends IBaseMapper<TeamBaseInfoDto>, IBaseProvider<TeamBaseInfoReq, TeamBaseInfoDto> {
// 可以添加自定义的查询方法
}
@Data
@ApiModel(value = "球队基础信息请求参数", description = "球队基础信息请求参数")
@TableName("tzy_team_info")
public class TeamBaseInfoReq extends BaseReq {
@ApiModelProperty(value = "运动")
@TableField(value = "sport")
@Where(fieldName = "sport", operator = EQ)
private String sport;
@ApiModelProperty(value = "简称")
@TableField(value = "simple_name")
@Where(fieldName = "simple_name", operator = EQ)
private String simpleName;
// 构造方法
public TeamBaseInfoReq() {}
public TeamBaseInfoReq(String sport, String simpleName) {
this.sport = sport;
this.simpleName = simpleName;
}
}
@Data
@ApiModel(value = "球队基础信息返回参数", description = "球队基础信息返回参数")
@TableName("tzy_team_info")
public class TeamBaseInfoDto extends BaseDto {
@ApiModelProperty(value = "ID")
@TableId(value = "id")
private Long id;
@ApiModelProperty(value = "区分是否商家创建:merchant=商家创建")
@TableField(value = "code")
private String code;
@ApiModelProperty(value = "中文名")
@TableField(value = "display_name")
private String displayName;
@ApiModelProperty(value = "英文名")
@TableField(value = "display_name_en")
private String displayNameEn;
@ApiModelProperty(value = "运动")
@TableField(value = "sport")
private String sport;
@ApiModelProperty(value = "头像")
@TableField(value = "head_url")
private String headUrl;
@ApiModelProperty(value = "国际化:其他语言翻译:json 字符串")
@TableField(value = "translations")
private String translations;
@ApiModelProperty(value = "简称")
@TableField(value = "simple_name")
private String simpleName;
}
框架提供了代码生成模板,可以快速生成基础的 Controller、Service、ServiceImpl、Mapper 等类。
// controller.java.vm
package ${package.Controller};
import ${package.Parent}.base.controller.BaseController;
import ${package.Parent}.dto.${entity}Dto;
import ${package.Entity}.${entity};
import ${package.Service}.${table.serviceName};
// ...
@RestController
@RequestMapping("#if(${package.ModuleName})/${package.ModuleName}#end/#if(${controllerMappingHyphenStyle})${controllerMappingHyphen}#else${table.entityPath}#end")
public class ${table.controllerName} extends BaseController<${table.serviceName}, ${entity}, ${entity}Dto> {
}
使用 i18n 注解和 I18nUtils 工具类可以轻松实现国际化支持。
@i18n(format = {I18nFormat.SEARCH}) // 支持国际化
@PostMapping("/detail/{id}")
public Result<TeamBaseInfoDto> detail(@PathVariable("id") Long id) {
return baseService.detail(id);
}
使用全局异常处理器 GlobalExceptionHandler 统一处理异常,并返回友好的错误信息。
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(AuthException.class)
public Result handleAuthException(AuthException e) {
return Result.error(e.getCode(), e.getMessage());
}
@ExceptionHandler(BusinessException.class)
public Result handleBusinessException(BusinessException e) {
return Result.error(e.getCode(), e.getMessage());
}
// 其他异常处理方法
// ...
}
通过 UserInfo 和 DataAuth 实现数据权限控制,确保用户只能访问有权限的数据。
// 在 BaseServiceImpl 中的 checkWrapper 方法中实现数据权限控制
UserInfo userInfo = checkUser ? ServletUtils.getUserInfo() : null;
if (null != userInfo && checkUser) {
switch (userInfo.getDataAuth()) {
case DEPT: // 部门[商家]级
if ("merchantId".equals(name) || "merId".equals(name)) {
wrapper = wrapper.eq(column, userInfo.getMerchantId());
}
break;
case PERSON: // 个人
if ("userId".equals(name) || "accountId".equals(name) || "createBy".equals(name)) {
wrapper = wrapper.eq(column, userInfo.getId());
}
break;
default:
if (null != value) {
wrapper = wrapper.eq(column, value);
}
}
}
Poyee Base 框架提供了一套完整的分层架构实现,通过抽象基类和泛型机制,实现了代码复用和业务逻辑的统一管理。该框架具有以下特点:
Result 对象统一封装接口返回数据。i18n 注解和 I18nUtils 工具类实现国际化。UserInfo 和 DataAuth 实现数据权限控制。通过使用 Poyee Base 框架,可以快速构建高质量的企业级应用,提高开发效率和代码质量。