|
@@ -0,0 +1,467 @@
|
|
|
|
|
+# CLAUDE.md
|
|
|
|
|
+
|
|
|
|
|
+## 项目概述
|
|
|
|
|
+
|
|
|
|
|
+| 项 | 值 |
|
|
|
|
|
+|---|---|
|
|
|
|
|
+| **项目名称** | jeeplus |
|
|
|
|
|
+| **技术栈** | Jeeplus + Spring 4.0.8 + MyBatis 3.2.8 + MySQL 5.7 + Layui 2.0.3 |
|
|
|
|
|
+| **打包方式** | WAR (`jeeplus-0.0.1-SNAPSHOT.war`) |
|
|
|
|
|
+| **Java** | JDK 7/8 |
|
|
|
|
|
+| **ORM** | MyBatis 3.2.8,XML 映射文件 |
|
|
|
|
|
+| **前端** | JSP + Layui 2.0.3 + jQuery,自定义 jeeplus 标签库 |
|
|
|
|
|
+| **工作流** | Activiti 5.x |
|
|
|
|
|
+| **权限** | Apache Shiro 1.2.3 |
|
|
|
|
|
+| **代码仓库** | Git,分支 `master` |
|
|
|
|
|
+
|
|
|
|
|
+## 核心配置文件
|
|
|
|
|
+
|
|
|
|
|
+- `jeeplus.properties` — 主配置(数据库、adminPath=`/a`、frontPath=`/f` 等)
|
|
|
|
|
+- `pom.xml` — Maven 依赖管理
|
|
|
|
|
+- Spring 配置位于 `src/main/resources/spring/` 目录
|
|
|
|
|
+
|
|
|
|
|
+## 项目包结构
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+com.jeeplus
|
|
|
|
|
+├── common/ # 公共基础类
|
|
|
|
|
+│ ├── config/Global.java # 全局配置常量
|
|
|
|
|
+│ ├── persistence/
|
|
|
|
|
+│ │ ├── BaseEntity.java # Entity 基类 (id, currentUser, page, sqlMap, isNewRecord)
|
|
|
|
|
+│ │ ├── DataEntity.java # 数据实体基类 (remarks, createBy, createDate, updateBy, updateDate, delFlag)
|
|
|
|
|
+│ │ ├── ActEntity.java # 工作流实体基类 (扩展 DataEntity, 含 Act act)
|
|
|
|
|
+│ │ ├── CrudDao.java # DAO 接口基类 (get, findList, insert, update, delete)
|
|
|
|
|
+│ │ ├── Page.java # 分页对象
|
|
|
|
|
+│ │ └── annotation/MyBatisDao.java # MyBatis DAO 标记注解
|
|
|
|
|
+│ ├── service/
|
|
|
|
|
+│ │ ├── BaseService.java # Service 基类
|
|
|
|
|
+│ │ └── CrudService.java # CRUD Service 基类 (泛型 D extends CrudDao, T extends DataEntity)
|
|
|
|
|
+│ ├── web/BaseController.java # Controller 基类
|
|
|
|
|
+│ └── utils/ # 工具类 (StringUtils, DateUtils, IdGen 等)
|
|
|
|
|
+├── modules/ # 业务模块 (按功能分包)
|
|
|
|
|
+│ └── {moduleName}/
|
|
|
|
|
+│ ├── entity/ # 实体类
|
|
|
|
|
+│ ├── dao/ # DAO 接口
|
|
|
|
|
+│ ├── service/ # Service 类
|
|
|
|
|
+│ ├── web/ # Controller 类
|
|
|
|
|
+│ ├── enums/ # 枚举类 (可选)
|
|
|
|
|
+│ ├── utils/ # 模块工具类 (可选)
|
|
|
|
|
+│ └── thread/ # 线程类 (可选)
|
|
|
|
|
+└── ...
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## 各层编码规范
|
|
|
|
|
+
|
|
|
|
|
+### 1. Entity 层
|
|
|
|
|
+
|
|
|
|
|
+**文件位置**: `src/main/java/com/jeeplus/modules/{moduleName}/entity/{EntityName}.java`
|
|
|
|
|
+
|
|
|
|
|
+**规范要点**:
|
|
|
|
|
+- 普通业务实体继承 `DataEntity<T>`,含工作流的实体继承 `ActEntity<T>`
|
|
|
|
|
+- 必须提供两个构造函数:无参构造、`(String id)` 构造调用 `super(id)`
|
|
|
|
|
+- 所有字段为 `private`,提供 public getter/setter
|
|
|
|
|
+- 日期字段 getter 上加 `@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")`
|
|
|
|
|
+- 需要导出的字段 getter 上加 `@ExcelField(title="字段名", align=2, sort=序号)`
|
|
|
|
|
+- 字段注释放在字段声明同一行末尾,用 `// 注释`
|
|
|
|
|
+- 必须声明 `private static final long serialVersionUID = 1L;`
|
|
|
|
|
+- 关联对象以完整对象引用(如 `private WorkStaffBasicInfo basicInfo`)
|
|
|
|
|
+- 列表字段初始化用 `Lists.newArrayList()`(如 `private List<WorkClientAttachment> workAttachments = Lists.newArrayList()`)
|
|
|
|
|
+
|
|
|
|
|
+```java
|
|
|
|
|
+/**
|
|
|
|
|
+ * Copyright © 2015-2020 <a href="http://www.jeeplus.org/">JeePlus</a> All rights reserved.
|
|
|
|
|
+ */
|
|
|
|
|
+package com.jeeplus.modules.{moduleName}.entity;
|
|
|
|
|
+
|
|
|
|
|
+// imports...
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * {模块中文名}Entity
|
|
|
|
|
+ * @author {作者}
|
|
|
|
|
+ * @version {日期}
|
|
|
|
|
+ */
|
|
|
|
|
+public class {EntityName} extends DataEntity<{EntityName}> {
|
|
|
|
|
+
|
|
|
|
|
+ private static final long serialVersionUID = 1L;
|
|
|
|
|
+ private String field1; // 字段注释
|
|
|
|
|
+ private Date field2; // 字段注释
|
|
|
|
|
+
|
|
|
|
|
+ public {EntityName}() {
|
|
|
|
|
+ super();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public {EntityName}(String id){
|
|
|
|
|
+ super(id);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @ExcelField(title="字段名", align=2, sort=7)
|
|
|
|
|
+ public String getField1() { return field1; }
|
|
|
|
|
+ public void setField1(String field1) { this.field1 = field1; }
|
|
|
|
|
+
|
|
|
|
|
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
|
|
|
|
+ @ExcelField(title="日期字段", align=2, sort=8)
|
|
|
|
|
+ public Date getField2() { return field2; }
|
|
|
|
|
+ public void setField2(Date field2) { this.field2 = field2; }
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 2. DAO 层
|
|
|
|
|
+
|
|
|
|
|
+**文件位置**: `src/main/java/com/jeeplus/modules/{moduleName}/dao/{EntityName}Dao.java`
|
|
|
|
|
+
|
|
|
|
|
+**规范要点**:
|
|
|
|
|
+- 接口必须加 `@MyBatisDao` 注解
|
|
|
|
|
+- 必须继承 `CrudDao<T>` 接口
|
|
|
|
|
+- 不使用 `implements`,只声明自定义方法
|
|
|
|
|
+- 自定义方法的参数复杂时用 `@Param` 注解
|
|
|
|
|
+
|
|
|
|
|
+```java
|
|
|
|
|
+/**
|
|
|
|
|
+ * Copyright © 2015-2020 <a href="http://www.jeeplus.org/">JeePlus</a> All rights reserved.
|
|
|
|
|
+ */
|
|
|
|
|
+package com.jeeplus.modules.{moduleName}.dao;
|
|
|
|
|
+
|
|
|
|
|
+import com.jeeplus.common.persistence.CrudDao;
|
|
|
|
|
+import com.jeeplus.common.persistence.annotation.MyBatisDao;
|
|
|
|
|
+import com.jeeplus.modules.{moduleName}.entity.{EntityName};
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * {模块中文名}DAO接口
|
|
|
|
|
+ * @author {作者}
|
|
|
|
|
+ * @version {日期}
|
|
|
|
|
+ */
|
|
|
|
|
+@MyBatisDao
|
|
|
|
|
+public interface {EntityName}Dao extends CrudDao<{EntityName}> {
|
|
|
|
|
+ // 自定义查询方法
|
|
|
|
|
+ public List<{EntityName}> getByXxx(@Param("param1")String param1);
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 3. MyBatis XML 映射
|
|
|
|
|
+
|
|
|
|
|
+**文件位置**: `src/main/resources/mappings/modules/{moduleName}/{EntityName}Dao.xml`
|
|
|
|
|
+
|
|
|
|
|
+**规范要点**:
|
|
|
|
|
+- `namespace` 必须等于 DAO 接口全限定名
|
|
|
|
|
+- 定义 `<sql id="{entityName}Columns">` 和 `<sql id="{entityName}Joins">` 片段
|
|
|
|
|
+- 列别名使用双引号(如 `a.field AS "field"`)
|
|
|
|
|
+- 关联嵌套对象使用点分隔别名(如 `w.name AS "basicInfo.name"`)
|
|
|
|
|
+- CRUD 标准方法:`get`, `findList`, `findAllList`, `insert`, `update`, `delete`, `deleteByLogic`, `findUniqueByProperty`
|
|
|
|
|
+- 分页排序使用 `page.orderBy` 动态 ORDER BY
|
|
|
|
|
+- 条件判断使用 `<if test="... != null and ... != ''"> `
|
|
|
|
|
+- 多数据库兼容写法:`<if test="dbName == 'mysql'">` / `oracle` / `mssql`
|
|
|
|
|
+
|
|
|
|
|
+```xml
|
|
|
|
|
+<?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="com.jeeplus.modules.{moduleName}.dao.{EntityName}Dao">
|
|
|
|
|
+
|
|
|
|
|
+ <sql id="{entityName}Columns">
|
|
|
|
|
+ a.id AS "id",
|
|
|
|
|
+ a.create_by AS "createBy.id",
|
|
|
|
|
+ a.create_date AS "createDate",
|
|
|
|
|
+ a.update_by AS "updateBy.id",
|
|
|
|
|
+ a.update_date AS "updateDate",
|
|
|
|
|
+ a.remarks AS "remarks",
|
|
|
|
|
+ a.del_flag AS "delFlag",
|
|
|
|
|
+ a.field1 AS "field1",
|
|
|
|
|
+ a.field2 AS "field2"
|
|
|
|
|
+ </sql>
|
|
|
|
|
+
|
|
|
|
|
+ <sql id="{entityName}Joins">
|
|
|
|
|
+ LEFT JOIN xxx_table x ON x.id = a.xxx_id
|
|
|
|
|
+ LEFT JOIN sys_office o ON o.id = a.office_id
|
|
|
|
|
+ LEFT JOIN sys_user u ON u.id = a.create_by
|
|
|
|
|
+ </sql>
|
|
|
|
|
+
|
|
|
|
|
+ <select id="get" resultType="{EntityName}">
|
|
|
|
|
+ SELECT <include refid="{entityName}Columns"/>
|
|
|
|
|
+ FROM {table_name} a
|
|
|
|
|
+ <include refid="{entityName}Joins"/>
|
|
|
|
|
+ WHERE a.id = #{id}
|
|
|
|
|
+ </select>
|
|
|
|
|
+
|
|
|
|
|
+ <select id="findList" resultType="{EntityName}">
|
|
|
|
|
+ SELECT <include refid="{entityName}Columns"/>
|
|
|
|
|
+ FROM {table_name} a
|
|
|
|
|
+ <include refid="{entityName}Joins"/>
|
|
|
|
|
+ <where>
|
|
|
|
|
+ a.del_flag = #{DEL_FLAG_NORMAL}
|
|
|
|
|
+ <if test="field1 != null and field1 != ''">
|
|
|
|
|
+ AND a.field1 = #{field1}
|
|
|
|
|
+ </if>
|
|
|
|
|
+ </where>
|
|
|
|
|
+ <choose>
|
|
|
|
|
+ <when test="page !=null and page.orderBy != null and page.orderBy != ''">
|
|
|
|
|
+ ORDER BY ${page.orderBy}
|
|
|
|
|
+ </when>
|
|
|
|
|
+ <otherwise>
|
|
|
|
|
+ ORDER BY a.update_date DESC
|
|
|
|
|
+ </otherwise>
|
|
|
|
|
+ </choose>
|
|
|
|
|
+ </select>
|
|
|
|
|
+
|
|
|
|
|
+ <insert id="insert">
|
|
|
|
|
+ INSERT INTO {table_name}(id, create_by, create_date, update_by, update_date, remarks, del_flag, field1, field2)
|
|
|
|
|
+ VALUES (#{id}, #{createBy.id}, #{createDate}, #{updateBy.id}, #{updateDate}, #{remarks}, #{delFlag}, #{field1}, #{field2})
|
|
|
|
|
+ </insert>
|
|
|
|
|
+
|
|
|
|
|
+ <update id="update">
|
|
|
|
|
+ UPDATE {table_name} SET
|
|
|
|
|
+ update_by = #{updateBy.id}, update_date = #{updateDate}, remarks = #{remarks},
|
|
|
|
|
+ field1 = #{field1}, field2 = #{field2}
|
|
|
|
|
+ WHERE id = #{id}
|
|
|
|
|
+ </update>
|
|
|
|
|
+
|
|
|
|
|
+ <update id="delete">
|
|
|
|
|
+ DELETE FROM {table_name} WHERE id = #{id}
|
|
|
|
|
+ </update>
|
|
|
|
|
+
|
|
|
|
|
+ <update id="deleteByLogic">
|
|
|
|
|
+ UPDATE {table_name} SET del_flag = #{DEL_FLAG_DELETE} WHERE id = #{id}
|
|
|
|
|
+ </update>
|
|
|
|
|
+
|
|
|
|
|
+ <select id="findUniqueByProperty" resultType="{EntityName}" statementType="STATEMENT">
|
|
|
|
|
+ select * FROM {table_name} where ${propertyName} = '${value}'
|
|
|
|
|
+ </select>
|
|
|
|
|
+</mapper>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 4. Service 层
|
|
|
|
|
+
|
|
|
|
|
+**文件位置**: `src/main/java/com/jeeplus/modules/{moduleName}/service/{EntityName}Service.java`
|
|
|
|
|
+
|
|
|
|
|
+**规范要点**:
|
|
|
|
|
+- 类上加 `@Service` 和 `@Transactional(readOnly = true)`
|
|
|
|
|
+- 必须继承 `CrudService<{EntityName}Dao, {EntityName}>`
|
|
|
|
|
+- 写操作方法加 `@Transactional(readOnly = false)`
|
|
|
|
|
+- 注入 DAO 使用 `@Autowired`,也可直接使用父类注入的 `dao` 字段
|
|
|
|
|
+- 数据权限过滤使用 `dataScopeFilter()` 放入 `sqlMap.dsf`
|
|
|
|
|
+- 覆盖 `save()` 方法时必须调用 `super.save(entity)` 并处理子表
|
|
|
|
|
+
|
|
|
|
|
+```java
|
|
|
|
|
+/**
|
|
|
|
|
+ * Copyright © 2015-2020 <a href="http://www.jeeplus.org/">JeePlus</a> All rights reserved.
|
|
|
|
|
+ */
|
|
|
|
|
+package com.jeeplus.modules.{moduleName}.service;
|
|
|
|
|
+
|
|
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
+import com.jeeplus.common.persistence.Page;
|
|
|
|
|
+import com.jeeplus.common.service.CrudService;
|
|
|
|
|
+import com.jeeplus.modules.{moduleName}.entity.{EntityName};
|
|
|
|
|
+import com.jeeplus.modules.{moduleName}.dao.{EntityName}Dao;
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * {模块中文名}Service
|
|
|
|
|
+ * @author {作者}
|
|
|
|
|
+ * @version {日期}
|
|
|
|
|
+ */
|
|
|
|
|
+@Service
|
|
|
|
|
+@Transactional(readOnly = true)
|
|
|
|
|
+public class {EntityName}Service extends CrudService<{EntityName}Dao, {EntityName}> {
|
|
|
|
|
+
|
|
|
|
|
+ public {EntityName} get(String id) {
|
|
|
|
|
+ return super.get(id);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public List<{EntityName}> findList({EntityName} entity) {
|
|
|
|
|
+ return super.findList(entity);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public Page<{EntityName}> findPage(Page<{EntityName}> page, {EntityName} entity) {
|
|
|
|
|
+ return super.findPage(page, entity);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Transactional(readOnly = false)
|
|
|
|
|
+ public void save({EntityName} entity) {
|
|
|
|
|
+ super.save(entity);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Transactional(readOnly = false)
|
|
|
|
|
+ public void delete({EntityName} entity) {
|
|
|
|
|
+ super.delete(entity);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 5. Controller 层
|
|
|
|
|
+
|
|
|
|
|
+**文件位置**: `src/main/java/com/jeeplus/modules/{moduleName}/web/{EntityName}Controller.java`
|
|
|
|
|
+
|
|
|
|
|
+**规范要点**:
|
|
|
|
|
+- `@Controller` + `@RequestMapping(value = "${adminPath}/{moduleName}/{entityName}")`
|
|
|
|
|
+- 必须继承 `BaseController`,不能继承其他 Controller
|
|
|
|
|
+- 使用 `@ModelAttribute` 方法根据 `id` 参数获取实体
|
|
|
|
|
+- 方法顺序:`list` → `form` → `save` → `delete` → `export/import` → 自定义
|
|
|
|
|
+- 列表方法需加 `@RequiresPermissions("{moduleName}:{entityName}:list")`
|
|
|
|
|
+- 返回视图路径格式:`modules/{moduleName}/{entityName}List` / `Form`
|
|
|
|
|
+- 保存成功后 `redirect` 回列表页,使用 `Global.getAdminPath()` 获取管理路径前缀
|
|
|
|
|
+- 使用 `addMessage(redirectAttributes, "消息")` 传递消息
|
|
|
|
|
+- 编辑保存前使用 `MyBeanUtils.copyBeanNotNull2Bean(formObj, dbObj)` 合并数据
|
|
|
|
|
+
|
|
|
|
|
+```java
|
|
|
|
|
+/**
|
|
|
|
|
+ * Copyright © 2015-2020 <a href="http://www.jeeplus.org/">JeePlus</a> All rights reserved.
|
|
|
|
|
+ */
|
|
|
|
|
+package com.jeeplus.modules.{moduleName}.web;
|
|
|
|
|
+
|
|
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
|
|
+import org.springframework.stereotype.Controller;
|
|
|
|
|
+import org.springframework.ui.Model;
|
|
|
|
|
+import org.springframework.web.bind.annotation.*;
|
|
|
|
|
+import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
|
|
|
|
+import com.jeeplus.common.config.Global;
|
|
|
|
|
+import com.jeeplus.common.persistence.Page;
|
|
|
|
|
+import com.jeeplus.common.web.BaseController;
|
|
|
|
|
+import com.jeeplus.common.utils.StringUtils;
|
|
|
|
|
+import com.jeeplus.modules.{moduleName}.entity.{EntityName};
|
|
|
|
|
+import com.jeeplus.modules.{moduleName}.service.{EntityName}Service;
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * {模块中文名}Controller
|
|
|
|
|
+ * @author {作者}
|
|
|
|
|
+ * @version {日期}
|
|
|
|
|
+ */
|
|
|
|
|
+@Controller
|
|
|
|
|
+@RequestMapping(value = "${adminPath}/{moduleName}/{entityName}")
|
|
|
|
|
+public class {EntityName}Controller extends BaseController {
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private {EntityName}Service {entityName}Service;
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private HttpServletRequest request;
|
|
|
|
|
+
|
|
|
|
|
+ @ModelAttribute
|
|
|
|
|
+ public {EntityName} get(@RequestParam(required=false) String id) {
|
|
|
|
|
+ {EntityName} entity = null;
|
|
|
|
|
+ if (StringUtils.isNotBlank(id)){
|
|
|
|
|
+ entity = {entityName}Service.get(id);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (entity == null){
|
|
|
|
|
+ entity = new {EntityName}();
|
|
|
|
|
+ }
|
|
|
|
|
+ return entity;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @RequiresPermissions("{moduleName}:{entityName}:list")
|
|
|
|
|
+ @RequestMapping(value = {"list", ""})
|
|
|
|
|
+ public String list({EntityName} entity, HttpServletRequest request, HttpServletResponse response, Model model) {
|
|
|
|
|
+ Page<{EntityName}> page = {entityName}Service.findPage(new Page<{EntityName}>(request, response), entity);
|
|
|
|
|
+ model.addAttribute("page", page);
|
|
|
|
|
+ return "modules/{moduleName}/{entityName}List";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @RequestMapping(value = "form")
|
|
|
|
|
+ public String form({EntityName} entity, Model model) {
|
|
|
|
|
+ model.addAttribute("{entityName}", entity);
|
|
|
|
|
+ return "modules/{moduleName}/{entityName}Form";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @RequestMapping(value = "save")
|
|
|
|
|
+ public String save({EntityName} entity, Model model, RedirectAttributes redirectAttributes) throws Exception {
|
|
|
|
|
+ if (!beanValidator(model, entity)){
|
|
|
|
|
+ return form(entity, model);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!entity.getIsNewRecord()){
|
|
|
|
|
+ {EntityName} t = {entityName}Service.get(entity.getId());
|
|
|
|
|
+ MyBeanUtils.copyBeanNotNull2Bean(entity, t);
|
|
|
|
|
+ {entityName}Service.save(t);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ {entityName}Service.save(entity);
|
|
|
|
|
+ }
|
|
|
|
|
+ addMessage(redirectAttributes, "保存成功");
|
|
|
|
|
+ return "redirect:" + Global.getAdminPath() + "/{moduleName}/{entityName}/?repage";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @RequestMapping(value = "delete")
|
|
|
|
|
+ public String delete({EntityName} entity, RedirectAttributes redirectAttributes) {
|
|
|
|
|
+ {entityName}Service.delete(entity);
|
|
|
|
|
+ addMessage(redirectAttributes, "删除成功");
|
|
|
|
|
+ return "redirect:" + Global.getAdminPath() + "/{moduleName}/{entityName}/?repage";
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 6. 前端 JSP 页面
|
|
|
|
|
+
|
|
|
|
|
+**文件位置**: `src/main/webapp/webpage/modules/{moduleName}/{entityName}List.jsp` / `{entityName}Form.jsp` / `{entityName}View.jsp`
|
|
|
|
|
+
|
|
|
|
|
+**规范要点**:
|
|
|
|
|
+- 使用 `<jsp:include>` 和 Jeeplus 自定义标签库(`taglib.jsp` 引入)
|
|
|
|
|
+- 表单使用 `<form:form>` 标签,`modelAttribute` 绑定后端对象
|
|
|
|
|
+- `${ctx}` 获取上下文路径(来自 `jeeplus.properties` 的 `adminPath`)
|
|
|
|
|
+- 列表页使用 Layui 的 oa-table 表格:`<table class="oa-table layui-table" id="contentTable"></table>`
|
|
|
|
|
+- 分页使用 `<table:page page="${page}"></table:page>` 标签
|
|
|
|
|
+- 排序使用 `<table:sortColumn id="orderBy" name="orderBy" value="${page.orderBy}" callback="sortOrRefresh();"/>`
|
|
|
|
|
+- 按钮样式类:`nav-btn nav-btn-add`、`nav-btn-refresh`、`nav-btn-import`、`nav-btn-export`
|
|
|
|
|
+- 弹窗使用 `openDialogAdd()`、`openDialogEdit()`、`openDialogView()` 函数
|
|
|
|
|
+- 后端消息使用 `<sys:message content="${message}"/>`
|
|
|
|
|
+- 表单验证使用 jQuery Validate
|
|
|
|
|
+- 文件上传限制检查:单文件限制 50MB,总文件限制 500MB
|
|
|
|
|
+- 列表 JS 初始化方式:
|
|
|
|
|
+
|
|
|
|
|
+```javascript
|
|
|
|
|
+$(document).ready(function() {
|
|
|
|
|
+ // 表格列配置
|
|
|
|
|
+ var cols = [
|
|
|
|
|
+ {field:'no', title:'编号', sortable: true, width:100},
|
|
|
|
|
+ {field:'name', title:'名称', sortable: true},
|
|
|
|
|
+ {field:'createDate', title:'创建时间', sortable: true, width:150},
|
|
|
|
|
+ {fixed:'right', title:'操作', toolbar:'#operating', width:180}
|
|
|
|
|
+ ];
|
|
|
|
|
+ var table = new TableInit("{entityName}", cols, '${ctx}/{moduleName}/{entityName}',
|
|
|
|
|
+ "searchForm", true, "contentTable", "operating");
|
|
|
|
|
+ table.init();
|
|
|
|
|
+});
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**关键 JavaScript 组件构造器**:
|
|
|
|
|
+- `TableInit(tableName, cols, url, formId, checkFlag, tableId, toolId)` — 初始化表格
|
|
|
|
|
+- `TableTreeInit(tableName, cols, url, formId, tableId, toolId, parentField)` — 树形表格
|
|
|
|
|
+- `DetailTableInit(detailName, fieldName, cols, url, tableId, toolId, obj)` — 子表
|
|
|
|
|
+
|
|
|
|
|
+**Layui 日期控件**: 使用 `lay('.di').each(function(){ laydate.render({ elem: this, type: 'date', trigger: 'click' });})`
|
|
|
|
|
+
|
|
|
|
|
+## 全局常量
|
|
|
|
|
+
|
|
|
|
|
+- `BaseEntity.DEL_FLAG_NORMAL = "0"` / `DEL_FLAG_DELETE = "1"` / `DEL_FLAG_AUDIT = "2"`
|
|
|
|
|
+- `Global.getAdminPath()` — 管理端根路径(默认 `/a`)
|
|
|
|
|
+- `${ctx}` — JSP 中引用 adminPath
|
|
|
|
|
+- `UserUtils.getUser()` — 获取当前登录用户
|
|
|
|
|
+- `UserUtils.getSelectCompany()` — 获取当前选中公司
|
|
|
|
|
+- `UserUtils.getSelectOffice()` — 获取当前选中部门
|
|
|
|
|
+
|
|
|
|
|
+## 文件命名规则
|
|
|
|
|
+
|
|
|
|
|
+| 类型 | 命名模式 | 示例 |
|
|
|
|
|
+|------|----------|------|
|
|
|
|
|
+| Entity | `{EntityName}.java` | `LeaveApply.java` |
|
|
|
|
|
+| DAO 接口 | `{EntityName}Dao.java` | `LeaveApplyDao.java` |
|
|
|
|
|
+| DAO XML | `{EntityName}Dao.xml` | `LeaveApplyDao.xml` |
|
|
|
|
|
+| Service | `{EntityName}Service.java` | `LeaveApplyService.java` |
|
|
|
|
|
+| Controller | `{EntityName}Controller.java` | `LeaveApplyController.java` |
|
|
|
|
|
+| 列表页 | `{entityName}List.jsp` | `leaveApplyList.jsp` |
|
|
|
|
|
+| 表单页 | `{entityName}Form.jsp` | `leaveApplyForm.jsp` |
|
|
|
|
|
+| 查看页 | `{entityName}View.jsp` | `leaveApplyView.jsp` |
|
|
|
|
|
+| 子表页 | `{childName}List.jsp` | `leaveDetailList.jsp` |
|
|
|
|
|
+
|
|
|
|
|
+## 数据库表命名
|
|
|
|
|
+
|
|
|
|
|
+- 表名使用下划线小写:`{module_name}` 如 `leave_apply`、`leave_detail`
|
|
|
|
|
+- 关联外键命名:`{ref_table}_id` 如 `staff_id`、`leave_id`
|
|
|
|
|
+- 必备列:`id`(varchar 64), `create_by`, `create_date`, `update_by`, `update_date`, `remarks`, `del_flag`
|
|
|
|
|
+
|
|
|
|
|
+## 其他注意事项
|
|
|
|
|
+
|
|
|
|
|
+1. **文件头版权声明**: 所有 Java/JSP 文件必须保留 JeePlus 版权声明
|
|
|
|
|
+2. **缩进**: 使用 Tab 缩进(4 空格宽度)
|
|
|
|
|
+3. **日期格式**: Java 端 `yyyy-MM-dd HH:mm:ss`,前端 `yyyy-MM-dd`(日期控件)
|
|
|
|
|
+4. **代码中字符串比较**用 `StringUtils.isNotBlank()`/`isBlank()` 而非 `!= null && !""`
|
|
|
|
|
+5. **权限注解**: Shiro 的 `@RequiresPermissions("module:entity:action")`
|
|
|
|
|
+6. **JSON 序列化忽略**: 对不需要 JSON 序列化的字段使用 `@JsonIgnore` 或 `@JSONField(serialize = false)`
|
|
|
|
|
+7. **import 语句**会包含 `com.google.common.collect.Lists`、`com.google.common.collect.Maps`
|
|
|
|
|
+8. **Controller 基类**注入 `HttpServletRequest request` 用于获取当前请求
|
|
|
|
|
+9. **Excel 导出**使用 `ExportExcel`/`ImportExcel` 工具类
|
|
|
|
|
+10. **子表处理**:在 Service 的 save 中先 `super.save(entity)` 再分别处理子表 CRUD
|