Junx-EP开发手册-开始使用
一、项目说明
Junx-EP项目是模块化项目,目前一共包含了以下11个模块:
junx-ep
|-junx-ep-auth:基于shiro实现的认证与鉴权模块,支持简单RAM认证鉴权配置与ShiroRealm的复杂认证鉴权。
|-junx-ep-codegen:代码生成模块后台Java实现,引入了本jar过后,相当于给系统添加代码生成功能。
|-junx-ep-codegen-ui:EP框架基于Layui默认实现的生成模块前端html和js代码
|-junx-ep-core:EP框架的微内核jar包,提供了核心的mybatis封装、Result、GlobalExceptionHandler等核心类定义。
|-junx-ep-fs:文件上传模块,提供了文件上传与存储功能,引入本jar过后,相当于引入了文件上传功能。
|-junx-ep-pvc:持久化版本控制模块,引入本模块jar包,相当于引入了基于数据库的模块版本控制,用于模块的数据库表结构初始化与后期版本升级。
|-junx-ep-qlexp:封装的淘宝QLExpress包,提供了规则引擎功能。
|-junx-ep-scheduler:基于Quartz封装的定时任务模块,引入本jar包,即可拥有分布式定时任务管理能力。
|-junx-ep-scheduler-ui:EP框架基于Layui实现的定时任务前端html和js代码。
|-junx-ep-sys:基于core包实现的默认系统框架,包含了系统登录及其系统管理等基础功能,含用户管理、组织管理、角色权限、菜单管理、系统日志等功能基础,是所有含有菜单的功能模块的基础模块。
|-junx-ep-sys-ui:EP基于Layui实现的系统基础功能,含用户登录、含用户管理、组织管理、角色权限、菜单管理、系统日志等功能的前端html和js,以及用到的基础js、css等前端代码文件。
EP框架的jar包中,自带前端html和js代码,通过webinjar的方式,添加到jar包中,再与springboot做集成,因此框架的UI界面是通过jar包进行引入的,后期可以统一进行升级,比较方便和简单。
二、使用方式
1、仅使用ep-core微内核
微内核仅提供后端开发相关能力,提供了轻度的mybatis封装,不过度封装,支持mybatis-plus注解,但是不提供mybatis-plus一样的封装,个人觉得mybatis-plus封装有些过度,不应经常使用。
Maven:
<dependency>
<groupId>io.github.junxworks</groupId>
<artifactId>junx-ep-core</artifactId>
<version>2.1.0</version>
</dependency>
1.1 ORM
引入core包后,即拥有了轻度封装的orm能力,下面是core提供的BaseMapper:
public interface BaseMapper {
/**
* 解析实体类并将其写入到数据库中,排除空值字段写入,Object必须含有io.github.junxworks.ep.core.orm.annotations.Table注解。
* 写入数据后,系统默认生成ID字段回写,ID字段默认名称为id,如果id不是这个字段的,请不要调用此方法,将本方法复制到自己的mapper中,修改ID字段名即可,如下:
*
* @InsertProvider(type = MybatisObjectSqlProvider.class, method = "insertWithoutNull")
* @Options(useGeneratedKeys = true, keyProperty = "xxxId")
* public int insertWithoutNull(Object entity);{
* ......
*
* }
*
* @param entity 需要写入数据库的实体对象
* @return 成功写入记录条数
*/
@InsertProvider(type = MybatisObjectSqlProvider.class, method = "insertWithoutNull")
@Options(useGeneratedKeys = true, keyProperty = SqlGenerator.ID_COLUMN)
public int insertWithoutNull(Object entity);
/**
* 将实体类批量写入数据库,会采用第一个实体类的表结构进行sql解析,不支持多种实体类混合写入。
*
* @param entities 需要写入数据库的实体对象集合
* @return 成功写入记录条数
*/
@InsertProvider(type = MybatisObjectSqlProvider.class, method = "insertBatch")
public int insertBatch(List<?> entities);
/**
* 解析实体类并将其写入到数据库中,保留空值字段写入,Object必须含有io.github.junxworks.ep.core.orm.annotations.Table注解。
* 写入数据后,系统默认生成ID字段回写,ID字段默认名称为id,如果id不是这个字段的,请不要调用此方法,将本方法复制到自己的mapper中,修改ID字段名即可,如下:
*
* @InsertProvider(type = MybatisObjectSqlProvider.class, method = "insertWithNull")
* @Options(useGeneratedKeys = true, keyProperty = "xxxId")
* public int insertWithNull(Object entity);{
* ......
*
* }
*
* @param entity 需要写入数据库的实体对象
* @return 成功写入记录条数
*/
@InsertProvider(type = MybatisObjectSqlProvider.class, method = "insertWithNull")
@Options(useGeneratedKeys = true, keyProperty = "id")
public int insertWithNull(Object entity);
/**
* 根据主键更新一条记录,排除空值字段写入,实体类必须要包含io.github.junxworks.ep.core.orm.annotations.Table注解,io.github.junxworks.ep.core.orm.annotations.PrimaryKey主键或id属性。
*
* @param entity 需要更新数据库的实体对象
* @return 成功更新的记录条数
*/
@UpdateProvider(type = MybatisObjectSqlProvider.class, method = "updateWithoutNull")
public int updateWithoutNull(Object entity);
/**
* 根据主键更新一条记录,保留排除空值字段写入,实体类必须要包含io.github.junxworks.ep.core.orm.annotations.Table注解,io.github.junxworks.ep.core.orm.annotations.PrimaryKey主键或id属性。
*
* @param entity 需要更新数据库的实体对象
* @return 成功更新的记录条数
*/
@UpdateProvider(type = MybatisObjectSqlProvider.class, method = "updateWithNull")
public int updateWithNull(Object entity);
/**
* 根据主键删除一条记录,实体类必须要包含io.github.junxworks.ep.core.orm.annotations.Table注解,io.github.junxworks.ep.core.orm.annotations.PrimaryKey主键或id属性。
*
* @param entity 需要删除数据库的实体对象
* @return 成功删除的记录条数
*/
@DeleteProvider(type = MybatisObjectSqlProvider.class, method = "deleteByPK")
public int deleteByPK(Object entity);
/**
* 根据实体类class与id,删除一条数据库记录,实体类必须要包含io.github.junxworks.ep.core.orm.annotations.Table注解,io.github.junxworks.ep.core.orm.annotations.PrimaryKey主键或id属性。
*
* @param entityClass 需要删除数据库的实体对象类
* @param id 关键字值
* @return 成功删除的记录条数
*/
@DeleteProvider(type = MybatisObjectSqlProvider.class, method = "deleteByID")
public int deleteOneById(@SuppressWarnings("rawtypes") @Param("class") Class entityClass, @Param("id") Long id);
/**
* 根据实体类class与id,查询一条数据库记录,实体类必须要包含io.github.junxworks.ep.core.orm.annotations.Table注解,io.github.junxworks.ep.core.orm.annotations.PrimaryKey主键或id属性。
*
* @param entity 需要查询数据库的实体对象类
* @param id 关键字值
* @return 查询结果
*/
@SelectProvider(type = MybatisObjectSqlProvider.class, method = "getOneByPK")
public Map<String, Object> selectMapByID(@SuppressWarnings("rawtypes") @Param("class") Class entityClass, @Param("id") Long id);
/**
* 根据实体类class与id,查询一条数据库记录,实体类必须要包含io.github.junxworks.ep.core.orm.annotations.Table注解,io.github.junxworks.ep.core.orm.annotations.PrimaryKey主键或id属性。
*
* @param entity 需要查询数据库的实体对象类
* @param pkName 关键属性列名
* @param id 关键字值
* @return 查询结果
*/
@SelectProvider(type = MybatisObjectSqlProvider.class, method = "getOneByPKNameAndValue")
public Map<String, Object> selectMapByPKNameAndValue(@SuppressWarnings("rawtypes") @Param("class") Class entityClass, @Param("pkName") String pkName, @Param("pkValue") Object pkValue);
}
业务自身mapper继承BaseMapper即可,再配合io.github.junxworks.ep.core.orm.annotations包中的注解,可以达到动态解析实体成对应sql的目的,当然也可以不用annotations包的注解,有默认解析机制,将Entity实体属性映射成DB字段,DB字段和表名默认是驼峰转蛇形(下划线)的方式,可以通过设置EntityResolver.turnOffCamelFieldToSnake()与EntityResolver.turnOffCamelTableNameToSnake()设置成保留驼峰命名。
core里面轻度封装mybatis,实现了一些基础的最常用的方法封装,极大提升开发效率,这里采用的Entity实体翻译sql模式,只要继承了BaseMapper,就可以翻译任何实体类,当然如果为了规范,可以采用TBaseMapper,指定实体泛型。而且基于SQL翻译,可以优雅的实现表字段部分更新逻辑,当你有一个功能,业务侧只编辑某一张实体表的某几个字段,然后传到后端,正常实现后端把所有传过来的字段判断一下,塞进一个实体中,下面是基于mybatis-plus的实现部分字段更新代码:
LambdaUpdateWrapper<OilUser> userUpdateWrapper = new LambdaUpdateWrapper<>();
userUpdateWrapper.set(OilUser::getUsername, user.getUsername());
userUpdateWrapper.set(OilUser::getNickName, user.getNickName());
userUpdateWrapper.set(OilUser::getTel, user.getTel());
userUpdateWrapper.set(OilUser::getEmail, user.getEmail());
if (!StringUtils.isEmpty(user.getPassword())) {
userUpdateWrapper.set(OilUser::getPassword, passwordEncoder.encode(user.getPassword()));
}
userUpdateWrapper.eq(OilUser::getId, user.getId());
oilUserMapper.update(null, userUpdateWrapper);
下面这个是基于ep-core实现的代码:
@Override
public int updateStudent(StudentDto studentDto) {
DStudentUpdateModel studentUM = new DStudentUpdateModel();
BeanUtils.copyProperties(studentDto, studentUM);
return tableDemoMapper.updateWithNull(studentUM);
}
大量简化了这种无脑代码,提升系统扩展能力,新增表字段过后,再也不用到处去找地方调整代码了。
下面是基于core开发的一些样例代码:
2、仅使用ep-auth鉴权认证
ep-auth基于shiro开发的RBAC角色权限控制模块,用起来极为简单,首先引入jar包:
Maven:
<dependency>
<groupId>io.github.junxworks</groupId>
<artifactId>junx-ep-auth</artifactId>
<version>2.1.0</version>
</dependency>
2.1 认证测试
我们先起一个简单的web项目,测试一下ep-auth的效果,下面这个是测试项目,一个最基础的springboot的web项目,包含一个controller,返回Result对象:
@RestController
@RequestMapping("/test")
public class TestController {
@GetMapping()
public Result test() {
return Result.ok("1");
}
}
服务器端口为9999,上下文为test,访问如下URL地址http://localhost:9999/test/test
能得到应答:
然后我们在application
启动类上加入注解@EnableEPShiroProxy
@EnableEPShiroProxy
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
public class EpTestApplication {
public static void main(String[] args) {
SpringApplication.run(EpTestApplication.class, args);
}
}
在application.yml
配置文件中加入下面这段auth配置:
junx:
ep:
auth:
shiro:
global-session-timeout: 86400000 #缓存过期时间,redis缓存有效,mem缓存无效
filters: #过滤配置,anon表示匿名访问,ep为基于ep实现的认证逻辑
"[/**/*.js]": anon
"[/**/*.html]": anon
"[/**/*.jpg]": anon
"[/**/*.png]": anon
"[/**/*.ico]": anon
"[/**/css/**]": anon
"[/**/plugins/**]": anon
"[/**/fonts/**]": anon
"[/**/verification-codes]": anon
"[/**/login]": anon
"[/**/system-name]": anon
"[/**]": ep
simple-accounts: #简单账号配置,请求方在header中带入key和secret即可访问有权限的url路径
- epRamKey: test
epRamSecret: "123"
authorizes: /**
同时新增自己项目的AuthorizingRealm对象,注入到bean配置中,如果不注入自己的AuthorizingRealm对象,则默认会采用EP实现的逻辑,如果没有引用ep-sys模块,则可能会出现异常。我们这里只测试,不做认证。下面是AuthorizingRealm的实现。
public class TestAuthorizingRealm extends AuthorizingRealm {
@Override
public boolean supports(AuthenticationToken token) {
return token instanceof DefaultToken;
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
//根据自己业务逻辑实现
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//根据自己业务逻辑实现
return null;
}
}
在bean配置中加入
@Bean
TestAuthorizingRealm testAuthorizingRealm() {
return new TestAuthorizingRealm();
}
加入ep-auth过后,再访问刚才那个url地址,就会出现如下结果
2.2 RAM认证
下面测试一下简单认证好使不好使,上面配置中配置了账户test密码123,可以访问的路径是所有,那用postman试一试,在header中计入两个认证属性。
请求结果
2.3 CacheManager缓存管理
ep-auth提供了2种缓存管理实现,1是基于本地内存的EPShiroMemCacheManager,这也是默认的认证缓存管理实现,第2种就是基于redis实现的EPShiroRedisCacheManager,要使用基于redis的分布式缓存,需要在bean注入的时候注入EPShiroRedisCacheManager,如下:
@Bean
public CacheManager epCacheManager() {
return new EPShiroRedisCacheManager();
}
同时需要配置项目的redis配置,具体参考springboot的redis配置。
对于测试环境或者一些很小的个人项目,可以直接使用本地内存的缓存即可。
3、使用ep-sys模块
ep-sys是包含系统管理的基础开发框架,主要面向的是后端开发人员,原生是基于springboot+ep+layui实现的,当然可以把layui换成其他MVVM框架,需要自己实现。在项目中引入ep-sys的jar包。
Maven:
<dependency>
<groupId>io.github.junxworks</groupId>
<artifactId>junx-ep-sys</artifactId>
<version>2.1.0</version>
</dependency>
首先,springboot项目一定是web项目,这里会用到controller与数据库,在springboot的application启动类上加入@EnableEPSys复合注解,即可开启ep框架,并且初始化数据库表结构。
/**
* 开启EP基础系统模块,含系统支撑以及EP认证
*
* @ClassName: EnableEPSys
* @author: Michael
* @date: 2020-7-19 12:17:47
* @since: v1.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@EnableBaseEPModules //EP基础系统模块
@EnableEPShiroProxy //开启EP认证
public @interface EnableEPSys {
}
3.1库表结构初始化
ep-sys在启动时候,会检查主库(如果是多数据源,则以@Primary定义的为主)的ep_s_profile表,检查每个模块的版本号,是否需要执行db升级,执行pvc持久化版本控制相关升级操作,第一次初始化库的时候,会在主库执行对应的sql,生成表结构和数据,sql脚本在各个模块的pvc包下:
profile中定义了当前最新的version版本号,如果ep_s_profile中模块版本号比jar包中的小,则会挨个执行每个sql脚本,直到最新的version。注意,这里数据库版本只支持升级,不能降级。
3.2系统默认登录页面
拿demo项目举例,demo项目上下文demo,默认登录页面为/eui/login.html,最终访问的URL地址为{系统域名}/demo/eui/login.html,系统默认超管账号admin,密码123456。
为了简化用户登录,只有当客户输错密码后,才会弹出验证码验证,不用每次登录都输入验证码。默认用户在连续输入5次错误密码时,账号会被锁定。如果用户账号被锁定,则需要在用户管理中进行修改用户状态。
EP框架基础使用先介绍到这里,下章继续介绍其他功能模块。