# Poyee Base 框架说明文档 ## 1. 概述 `com.poyee.base` 包是 Poyee Checklist 项目的核心基础框架,提供了一套完整的分层架构实现,包括控制层(Controller)、服务层(Service)、数据访问层(Mapper)以及相关的数据传输对象(DTO)、请求对象(Req)和实体对象(Entity)。该框架采用了面向对象的设计思想,通过抽象基类和泛型机制,实现了代码复用和业务逻辑的统一管理。 ## 2. 核心组件 ### 2.1 基础架构 #### 2.1.1 控制层(Controller) **BaseController** `BaseController` 是所有控制器的基类,提供了通用的请求处理和日志记录功能。 ```java public abstract class BaseController, T extends BaseReq, R extends BaseDto> { @Autowired protected S baseService; // 日志记录 public void console(String label, Object obj) { ... } // 分页查询 public Result listPage(T req, boolean checkUser) { ... } // 详情查询 public Result info(Integer id) { ... } // 获取请求对象 public HttpServletRequest getRequest() { ... } } ``` #### 2.1.2 服务层(Service) **BaseService 接口** `BaseService` 接口定义了服务层的通用方法,包括查询、分页、计数等操作。 ```java public interface BaseService extends IService { Result listPage(T req, boolean checkUser); List selectJoinAllList(MPJLambdaWrapper wrapper, T req); QueryWrapper checkWrapper(T req, boolean checkUser); Long selectCount(MPJLambdaWrapper wrapper); List getAllList(T req, boolean checkUser); Result info(Integer id); Result getOne(T req); Result getOneDto(T req); UserInfo getUserInfo(); IPage ipage(MPJLambdaWrapper wrapper, Q req); Result ipageResult(MPJLambdaWrapper wrapper, Q req); MPJLambdaWrapper mpjWrapper(Object req); MPJLambdaWrapper mpjWrapper(Object req, String alias); MPJLambdaWrapper mpjWrapper(MPJLambdaWrapper mpjLambdaWrapper, Object req, String alias); } ``` **BaseServiceImpl 实现类** `BaseServiceImpl` 是 `BaseService` 接口的实现类,提供了各种通用方法的具体实现。 ```java public class BaseServiceImpl, T extends BaseReq, R extends BaseDto> extends ServiceImpl implements BaseService { // 检查用户权限 public

void checkAndSetUserId(P p) { ... } // 分页查询 @Override public Result listPage(T req, boolean checkUser) { ... } // 获取单条数据 @Override public Result info(Integer id) { ... } // 构建查询条件 @Override public QueryWrapper checkWrapper(T req, boolean checkUser) { ... } // 构建MPJ查询条件 @Override public MPJLambdaWrapper mpjWrapper(Object req) { ... } } ``` #### 2.1.3 数据访问层(Mapper) **IBaseMapper 接口** `IBaseMapper` 接口继承了 MyBatis-Plus 的 `BaseMapper` 和 `MPJBaseMapper`,提供了基础的数据库操作方法。 ```java public interface IBaseMapper extends BaseMapper, MPJBaseMapper { // 基础方法由 BaseMapper 和 MPJBaseMapper 提供 } ``` **IBaseProvider 接口** `IBaseProvider` 接口定义了动态 SQL 构建的方法,用于复杂查询场景。 ```java public interface IBaseProvider { List> selectListMap(@Param("req") T req, @Param("clazz") Class clazz); long pageCount(String sql); List> page(String sql); Map selectOneMap(@Param("req") T req, @Param("clazz") Class clazz); Map selectByIdMap(@Param("id") Serializable id, @Param("clazz") Class clazz); Map selectSumMap(@Param("req") T req, @Param("clazz") Class clazz); int save(T req); int update(T req); } ``` **BaseProvider 实现类** `BaseProvider` 是 `IBaseProvider` 接口的抽象实现,提供了 SQL 构建的核心功能。 ```java 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 insertMap = new HashMap<>(); // 记录 UPDATE key-value(线程安全) public final Map updateMap = new HashMap<>(); // 存储表信息的映射(线程安全) public final Map tableInfos = new ConcurrentHashMap<>(); // 记录 WHERE 条件(线程安全) public final List whereInfos = new CopyOnWriteArrayList<>(); // 记录 SELECT 列(线程安全) public final List selectColumns = new CopyOnWriteArrayList<>(); // 记录 LEFT JOIN 信息(线程安全) public final List leftJoinInfos = new CopyOnWriteArrayList<>(); // 记录 ORDER BY 信息(线程安全) // ... } ``` ### 2.2 数据对象 #### 2.2.1 基础请求对象(BaseReq) `BaseReq` 是所有请求对象的基类,提供了分页、排序等通用参数。 ```java @Data public class BaseReq { @ApiModelProperty(hidden = true) @TableField(exist = false) public static List 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; } } ``` #### 2.2.2 基础数据传输对象(BaseDto) `BaseDto` 是所有数据传输对象的基类,通常包含实体的基本属性和一些扩展属性。 ```java @Data public class BaseDto { // 基础属性 } ``` #### 2.2.3 基础实体对象(BaseEntity) `BaseEntity` 是所有实体对象的基类,提供了分页、排序等通用参数。 ```java @Data public class BaseEntity { @ApiModelProperty(hidden = true) @TableField(exist = false) public static List 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; } } ``` #### 2.2.4 结果对象(Result) `Result` 是统一的响应结果对象,用于封装接口返回数据。 ```java @Data @ApiModel("通用返回结果") @JsonIgnoreProperties(ignoreUnknown = true) public class Result 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 Result ok(R data) { ... } public static Result error(String msg) { ... } public static Result error(Integer code, String msg) { ... } public static Result page(IPage iPage) { ... } // ... } ``` #### 2.2.5 用户信息对象(UserInfo) `UserInfo` 封装了当前登录用户的信息,用于权限控制和数据过滤。 ```java @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) { ... } } ``` ### 2.3 工具类和注解 #### 2.3.1 国际化支持 **i18n 注解** `i18n` 注解用于标记需要国际化的字段、方法或类。 ```java @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` 提供了获取国际化消息的方法。 ```java @Configuration public class I18nUtils { // 定义占位符的正则表达式模式 private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("\\{(\\d+)\\}"); private MessageProperties messageProperties; // 存储消息的Map,键是消息键,值是包含语言和消息的Map private static Map> messages; // 初始化国际化工具类,并加载消息属性 @Autowired public I18nUtils(MessageProperties messageProperties) { ... } // 根据枚举和参数获取国际化消息 public static String get(I18nMessageEnums i18n, Object... args) { ... } // ... } ``` **I18nMessageEnums 枚举** `I18nMessageEnums` 定义了系统中所有的国际化消息。 ```java @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) { ... } } ``` #### 2.3.2 Servlet 工具类 `ServletUtils` 提供了获取请求、响应、会话以及用户信息的方法。 ```java 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() { ... } // ... } ``` #### 2.3.3 数据库注解 **Select 注解** `Select` 注解用于指定查询字段。 ```java @Select(table = UserEntity.class, fieldName = "username", distinct = true) private String username; ``` **Where 注解** `Where` 注解用于指定查询条件。 ```java @Where(fieldName = "status", operator = EQ) private String status; ``` **LeftJoin 注解** `LeftJoin` 注解用于指定左连接查询。 ```java @LeftJoin(table = RoleEntity.class, leftTable = UserEntity.class, fieldName = "id", leftFieldName = "roleId") private String roleName; ``` **OrderBy 注解** `OrderBy` 注解用于指定排序字段。 ```java @OrderBy(fieldName = "createTime", sort = "DESC") private String createTime; ``` ## 3. 使用示例 ### 3.1 创建控制器 ```java @Slf4j @Api(value = "球队基础信息管理", tags = "球队基础信息管理") @RestController @RequestMapping("/api/v1/teamInfo") public class TeamBaseInfoController extends BaseController { @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 detail(@PathVariable("id") Long id) { return baseService.detail(id); } } ``` ### 3.2 创建服务 ```java public interface TeamBaseInfoService extends BaseService { Page page(TeamInfoPageReq req); Result add(TeamInfoCreateReq req); Result update(TeamInfoUpdateReq req); Result delete(RemoveInfoReq req); List searchTeamInfosByTeamSimpleName(TeamBaseInfoReq req); List getByIds(List ids); } ``` ### 3.3 实现服务 ```java @Slf4j @Service public class TeamBaseInfoServiceImpl extends BaseServiceImpl 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)); } // 其他方法实现 // ... } ``` ### 3.4 创建 Mapper ```java public interface TeamBaseInfoMapper extends IBaseMapper, IBaseProvider { // 可以添加自定义的查询方法 } ``` ### 3.5 创建请求对象 ```java @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; } } ``` ### 3.6 创建数据传输对象 ```java @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; } ``` ## 4. 最佳实践 ### 4.1 分层架构 - **控制层(Controller)**:负责处理请求、参数校验和返回结果,不包含业务逻辑。 - **服务层(Service)**:负责业务逻辑处理,包括数据校验、业务规则和事务管理。 - **数据访问层(Mapper)**:负责数据库操作,包括 CRUD 和复杂查询。 ### 4.2 代码生成 框架提供了代码生成模板,可以快速生成基础的 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> { } ``` ### 4.3 国际化支持 使用 `i18n` 注解和 `I18nUtils` 工具类可以轻松实现国际化支持。 ```java @i18n(format = {I18nFormat.SEARCH}) // 支持国际化 @PostMapping("/detail/{id}") public Result detail(@PathVariable("id") Long id) { return baseService.detail(id); } ``` ### 4.4 异常处理 使用全局异常处理器 `GlobalExceptionHandler` 统一处理异常,并返回友好的错误信息。 ```java @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()); } // 其他异常处理方法 // ... } ``` ### 4.5 数据权限控制 通过 `UserInfo` 和 `DataAuth` 实现数据权限控制,确保用户只能访问有权限的数据。 ```java // 在 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); } } } ``` ## 5. 总结 Poyee Base 框架提供了一套完整的分层架构实现,通过抽象基类和泛型机制,实现了代码复用和业务逻辑的统一管理。该框架具有以下特点: 1. **分层架构**:清晰的控制层、服务层、数据访问层分离,职责明确。 2. **代码复用**:通过抽象基类和泛型机制,减少重复代码。 3. **统一响应**:使用 `Result` 对象统一封装接口返回数据。 4. **国际化支持**:通过 `i18n` 注解和 `I18nUtils` 工具类实现国际化。 5. **数据权限控制**:通过 `UserInfo` 和 `DataAuth` 实现数据权限控制。 6. **异常处理**:使用全局异常处理器统一处理异常。 通过使用 Poyee Base 框架,可以快速构建高质量的企业级应用,提高开发效率和代码质量。