# EasyBoot
**Repository Path**: ApeCoder/easy-boot
## Basic Information
- **Project Name**: EasyBoot
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: MIT
- **Default Branch**: 1.1
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2024-05-10
- **Last Updated**: 2026-03-18
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# EasyBoot
## 介绍
[EasyBoot](https://gitee.com/rankeiot/easyboot)为 SpringBoot + Sqltoy + Vue3 全栈框架。内置vue3与js的编译处理插件。开发与部署均无需node环境。
## 相关技术
- 后端基础框架 [SpringBoot](https://spring.io/projects/spring-boot)
- ORM框架 [Sqtoy](https://gitee.com/sagacity/sagacity-sqltoy)
- Bean拷贝 [MapStruct](https://mapstruct.org/)
- 前端框架 [Vue3](https://cn.vuejs.org/) [Preact(可选)](https://preact.nodejs.cn/)
- 前端UI组件库 [HeyUI](https://v2.heyui.top/)
- 前端UI组件库 [ElementPlus](https://element-plus.org/zh-CN/)
## 项目说明
[EasyBoot](https://gitee.com/rankeiot/easyboot)内主要是基础的功能和平台。
[EasyPlugins](https://gitee.com/rankeiot/easyplugins)项目里面主要包含一些扩展插件
[EasyStarter](https://gitee.com/rankeiot/easystarter)简单的示例启动项目
### EasyBoot项目结构
- easy-core 核心模块,不带业务逻辑,包含了一些基础功能扩展,如配置项,菜单配置,权限认证等功能
- easy-platform 基础平台模块,包含了用户管理,权限管理,等平台业务功能,带相关界面
- easy-dev 开发工具模块,包括代码生成和一些小工具
- easy-vue vue模板加载模板,包含了vue的主文件。提供了vue文件,mjs文件,less文件的页面端支持
### 系统功能
- 用户管理:提供用户的相关配置,新增用户后,默认密码为123456
- 角色管理:对权限与菜单进行分配,角色可绑定用户和菜单/按钮权限
- 部门管理:可配置系统组织架构,树形表格展示。部门有一个带级连关系的内部ID。
- 字典管理:可维护常用一些固定的数据,如:状态,性别等
- 配置项管理:管理各种常用可变配置
- 用户日志:记录用户操作日志,可自定义日志
- 慢SQL日志:记录运行慢的日志,方便维护和调优,阈值可设置
- 定时任务:方便定时任务,有任务执行记录
- 报表管理:XMReport集成,在线模板设计器,pdf导出
- 代码生成:高灵活度生成前后端代码,减少大量重复的工作任务
- API接口:可以导出api.json和在线调试
## 快速开始
1. 新建maven项目,然后修改pom.xml
```xml
4.0.0
easyboot
com.rankeiot.easy
1.1-SNAPSHOT
yourgroupId
youartifactId
1.0-SNAPSHOT
17
17
UTF-8
rankeiot-public-central
central
https://maven.cnb.cool/rankeiot/public/-/packages/
true
true
always
rankeiot-public-central
central
https://maven.cnb.cool/rankeiot/public/-/packages/
true
true
com.rankeiot.easy
easy-vue
com.rankeiot.easy
easy-dev
runtime
true
com.rankeiot.easy
easy-platform
org.projectlombok
lombok
compile
true
mysql
mysql-connector-java
org.springframework.boot
spring-boot-maven-plugin
org.projectlombok
lombok
true
```
2. 编写启动类
```java
package yourpackage;
import com.rankeiot.core.Module;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
/**
* 基于 EasyBoot 的库存管理系统启动类。
*/
@SpringBootApplication
public class Application implements Module {
@Override
public String name() {
return "系统名称";
}
/**
* 进行初始化
*/
@Override
public void start(ApplicationContext applicationContext) {
//注册框架的功能支持
//注册用户菜单
//regMenu(demoMenu.class);
//注册会员菜单,通常不需要,同时使用会员和用户菜单是才用
//regMemberMenu(demoMemberMenu.class);
//注册系统配置项
//regConfigs(config.class)
//注册自定义的固定菜单项
//regFixedDict(DictEnum.class)
//注册前端用的js模块,js满足esm标注,前端页面通过 import xx from 'name' 方式使用
//jsModule("moduleName","js/module_a.js")
//注册vue组件,注册后前端vue页面中可直接使用注册名使用组件
//vueComponent("VueCom1","coms/VueCom1.vue")
//添加全局css样式,会在启动页面自动载入
//addGlobalStyle(String path)
//添加全局js文件,非esm模块,会在启动页面自动载入
//setGlobalScripts(path)
//其他自定义初始化代码
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
```
启动后打开浏览器进入 http://localhost:8080

目前只支持了mysql,当然sqltoy本身是适配了多数据库的。填写完数据库信息后点确定即可进行数据库的初始化。初始化完成后会在项目目录下生成application-dev.yml文件。
可将application-dev.yml移动到src/main/resources目录下面,这样打包后运行不需要重新配置。也可以将application-dev.yml放置与jar包同一目录(工作目录)
初始化完成后不出意外的化,我们会看到下面的界面

进入系统后我们会看到一个非常干净的首页。可通过新建文件 src/main/resources/static/home.vue 来覆盖首页,其他页面也可以通过这种方式覆盖。

到这里基本的系统已经跑起来了。
## 开发指南
建议使用IDEA进行开发,根据Maven的profile配置,IDEA会在项目打开的时候会显示对于的配置选项。EasyBoot开发依赖数据库设计,当设计好数据库后,我们可以从系统中直接导入表模型进行代码生成。

开发的时候,maven默认选择了dev这个profile。在打包的时候应该选择prod,maven会根据参数替换application.yml中的配置,并去掉开发和接口api模块进行打包
### 代码生成
在开发模式下(profile=dev),进入http://localhost:8080,选择代码生成器进入下面菜单。通过导入数据库中以及设计好的数据库表的方式,我们可以导入模型,生成对应代码。数据库表设计时,请添加必要的表注释及字段注释。

### 项目目录结构说明
```
/project_root
├── pom.xml
├── src
│ ├── main
│ │ ├── java
│ │ │ └── yourpackage #应用基础包
│ │ │ ├── moduleA #应用模块A
│ │ │ │ ├── controller #controller目录
│ │ │ │ ├── dao #DAO接口目录
│ │ │ │ ├── domain #Domain目录
│ │ │ │ │ ├── dto #DTO目录
│ │ │ │ │ ├── entity #数据库实体目录
│ │ │ │ │ ├── vo #VO目录
│ │ │ │ │ └── DemoMapper.java #MapStruct的数据映射接口
│ │ │ │ ├── service #service目录
│ │ │ │ ├── config #配置项目录
│ │ │ │ ├── dict #固定字典项目录
│ │ │ │ └── task #定时任务目录
│ │ │ ├── moduleB #应用模块B
│ │ │ └── Application.java #启动文件
│ │ └── resources
│ │ ├── models #使用代码生成器时,自动生成的实体模型
│ │ │ └── moduledir1 #模块1
│ │ │ └── xxtable.json #实体模型,描述了模型名字,字段名,字段类型,页面显示等信息
│ │ ├── sql #初始化sql目录
│ │ │ └── xxtable_init.sql #业务初始化sql
│ │ ├── static #前端模块
│ │ │ ├── coms #自定义前端组件,每个组件为单个vue或jsx文件
│ │ │ ├── css #css 放通用css和less文件
│ │ │ ├── js #js目录,支持ESM标准
│ │ │ └── moduledir1 #某个功能的页面目录
│ │ │ └── xxlist.vue #包含页面,可以是vue组件文件或jsx的React组件
│ │ ├── application.yml #项目配置
│ │ ├── application-dev.yml #项目DEV配置
│ │ └── application-prod.yml #项目PROD配置
│ └── test
│ ├── java
│ │ └── yourpackage
│ │ └── MainTestApp.java
│ └── resources
│ └── application.yml #测试用配置文件
```
### 后端指南
Easy Boot后端采用SpringBoot和sqltoy进行开发
#### 模块划分
Easy Boot按照业务划分包模块,可在模块中配置模块的业务菜单,固定配置项,字典项等
对于需要独立出来的模块,需要进行下面的定义
```java
//可参考com.rankeiot.platform.PlatformModule
@Configuration
public class DemoModule implements Module {
public void start(ApplicationContext context) {
//注册菜单
//regMenu(TestMenu.class);
}
}
//按spring自动组件的要求,新建文件 /sources/META-INF/spring.factories,加入:
//org.springframework.boot.autoconfigure.EnableAutoConfiguration=模块完整类名,如:com.rankeiot.platform.PlatformModule
```
### 数据库实体相关
1. 通过[SqlToy](https://gitee.com/sagacity/sagacity-sqltoy)定义数据库实体类,
2. 通过Sqltoy的注解@Entity来标明后端实体,
3. 通过@Column绑定数据库字段,当查询用于输出VO时,输出字段无需使用@Column标注,输出会自动映射到同名字段。带下划线的字段名会按驼峰规则转换后映射,如:user_name->userName。如仍需@Cloumn映射字段的情况下,实体类需要标注@Entity注解(tableName可留空),否则@Column不生效。
4. 通过@ClientValidator生成前端实体验证器,名字与类同名,可以通过注解@ClientValidator("otherName")改写前端名字,可用于entity,dto等。与数据库、sqltoy无直接关系。验证器通过hibernate字段验证注解,如:@NotNull,@Length等直接生成前端字段验证逻辑
以Student为例:
```java
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
import java.sql.Types;
import lombok.Data;
import lombok.experimental.FieldNameConstants;
import io.swagger.v3.oas.annotations.media.Schema;
import org.sagacity.sqltoy.config.annotation.Entity;
import org.sagacity.sqltoy.config.annotation.Id;
import org.sagacity.sqltoy.config.annotation.Column;
import jakarta.validation.constraints.*;
import jakarta.validation.constraints.Email;
import org.hibernate.validator.constraints.*;
import com.rankeiot.core.validation.*;
import com.rankeiot.core.anno.ClientValidator;
/**
* 学生信息
*/
@Schema(description="学生信息")
@Data
@ClientValidator
@FieldNameConstants(asEnum = true)
@Entity(tableName=Student.TABLE)
public class Student implements Serializable{
public static final String TABLE="student_table_name";
/**
* ID
*/
@Schema(description="ID")
@Id(strategy = "identity")
@Column(name="ID",length=64L,type=Types.BIGINT,nullable=false,autoIncrement=true)
private Long id;
/**
* 发票号码
*/
@Schema(description="发票号码")
@Length(max=50)
@Column(name="user_name",length=50L,type=Types.VARCHAR)
private String userName;
}
```
后端调用:
```java
@Service
@RequiredArgsConstructor
public class StudentService{
final LightDao dao;
public void createStudent(){
var student=new Student();
student.setUserName("testName");
dao.save(student);
}
}
```
前端调用验证器,引入路径为'@validator/{校验器名称}.js',如:
```vue
```
#### DAO
DAO基于[SqlToy](https://gitee.com/sagacity/sagacity-sqltoy)实现,用于数据库数据查询。
通过编写DAO接口的方式,编译时框架自动生成对应的实现类。DAO编写步骤:
1. 编写一个接口,需要继承SqlToyRepository接口,然后添加类注解@com.rankeiot.core.sqltoy.anno.Dao或@org.springframework.stereotype.Repository。二者区别在于,Repository会通过Spring自动处理Transaction
2. 编写SQL查询或执行的方法,添加一个方法,然后通过@Query注解添加对应的执行SQL语句。Query会自动判断执行的sql类型(QUERY或UPDATE),自动处理参数映射和返回类型
3. 查询SQL遵循SqlToy的语法规则,基础的两个规则为:paramName 表示参数占位,用#[]包裹时,如:#[user_name like :UserName] ,会自动判断包裹的参数是否为空,从而进行动态剔除,支持其余SqlToy的高级方法
4. 方法注解增加了@DateFormat,@NumberFormat,@Translate,@LLike,@RLike,@Blank。功能对应SqlToy中XML的同名指令
```java
import com.rankeiot.core.sqltoy.StreamFetcher;
import java.util.List;
import com.rankeiot.core.sqltoy.OrderBy;
import com.rankeiot.core.sqltoy.SqlToyRepository;
import com.rankeiot.core.sqltoy.anno.Dao;
import com.rankeiot.core.sqltoy.anno.Query;
import org.sagacity.sqltoy.model.Page;
import java.util.Map;
import com.rankeiot.core.sqltoy.anno.filters.LLike;
import com.rankeiot.core.sqltoy.anno.filters.RLike;
/**
* 演示DAO
*/
@Dao
public interface DemoDao extends SqlToyRepository {
/**
* 简单分页查询
* 1. 当参数列表中,除去Page和OrderBY类型的参数,只剩下一个 Map类型参数时,语句中的查询占位名与map中的key值名相对应
* 2. 当参数列表中,除去Page和OrderBY类型的参数,只剩下一个实现Serializable接口类型的参数时,语句中的查询占位名与该bean中的字段名相对应
* 3. 其余情况直接对应参数名本身
* @param pageable
* @param params
* @param order
* @return
*/
@Query("SELECT * FROM demo_table WHERE param like :param")
Page list(Page> pageable, Map params, OrderBy order);
/**
* 占位直接对应到参数名
* @param userName
* @return
*/
@Query("SELECT * FROM demo_table WHERE param like :userName")
int queryCountByName(String userName);
/**
* 列表查询,通过返回StreamFetcher的方式,可以流式获取数据,也可以直接返回List
*/
@Query("SELECT * FROM demo_table WHERE param like :param")
StreamFetcher list(Map params);
/**
* like查询示例,默认情况下 like :param 会自动在参数值两端拼接 %,无需手动concat("%")
* 当前仅需左侧补%时,使用@LLike注解进行声明,需右侧补%进行匹配时,使用@RLike进行声明
* @param name
* @return
*/
@LLike({"name"}) // 可对多个字段生效
@Query("SELECT * FROM demo_table WHERE param like :name")
DemoVO findByName(String name);
/**
* in查询使用()包裹占位名后直接查
* @param ids id列表
* @return
*/
@Query("SELECT * FROM table WHERE id in (:ids)")
List findDemos(List ids);
/**
* 快速分页。@fast, @fastPage与@fast等效
* Sqltoy的分页不是简单的包裹sql,根据sql情况智能剔除了sql中的order by,
* 同时select count(1) 模式是根据sql逻辑决定是直接切除掉原sql的from 之前的语句,
* 替换成select count(1) from 避免不必要的sql函数运算。
* 如下示例中,计算总数时,只用执行@fast包裹住的部分,而不需要额外join其他的表。
*/
@Query("""
select tmp.*,d.rpt name file_name from
@fast(
select m.* from nebula_rpt_subscribe_mail m where 1=l
#[and m.operate date between :beginDate and :endDate]
#[and m.status=:status]
#[and m.subscribe id=:subscribeId]
order by m.operate_time desc
) tmp
left join nebula_rpt_subscribe_file f on f.id=tmp.id
left join nebula_rpt_deploy d on d.rpt id=f.rpt id
""")
Page fastPageList(Date beginDate,Date endDate,Integer status,Long subscribeId);
/**
* sql内条件处理
* SQL内@if(),@elseif() @else
*
*/
@Query("""
select * from table where name='测试'
-- 非计逻辑场景下,内部动态参数为null,最终为andstatus=1也要自动剔除
#[and status=1 #[and type=:type] #[and orderName like :orderName] ]
-- flag==1时成立,因为内容存在功态参数,所以继续变成#[and status=:status]参数为nuLL剔除,不为nuLL则保留
#[@if(:flag==1) and status=:status]
-- flag==1时成立,因为and status=1没有动态参数,则保留and status=1
#[@if(:flag==1) and status=1 ]
#[@elseif(:flag==2) and status in (2,4) ]
#[@else and status in (1,2)]
""")
List findByType(String type,String orderName,int status,int flag);
/**
* 1.使用@blank()目的是为非条件部分的语句虚构出一个参数,让其符合sqltoy的sql组织规则复杂场景请结合@if和@value使用来解决问题,比如@value(:sqlScript) 直接嵌入组织好的sql。
* 2.@value(:paramName) 类似于@blank(:paramName),唯一的区别是 @value(:paramName) 会直接显示paramName对应的值。
*/
@Query("""
select t.STAFF_ID,t.STAFF_CODE,t.STAFF_NAME,t.POST,
-- 当sexType参数为空时,结果字段中不会输出 t.SEX_TYPE
#[@blank(:sexType) t.SEX_TYPE, ]t.ORGAN_ID,t1.ORGAN_NAME
from sys_staff_info t left join sys_organ_info t1on t.ORGAN_ID=t1.ORGAN_ID
where 1=1
#[and t.STAFF_NAME like :staffName]
#[and t.sex_type=:sexType]
""")
List findStaffByNameAndType(String staffName,String sexType);
/**
* 循环 @loop()、@secure-loop()、@loop-full()、@secure-loop-full()的用法
* @loop()用于sql动态循环拼接字段、条件,一般针对数组或集合,且不适用于in的场景。
* @secure-loop():跟@loop的区别在于参数不会直接拼接到sql中,而是采用?形式入参,防止sql注入
* 分三种格式
* @secure-loop(:loopParam,loopContent)
* @loop(:loopParam,loopContent) 不推荐
* @secure-loop(:loopParam,loopContent,linkSign)
* @loop(:loopParam,loopContent,linkSign) 不推荐
* @secure-loop(:loopParam,loopContent,linkSign,startIndex,endIndex)
* @loop(:loopParam,loopContent,linkSign,startIndex,endIndex) 不推荐
* 推荐使用:@@secure-loop
* 1、为了确保@loop宏参数用逗号切割的准确性,支持参数上用{},’’,”” 三种方式包裹
* 2. @secure-loop(:loopParams,{loopContent},or) 默认跳过null和空,不参与循环,如不跳过则请使用@secure-loop-full(:loopParams,{loopContent},or)
* 下面语句中,当ids=[1,2,3]时,实际的语句为: SELECT * FROM table WHERE id=1 or id=2 or id=3
*/
@Query("""
SELECT * FROM table WHERE #[@if(size(:ids)>0) @loop(:ids,"id=:ids[i]"," or ")]
""")
List listByIds(List ids);
/**
* 使用@include(:partSql)可以通过动态参数形式传入sql片段,当需要动态语句时使用。因可读性较差,纯在管理影响,不推荐使用
* @param sqlPart 传入的sql,可以带占位,如: and field_a=:paramA
* @param paramA 参数A
*/
@Query("""
SELECT * FROM table WHERE status=1 @include(:sqlPart)
""")
List findWithSqlPart(String sqlPart,String paramA);
/**
* 数据更新
* @param demo
*/
@Query("UPDATE demo_table SET field_a=:fieldA where id=:id")
void update(DemoEntity demo);
/**
* 批量更新,返回受影响数据条数,可返回void
* @param demos
*/
@Query("UPDATE demo_table SET field_a=:fieldA where id=:id")
int update(List demos);
}
```
StreamFetcher
```java
package com.rankeiot.core.sqltoy;
/**
* 用于接口DAO中返回流式处理结果
* @param
*/
public interface StreamFetcher {
/**
* 获取数据
* @param handler 数据处理handler
*/
void fetch(StreamResultHandler handler);
/**
* 获取数据
* @param consumer BiConsumer[Data,rowIndex]
*/
void fetch(BiConsumer consumer);
}
```
StreamResultHandler
```java
package org.sagacity.sqltoy.callback;
/**
* @project sagacity-sqltoy
* @description 定义基于流模式获取查询结果的反调
* @author zhongxuchen
* @version v1.0, Date:2022-7-23
*/
public interface StreamResultHandler {
/**
* 开始
* @param columnsLabels 查询结果列标题
* @param columnsTypes 查询结果列对应的数据类型
*/
public default void start(String[] columnsLabels, String[] columnsTypes) {
}
/**
* 对行数据进行消费
* @param row
* @param rowIndex
*/
public default void consume(Object row, int rowIndex) {
}
/**
* 有条件存在终止行为的消费
* @param row
* @param rowIndex
* @return
*/
public default boolean doNextConsume(Object row, int rowIndex) {
return true;
}
/**
* 流数据提取完成
*/
public default void end() {
}
}
```
### 业务菜单和权限
Easy Framework使用注解方式来声明权限,新增菜单或者权限后,重新启动项目,页面菜单会自动更新。如果修改后没有更新,在后端管理页面菜单中点击重置内部菜单按钮,可以刷新菜单
```java
import com.rankeiot.core.anno.Menu;
import com.rankeiot.core.anno.Permission;
//这里声明了菜单以及权限
@Menu(value = "测试", icon = "icon-file", id = TestMenu.ID)
public interface TestMenu {
String ID = "Demo";
//配置菜单,也支持jsx(React)组件路径
@Menu(value = "示例", path = "test/demo.vue", icon = "icon-file")
String DEMO = ID + ".demo";
// demo增删改权限
@Permission(value = "新增", parent = DEMO)
String DEMO_ADD = DEMO + ".add";
@Permission(value = "修改", parent = DEMO)
String DEMO_EDIT = DEMO + ".edit";
@Permission(value = "删除", parent = DEMO)
String DEMO_DELETE = DEMO + ".delete";
}
```
框架中的权限注解说明
```java
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Auth {
/**
* 调用方法需要的用户权限,默认不需权限,仅登录即可。
*/
String[] value() default {};
/**
* 调用方法需要的用户角色。
*/
String[] role() default {};
/**
* 调用方法限定的用户类型,默认为Current.TYPE_USER,即后台用户,可选值为:Current.TYPE_USER(后台用户),Current.TYPE_MEMBER(前台会员)。
*/
char userType() default Current.TYPE_USER;
/**
* 用户子类型,备用字段,可用于用户业务类型判断
*/
char[] subType() default Current.SUB_TYPE_DEFAULT;
/**
* 是否需要登录,Controller上标注时,全部方法都需要进登录,可以用@Auth(login=false)单独注解一个方法,用来表示其不需要登录
*/
boolean login() default true;
}
```
后端接口代理注解说明
```java
package com.rankeiot.core.anno;
/**
* 标注于Controller上,生成同名前端调用接口代理
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ClientCallable {
}
/**
* 方法注解,非必须
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ClientMethod {
//映射的方法名,默认情况下,使用java代码中原本的方法名
String value() default "";
//是否需要排除该方法
boolean exclude() default false;
//该方法是否为文件下载处理方法
boolean download() default false;
}
```
后端权限使用,以学生信息管理为例
```java
import com.rankeiot.core.anno.ClientCallable;
import com.rankeiot.core.anno.ClientMethod;
/**
*
* 示例 @Auth 表示需要登录,@Auth(string)表示调用该方法需要的权限,也可指定所需角色(role)
* 当传入多个权限或者角色时,表示有当中任意一个条件满足即可调用该方法
* 以下@Api和ApiOperation注解为Swagger注解,使用Swagger注解的Controller才会出现在API文档中
* 除此外,Controller写法与常规SpringBoot Controller相同
* ClientCallable注解会自动生成前端调用的接口
* */
@Api(tags="学生信息管理")
@Auth
@RestController
@ClientCallable
@RequestMapping("demo")
@RequiredArgsConstructor
public class DemoController {
//org.mapstruct.Mapper 类型映射接口,用于不同类的数据拷贝
final DemoMapper demoMapper;
//数据接口
final DemoDao demoDao;
//Sqltoy的默认DAO,可直接用数据操作,简单CRUD业务直接在controller中实现即可。复杂的或需要复用的,才提取到Service中
final LightDao dao;
//Service 业务复杂或需要服用的业务再提取到service中
//final DemoService demoService;
/**
* 新增学生
*/
@ApiOperation("新增学生")
@Auth(StuMenu.STUDENT_ADD)
@PostMapping("add")
public Resp add(@Valid @RequestBody StudentRequest req){
//获取当前用户信息,如果该方法没有@Auth注解
UserInfo userInfo = Current.user();
Student student=demoMapper.toEntity(req);
student.setAddTime(new Date());
student.setAddUser(User.userInfo.getUsername());
dao.save(student);
//Resp说明:
//Resp.ok() 返回成功消息
//Resp.ok("message") 返回成功消息
//Resp.ok(data,"message") 携带数据返回成功消息
//Resp.of(data) 携带数据返回成功消息
//Resp.fail("message") 抛出 new BusinessException(message) 异常
return Resp.ok();
}
/**
* 删除学生
*/
@ApiOperation("删除学生")
@Auth(StuMenu.STUDENT_DELETE)
@Transactional
@PostMapping("delete")
public Resp delete(List ids){
// dao.loadAll(students);
List students = CollectionUtil.map(ids,Student::new);
dao.deleteAll(students);
return Resp.ok();
}
/**
* 更新学生信息
* 使用 dao.update 更新数据时,直接使用update会根据实体中@Id标注的字段,对其余有值的字段进行更新,如果@Id字段没有值,会抛出异常
* 如果需要空值也需要更新,则需指定强制更新字段:dao.update(student,"field1","field2",...)
* 如果仅需更新指定字段使用updateFields:
* 单个实体:dao.update().updateFields("field1"...).one(student)
* 更新实体列表:dao.update().updateFields("field1"...).many(studentList)
* 也可通过自定义Dao接口,写SQL语句对数据进行精确修改
*/
@ApiOperation("更新学生")
@Auth(StuMenu.STUDENT_EDIT)
@PostMapping("save")
public Resp save(@Valid @RequestBody Student student){
dao.update(student);
return Resp.ok();
}
/**
* 获取学生
*/
@ApiOperation("获取学生详细")
@Auth(StuMenu.STUDENT)
@GetMapping("detail")
public Resp detail(Integer id){
Student student=dao.load(new Student(id));
return Resp.of(student);
}
/**
* 获取学生列表
*/
@ApiOperation("列出学生")
@Auth(StuMenu.STUDENT)
@PostMapping("list")
public Resp