Compare commits

...

17 Commits

Author SHA1 Message Date
JerryMa1024 c32a441994 修复字典VO的children注解错误 2020-08-18 19:57:31 +08:00
JerryMa1024 f2883e8577 + buildTree支持指定属性名 2020-08-18 08:59:08 +08:00
JerryMa1024 937d384fe6 + jdbc配置项支持shardingsphere及指定配置项 2020-08-18 08:58:13 +08:00
JerryMa1024 4a69e0163a + validateBean单元测试 2020-08-18 08:56:22 +08:00
wuy 7683f78159 add:增加swagger配置说明 2020-08-04 17:03:52 +08:00
wuy 941fbaf8ac fix:升级文档版本错误修改 2020-08-04 12:43:47 +08:00
JerryMa1024 f8970525a8 修复condition中的like条件解析错误 2020-07-29 11:50:31 +08:00
JerryMa1024 ab3e7dc7a7 Merge remote-tracking branch 'origin/develop' into develop 2020-07-29 11:47:06 +08:00
JerryMa1024 1ca8c8695e 修复condition中的like条件解析错误 2020-07-29 11:45:46 +08:00
yangzhao635226@163.com a21baf717c 更改文档中的run server为serve 2020-07-28 10:07:20 +08:00
JerryMa1024 4af05dc763 rename cacheManager to shiroCacheManager 2020-07-25 09:49:44 +08:00
JerryMa1024 fdb2496f10 更新文档diboot-v2链接 2020-07-24 06:11:31 +08:00
JerryMa1024 af0c90cd6e 更新文档diboot-v2链接 2020-07-24 06:11:02 +08:00
JerryMa1024 b05d770074 更新文档diboot-v2链接 2020-07-24 06:10:13 +08:00
JerryMa1024 1c213527ba 更新IAM相关文档 2020-07-23 20:51:23 +08:00
yangzhao635226@163.com 12997246d8 登录参数与登录后的扩展数据中可传入扩展数据 2020-07-23 16:30:18 +08:00
yangzhao635226@163.com 1e71b5024a 更改版本为2.1.2;为认证类添加扩展属性字段。 2020-07-23 14:58:44 +08:00
40 changed files with 214 additions and 64 deletions

View File

@ -1,4 +1,4 @@
> v2.1版本发布可以告别常规SQL和CRUD了 [B站上手视频](https://www.bilibili.com/video/BV17V411r7Cc) 、 [playground弹药包](https://gitee.com/dibo_software/diboot-v2-example/raw/master/playground.zip) > v2.1版本发布可以告别常规SQL和CRUD了 [B站上手视频](https://www.bilibili.com/video/BV17V411r7Cc) 、 [playground新手体验包](https://gitee.com/dibo_software/diboot-example/raw/master/playground.zip)
# diboot - 化繁为简,以简驭繁 # diboot - 化繁为简,以简驭繁
<p align="center"> <p align="center">
@ -32,7 +32,7 @@ diboot v2版本目前实现: diboot-core高效内核 + diboot-devtools开发
> JsonResult、字符串处理、常用校验、BeanUtils、DateUtils等 > JsonResult、字符串处理、常用校验、BeanUtils、DateUtils等
基于diboot-core 2.x版本的CRUD和简单关联的常规功能实现代码量比传统Mybatis项目减少80%+),且实现更高效更易维护。 基于diboot-core 2.x版本的CRUD和简单关联的常规功能实现代码量比传统Mybatis项目减少80%+),且实现更高效更易维护。
更多介绍请查看: [diboot-core README](https://github.com/dibo-software/diboot-v2/tree/master/diboot-core "注解自动绑定多表关联"). 更多介绍请查看: [diboot-core README](https://github.com/dibo-software/diboot/tree/master/diboot-core "注解自动绑定多表关联").
## 二、 diboot-devtools 自动化开发助理 ## 二、 diboot-devtools 自动化开发助理
@ -55,14 +55,14 @@ diboot v2版本目前实现: diboot-core高效内核 + diboot-devtools开发
* 支持基于注解的数据权限实现 * 支持基于注解的数据权限实现
* 支持灵活的扩展能力(扩展多种登录方式、灵活替换用户实体类、自定义缓存等) * 支持灵活的扩展能力(扩展多种登录方式、灵活替换用户实体类、自定义缓存等)
更多介绍请查看: [iam-base-starter README](https://github.com/dibo-software/diboot-v2/tree/master/iam-base-starter "身份认证管理组件"). 更多介绍请查看: [iam-base-starter README](https://github.com/dibo-software/diboot/tree/master/iam-base-starter "身份认证管理组件").
## 四、diboot-file 文件相关处理组件 ## 四、diboot-file 文件相关处理组件
* EasyExcel轻量封装支持Java注解校验与@ExcelBind*注解实现字典及关联字段的name-value转换并提供完善的校验错误提示 * EasyExcel轻量封装支持Java注解校验与@ExcelBind*注解实现字典及关联字段的name-value转换并提供完善的校验错误提示
* 封装常用的文件本地存储、上传下载、图片压缩水印等常用处理 * 封装常用的文件本地存储、上传下载、图片压缩水印等常用处理
更多介绍请查看: [diboot-file-starter README](https://github.com/dibo-software/diboot-v2/tree/master/diboot-file-starter "文件组件"). 更多介绍请查看: [diboot-file-starter README](https://github.com/dibo-software/diboot/tree/master/diboot-file-starter "文件组件").
> 其他组件逐步开发中 ... > 其他组件逐步开发中 ...

View File

@ -7,11 +7,11 @@
<parent> <parent>
<groupId>com.diboot</groupId> <groupId>com.diboot</groupId>
<artifactId>diboot-root</artifactId> <artifactId>diboot-root</artifactId>
<version>2.1.1</version> <version>2.1.2</version>
</parent> </parent>
<artifactId>diboot-core-spring-boot-starter</artifactId> <artifactId>diboot-core-spring-boot-starter</artifactId>
<version>2.1.1</version> <version>2.1.2</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<description>diboot core starter project</description> <description>diboot core starter project</description>
@ -25,7 +25,7 @@
<dependency> <dependency>
<groupId>com.diboot</groupId> <groupId>com.diboot</groupId>
<artifactId>diboot-core</artifactId> <artifactId>diboot-core</artifactId>
<version>2.1.1</version> <version>2.1.2</version>
</dependency> </dependency>
<dependency> <dependency>

View File

@ -159,4 +159,4 @@ spring.datasource.hikari.driver-class-name=com.mysql.cj.jdbc.Driver
#### 3. 详细文档 - [diboot-core 官方文档](https://www.diboot.com/guide/diboot-core/%E5%AE%89%E8%A3%85.html) #### 3. 详细文档 - [diboot-core 官方文档](https://www.diboot.com/guide/diboot-core/%E5%AE%89%E8%A3%85.html)
#### 4. 参考样例 - [diboot-core-example](https://github.com/dibo-software/diboot-v2-example/tree/master/diboot-core-example) #### 4. 参考样例 - [diboot-core-example](https://github.com/dibo-software/diboot-example/tree/master/diboot-core-example)

View File

@ -7,11 +7,11 @@
<parent> <parent>
<groupId>com.diboot</groupId> <groupId>com.diboot</groupId>
<artifactId>diboot-root</artifactId> <artifactId>diboot-root</artifactId>
<version>2.1.1</version> <version>2.1.2</version>
</parent> </parent>
<artifactId>diboot-core</artifactId> <artifactId>diboot-core</artifactId>
<version>2.1.1</version> <version>2.1.2</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<description>diboot core project</description> <description>diboot core project</description>

View File

@ -141,7 +141,25 @@ public abstract class BaseBinder<T> {
return this; return this;
} }
public BaseBinder<T> andLike(String fieldName, String value){ public BaseBinder<T> andLike(String fieldName, String value){
queryWrapper.like(S.toSnakeCase(fieldName), formatValue(fieldName, value)); fieldName = S.toSnakeCase(fieldName);
value = (String)formatValue(fieldName, value);
if(S.startsWith(value, "%")){
value = S.substringAfter(value, "%");
if(S.endsWith(value, "%")){
value = S.substringBeforeLast(value, "%");
queryWrapper.like(fieldName, value);
}
else{
queryWrapper.likeLeft(fieldName, value);
}
}
else if(S.endsWith(value, "%")){
value = S.substringBeforeLast(value, "%");
queryWrapper.likeRight(fieldName, value);
}
else{
queryWrapper.like(fieldName, value);
}
return this; return this;
} }
public BaseBinder<T> andIn(String fieldName, Collection valueList){ public BaseBinder<T> andIn(String fieldName, Collection valueList){

View File

@ -163,11 +163,12 @@ public class ConditionManager extends BaseConditionManager{
else if(operator instanceof LikeExpression){ else if(operator instanceof LikeExpression){
LikeExpression express = (LikeExpression)operator; LikeExpression express = (LikeExpression)operator;
String annoColumn = removeLeftAlias(express.getLeftExpression().toString()); String annoColumn = removeLeftAlias(express.getLeftExpression().toString());
String value = express.getRightExpression().toString();
if(express.isNot() == false){ if(express.isNot() == false){
binder.andLike(annoColumn, express.getStringExpression()); binder.andLike(annoColumn, value);
} }
else{ else{
binder.andNotLike(annoColumn, express.getStringExpression()); binder.andNotLike(annoColumn, value);
} }
} }
else{ else{

View File

@ -154,10 +154,10 @@ public class JoinConditionManager extends BaseConditionManager {
currentSegments = middleTableOnSegments; currentSegments = middleTableOnSegments;
} }
if(expression.isNot() == false){ if(expression.isNot() == false){
currentSegments.add(left + " LIKE " + expression.getStringExpression()); currentSegments.add(left + " LIKE " + expression.getRightExpression().toString());
} }
else{ else{
currentSegments.add(left + " NOT LIKE " + expression.getStringExpression()); currentSegments.add(left + " NOT LIKE " + expression.getRightExpression().toString());
} }
} }
else{ else{

View File

@ -343,13 +343,26 @@ public class BeanUtils {
* @return * @return
*/ */
public static <T> List<T> buildTree(List<T> allNodes, Object rootNodeId){ public static <T> List<T> buildTree(List<T> allNodes, Object rootNodeId){
return buildTree(allNodes, rootNodeId, Cons.FieldName.parentId.name(), Cons.FieldName.children.name());
}
/***
* 构建指定根节点的上下级关联的树形结构上级parentId子节点children
* @param allNodes 所有节点对象
* @param rootNodeId 跟节点ID
* @param parentIdFieldName 父节点属性名
* @param childrenFieldName 子节点集合属性名
* @param <T>
* @return
*/
public static <T> List<T> buildTree(List<T> allNodes, Object rootNodeId, String parentIdFieldName, String childrenFieldName){
if(V.isEmpty(allNodes)){ if(V.isEmpty(allNodes)){
return null; return null;
} }
// 提取所有的top level对象 // 提取所有的top level对象
List<T> topLevelModels = new ArrayList(); List<T> topLevelModels = new ArrayList();
for(T node : allNodes){ for(T node : allNodes){
Object parentId = getProperty(node, Cons.FieldName.parentId.name()); Object parentId = getProperty(node, parentIdFieldName);
if(parentId == null || V.fuzzyEqual(parentId, rootNodeId)){ if(parentId == null || V.fuzzyEqual(parentId, rootNodeId)){
topLevelModels.add(node); topLevelModels.add(node);
} }
@ -364,8 +377,8 @@ public class BeanUtils {
// 遍历第一级节点并挂载 children 子节点 // 遍历第一级节点并挂载 children 子节点
for(T node : allNodes) { for(T node : allNodes) {
Object nodeId = getProperty(node, Cons.FieldName.id.name()); Object nodeId = getProperty(node, Cons.FieldName.id.name());
List<T> children = buildTreeChildren(nodeId, allNodes); List<T> children = buildTreeChildren(nodeId, allNodes, parentIdFieldName, childrenFieldName);
setProperty(node, Cons.FieldName.children.name(), children); setProperty(node, childrenFieldName, children);
} }
return topLevelModels; return topLevelModels;
} }
@ -374,12 +387,14 @@ public class BeanUtils {
* 递归构建树节点的子节点 * 递归构建树节点的子节点
* @param parentId * @param parentId
* @param nodeList * @param nodeList
* @param parentIdFieldName 父节点属性名
* @param childrenFieldName 子节点集合属性名
* @return * @return
*/ */
private static <T> List<T> buildTreeChildren(Object parentId, List<T> nodeList) { private static <T> List<T> buildTreeChildren(Object parentId, List<T> nodeList, String parentIdFieldName, String childrenFieldName) {
List<T> children = null; List<T> children = null;
for(T node : nodeList) { for(T node : nodeList) {
Object nodeParentId = getProperty(node, Cons.FieldName.parentId.name()); Object nodeParentId = getProperty(node, parentIdFieldName);
if(nodeParentId != null && V.equals(nodeParentId, parentId)) { if(nodeParentId != null && V.equals(nodeParentId, parentId)) {
if(children == null){ if(children == null){
children = new ArrayList<>(); children = new ArrayList<>();
@ -390,11 +405,11 @@ public class BeanUtils {
if(children != null){ if(children != null){
for(T child : children) { for(T child : children) {
Object nodeId = getProperty(child, Cons.FieldName.id.name()); Object nodeId = getProperty(child, Cons.FieldName.id.name());
List<T> childNodeChildren = buildTreeChildren(nodeId, nodeList); List<T> childNodeChildren = buildTreeChildren(nodeId, nodeList, parentIdFieldName, childrenFieldName);
if(childNodeChildren == null) { if(childNodeChildren == null) {
childNodeChildren = new ArrayList<>(); childNodeChildren = new ArrayList<>();
} }
setProperty(child, Cons.FieldName.children.name(), childNodeChildren); setProperty(child, childrenFieldName, childNodeChildren);
} }
} }
return children; return children;

View File

@ -258,8 +258,22 @@ public class ContextHelper implements ApplicationContextAware {
} }
if(jdbcUrl == null){ if(jdbcUrl == null){
String master = environment.getProperty("spring.datasource.dynamic.primary"); String master = environment.getProperty("spring.datasource.dynamic.primary");
if(master != null){
jdbcUrl = environment.getProperty("spring.datasource.dynamic.datasource."+master+".url"); jdbcUrl = environment.getProperty("spring.datasource.dynamic.datasource."+master+".url");
} }
}
if(jdbcUrl == null){
String names = environment.getProperty("spring.shardingsphere.datasource.names");
if(names != null){
jdbcUrl = environment.getProperty("spring.shardingsphere.datasource."+ names.split(",")[0] +".url");
}
}
if(jdbcUrl == null){
String urlConfigItem = environment.getProperty("diboot.datasource.url.config");
if(urlConfigItem != null){
jdbcUrl = environment.getProperty(urlConfigItem);
}
}
return jdbcUrl; return jdbcUrl;
} }

View File

@ -31,7 +31,7 @@ import java.util.List;
@Accessors(chain = true) @Accessors(chain = true)
public class DictionaryVO extends Dictionary { public class DictionaryVO extends Dictionary {
@BindEntityList(entity= Dictionary.class, condition="this.type=type AND parent_id>0") @BindEntityList(entity= Dictionary.class, condition="this.type=type AND this.id=parent_id")
private List<Dictionary> children; private List<Dictionary> children;
} }

View File

@ -112,6 +112,7 @@ public class TestEntityListBinder {
// 查询是否创建成功 // 查询是否创建成功
LambdaQueryWrapper<Dictionary> queryWrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<Dictionary> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Dictionary::getType, "GENDER"); queryWrapper.eq(Dictionary::getType, "GENDER");
queryWrapper.eq(Dictionary::getParentId, 0L);
Dictionary dictionary = dictionaryService.getSingleEntity(queryWrapper); Dictionary dictionary = dictionaryService.getSingleEntity(queryWrapper);
DictionaryVO vo = Binder.convertAndBindRelations(dictionary, DictionaryVO.class); DictionaryVO vo = Binder.convertAndBindRelations(dictionary, DictionaryVO.class);

View File

@ -35,7 +35,7 @@ public class EntityBinderVO extends User {
private static final long serialVersionUID = 3526115343377985725L; private static final long serialVersionUID = 3526115343377985725L;
// 字段关联相同条件的entity+condition将合并为一条SQL查询 // 字段关联相同条件的entity+condition将合并为一条SQL查询
@BindEntity(entity= Department.class, condition="this.department_id=id AND parent_id >= 0") @BindEntity(entity= Department.class, condition="this.department_id=id AND name like '发'")
private Department department; private Department department;
// 通过中间表关联Entity // 通过中间表关联Entity

View File

@ -312,12 +312,30 @@ public class BaseServiceTest {
List<DictionaryVO> voList = dictionaryService.getViewObjectList(queryWrapper, pagination, DictionaryVO.class); List<DictionaryVO> voList = dictionaryService.getViewObjectList(queryWrapper, pagination, DictionaryVO.class);
Assert.assertTrue(voList.size() == 1); Assert.assertTrue(voList.size() == 1);
Assert.assertTrue(pagination.getTotalPage() >= 2); Assert.assertTrue(pagination.getTotalPage() >= 2);
Assert.assertTrue(V.isEmpty(voList.get(0).getChildren()));
pagination.setPageIndex(2); pagination.setPageIndex(2);
voList = dictionaryService.getViewObjectList(queryWrapper, pagination, DictionaryVO.class); voList = dictionaryService.getViewObjectList(queryWrapper, pagination, DictionaryVO.class);
Assert.assertTrue(voList.size() == 1); Assert.assertTrue(voList.size() == 1);
} }
@Test
public void testDictVo(){
Dictionary dict = new Dictionary();
dict.setParentId(0L);
dict.setType("GENDER");
dict.setEditable(true);
QueryWrapper<Dictionary> queryWrapper = QueryBuilder.toQueryWrapper(dict);
List<DictionaryVO> voList = dictionaryService.getViewObjectList(queryWrapper, null, DictionaryVO.class);
Assert.assertTrue(voList.size() == 1);
Assert.assertTrue(voList.get(0).getChildren().size() == 2);
List<KeyValue> keyValues = dictionaryService.getKeyValueList("GENDER");
Assert.assertTrue(keyValues.size() == 2);
}
/** /**
* 测试n-n的批量新建/更新 * 测试n-n的批量新建/更新
*/ */

View File

@ -174,6 +174,11 @@ public class BeanUtilsTest {
Assert.assertEquals(list.size(), 1); Assert.assertEquals(list.size(), 1);
Assert.assertEquals(list.get(0).getChildren().size(), 5); Assert.assertEquals(list.get(0).getChildren().size(), 5);
list = BeanUtils.convertList(dictionaryList, DictionaryVO.class);
list = BeanUtils.buildTree(list, 0, "parentId", "children");
Assert.assertEquals(list.size(), 1);
Assert.assertEquals(list.get(0).getChildren().size(), 5);
// 异常数据告警 // 异常数据告警
Dictionary dict2 = new Dictionary(); Dictionary dict2 = new Dictionary();
dict2.setId(1L); dict2.setId(1L);
@ -182,6 +187,7 @@ public class BeanUtilsTest {
list = BeanUtils.convertList(dictionaryList, DictionaryVO.class); list = BeanUtils.convertList(dictionaryList, DictionaryVO.class);
try{ try{
list = BeanUtils.buildTree(list); list = BeanUtils.buildTree(list);
Assert.assertTrue(false);
} }
catch (Exception e){ catch (Exception e){
Assert.assertTrue(e.getMessage().contains("请检查")); Assert.assertTrue(e.getMessage().contains("请检查"));

View File

@ -21,7 +21,9 @@ import diboot.core.test.config.SpringMvcConfig;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.env.Environment;
import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.junit4.SpringRunner;
@ -36,6 +38,9 @@ import org.springframework.test.context.junit4.SpringRunner;
@SpringBootTest(classes = {StartupApplication.class}) @SpringBootTest(classes = {StartupApplication.class})
public class PropertiesTest { public class PropertiesTest {
@Autowired
private Environment environment;
@Test @Test
public void testGetString(){ public void testGetString(){
String str1 = PropertiesUtils.get("spring.datasource.url"); String str1 = PropertiesUtils.get("spring.datasource.url");
@ -49,4 +54,23 @@ public class PropertiesTest {
Integer num = PropertiesUtils.getInteger("spring.datasource.hikari.maximum-pool-size"); Integer num = PropertiesUtils.getInteger("spring.datasource.hikari.maximum-pool-size");
Assert.assertTrue(num > 0 ); Assert.assertTrue(num > 0 );
} }
@Test
public void testDatasourceUrl(){
String jdbcUrl = null;
if(jdbcUrl == null){
String names = environment.getProperty("spring.shardingsphere.datasource.names");
if(names != null){
jdbcUrl = environment.getProperty("spring.shardingsphere.datasource."+ names.split(",")[0] +".url");
}
}
if(jdbcUrl == null){
String urlConfigItem = environment.getProperty("diboot.datasource.url.config");
if(urlConfigItem != null){
jdbcUrl = environment.getProperty(urlConfigItem);
}
}
System.out.println(jdbcUrl);
Assert.assertTrue(jdbcUrl != null);
}
} }

View File

@ -15,6 +15,7 @@
*/ */
package diboot.core.test.util; package diboot.core.test.util;
import com.diboot.core.entity.Dictionary;
import com.diboot.core.util.S; import com.diboot.core.util.S;
import com.diboot.core.util.V; import com.diboot.core.util.V;
import org.junit.Assert; import org.junit.Assert;
@ -85,6 +86,11 @@ public class VTest {
Assert.assertTrue(V.equals(list1, list2)); Assert.assertTrue(V.equals(list1, list2));
} }
@Test
public void testValidateBean(){
String msg = V.validateBean(new Dictionary());
System.out.println(msg);
Assert.assertTrue(msg != null);
}
} }

View File

@ -156,11 +156,11 @@ module.exports = {
items: [ items: [
{ {
text: 'Gitee', text: 'Gitee',
link: 'https://gitee.com/dibo_software/diboot-v2' link: 'https://gitee.com/dibo_software/diboot'
}, },
{ {
text: 'GitHub', text: 'GitHub',
link: 'https://github.com/dibo-software/diboot-v2' link: 'https://github.com/dibo-software/diboot'
} }
] ]
}/*, { }/*, {

View File

@ -18,7 +18,7 @@ diboot-antd-admin前端基础项目是一个与diboot其他后端组件构成
* 基于开源项目[ant-design-pro-vue](https://github.com/sendya/ant-design-pro-vue) * 基于开源项目[ant-design-pro-vue](https://github.com/sendya/ant-design-pro-vue)
* 在**ant-design-pro-vue**项目基础上,进行精简; * 在**ant-design-pro-vue**项目基础上,进行精简;
* 登录、权限、接口对接上与diboot-v2相关组件构建的后端应用无缝集成且开箱可用; * 登录、权限、接口对接上与diboot相关组件构建的后端应用无缝集成且开箱可用
* 提取CRUD页面相关通用属性与方法到mixins文件中少写代码多做事情 * 提取CRUD页面相关通用属性与方法到mixins文件中少写代码多做事情
* 菜单到按钮级别的细粒度权限控制; * 菜单到按钮级别的细粒度权限控制;
* 智能化的权限配置方案; * 智能化的权限配置方案;

View File

@ -54,9 +54,9 @@ devServer: {
执行以下命令启动项目 执行以下命令启动项目
```bash ```bash
yarn server yarn serve
# OR # OR
npm run server npm run serve
``` ```
运行完成后,点击命令行提示出的地址,打开页面成功,项目启动就完成了。 运行完成后,点击命令行提示出的地址,打开页面成功,项目启动就完成了。

View File

@ -89,7 +89,7 @@ private Organization organization;
@BindEntityList(entity = Department.class, condition="department_id=id") @BindEntityList(entity = Department.class, condition="department_id=id")
private List<Department> departmentList; private List<Department> departmentList;
// 关联自身,实现无限极分类等 // 关联自身,实现加载子级
@BindEntityList(entity = Department.class, condition = "id=parent_id") @BindEntityList(entity = Department.class, condition = "id=parent_id")
private List<Department> children; private List<Department> children;
``` ```

View File

@ -13,7 +13,7 @@
4. 跨表Join查询无SQLQueryWrapper自动构建与查询 4. 跨表Join查询无SQLQueryWrapper自动构建与查询
5. BaseService扩展增强支持常规的单表及关联开发场景接口 5. BaseService扩展增强支持常规的单表及关联开发场景接口
6. 其他常用Service接口、工具类的最佳实践封装 6. 其他常用Service接口、工具类的最佳实践封装
7. 提供[diboot-core-starter](https://github.com/dibo-software/diboot-v2-example/tree/master/diboot-core-example)简化diboot-core的初始化配置自动配置、自动创建数据字典表 7. 提供[diboot-core-starter](https://github.com/dibo-software/diboot-example/tree/master/diboot-core-example)简化diboot-core的初始化配置自动配置、自动创建数据字典表
## diboot-core 使用步骤 ## diboot-core 使用步骤
### 1. 引入依赖 ### 1. 引入依赖
@ -48,7 +48,7 @@ spring.datasource.hikari.driver-class-name=com.mysql.cj.jdbc.Driver
diboot.core.init-sql=false diboot.core.init-sql=false
~~~ ~~~
### 3. 参考样例 - [diboot-core-example](https://github.com/dibo-software/diboot-v2-example/tree/master/diboot-core-example) ### 3. 参考样例 - [diboot-core-example](https://github.com/dibo-software/diboot-example/tree/master/diboot-core-example)
> diboot-core的最佳实践建议自定义自己的Base类避免直接继承core中的Base类便于后期扩展。 > diboot-core的最佳实践建议自定义自己的Base类避免直接继承core中的Base类便于后期扩展。
启用devtools可一键生成初始Base类代码到本地。 启用devtools可一键生成初始Base类代码到本地。

View File

@ -157,6 +157,6 @@ diboot-devtools在初次运行中会自动检测安装以diboot_前缀的数
单独为devtools建立一个专属项目生成代码路径指向你的项目代码需要使用devtools时启动这个devtools项目。 单独为devtools建立一个专属项目生成代码路径指向你的项目代码需要使用devtools时启动这个devtools项目。
## 参考样例 ## 参考样例
devtools使用样例(gradle配置) [diboot-devtools-example](https://github.com/dibo-software/diboot-v2-example/tree/master/diboot-devtools-example) devtools使用样例(gradle配置) [diboot-devtools-example](https://github.com/dibo-software/diboot-example/tree/master/diboot-devtools-example)
> 使用过程中遇到问题,可加群交流。 > 使用过程中遇到问题,可加群交流。

View File

@ -18,7 +18,7 @@ diboot-element-admin前端基础项目是一个与diboot其他后端组件构
* 基于开源项目[vue-element-admin](https://panjiachen.github.io/vue-element-admin-site/zh/)的基础模板[vue-admin-template](https://github.com/PanJiaChen/vue-admin-template) * 基于开源项目[vue-element-admin](https://panjiachen.github.io/vue-element-admin-site/zh/)的基础模板[vue-admin-template](https://github.com/PanJiaChen/vue-admin-template)
* 在**vue-admin-template**项目基础上增加了vue-element-admin具有的多页签、菜单搜索、全屏显示、调整布局大小等功能 * 在**vue-admin-template**项目基础上增加了vue-element-admin具有的多页签、菜单搜索、全屏显示、调整布局大小等功能
* 登录、权限、接口对接上与diboot-v2相关组件构建的后端应用无缝集成且开箱可用; * 登录、权限、接口对接上与diboot相关组件构建的后端应用无缝集成且开箱可用
* 提取CRUD页面相关通用属性与方法到mixins文件中少写代码多做事情 * 提取CRUD页面相关通用属性与方法到mixins文件中少写代码多做事情
* 菜单到按钮级别的细粒度权限控制; * 菜单到按钮级别的细粒度权限控制;
* 智能化的权限配置方案; * 智能化的权限配置方案;

View File

@ -29,9 +29,9 @@ npm install
执行以下命令启动项目 执行以下命令启动项目
```bash ```bash
yarn server yarn serve
# OR # OR
npm run server npm run serve
``` ```
运行完成后,点击命令行提示出的地址,打开页面成功,项目启动就完成了。 运行完成后,点击命令行提示出的地址,打开页面成功,项目启动就完成了。

View File

@ -163,6 +163,6 @@ ZipHelper.zipFile(String srcRootDir, File file, ZipOutputStream zos, String... m
~~~ ~~~
## 4 样例参考 - [diboot-file-example](https://github.com/dibo-software/diboot-v2-example/tree/master/diboot-file-example) ## 4 样例参考 - [diboot-file-example](https://github.com/dibo-software/diboot-example/tree/master/diboot-file-example)
> 使用过程中遇到问题,可加群交流。 > 使用过程中遇到问题,可加群交流。

View File

@ -18,6 +18,8 @@ compile("com.diboot:diboot-iam-base-spring-boot-starter:{latestVersion}")
> 如果使用diboot-devtools还需要引入devtools相关依赖可一键生成iam-base相关的controller。 > 如果使用diboot-devtools还需要引入devtools相关依赖可一键生成iam-base相关的controller。
注: iam初始化的账号密码为: admin/123456 ,启动成功后请及时修改密码。
## 2、参数配置 ## 2、参数配置
* 注解配置: * 注解配置:
@ -108,6 +110,6 @@ BaseLoginUser loginUser = IamSecurityUtils.getCurrentUser();
// 转型 // 转型
~~~ ~~~
## 6、样例参考 - [diboot-iam-example](https://github.com/dibo-software/diboot-v2-example/diboot-iam-example) ## 6、样例参考 - [diboot-iam-example](https://github.com/dibo-software/diboot-example/diboot-iam-example)
> 使用过程中遇到问题,可加群交流。 > 使用过程中遇到问题,可加群交流。

View File

@ -10,25 +10,44 @@ MyAuthCredential credential = new MyAuthCredential();
String authtoken = AuthServiceFactory.getAuthService("WX_CP").applyToken(credential); String authtoken = AuthServiceFactory.getAuthService("WX_CP").applyToken(credential);
~~~ ~~~
## 2、替换用户类型 ## 2、替换用户类型或扩展多种用户类型
默认的用户实体为IamUser获取当前登录用户对象: 默认的用户实体为IamUser获取当前登录用户对象:
~~~java ~~~java
IamUser currentUser = IamSecurityUtils.getCurrentUser(); IamUser currentUser = IamSecurityUtils.getCurrentUser();
~~~ ~~~
如果预置属性如果不能满足业务场景需要,可替换用户为你的实体: 如果预置属性如果不能满足业务场景需要,可替换用户为你的实体:
* 首先在登录的方法中生成token前传入当前用户类型
(如果有多种用户类型共用登录接口,可以从前端登录页传入"用户类型值"
~~~java ~~~java
MyAuthCredential credential = new MyAuthCredential(); MyAuthCredential credential = new MyAuthCredential();
credential.setUserTypeClass(Employee.class); // 替换用户类型为自定义 credential.setUserTypeClass(Employee.class); // 用户类型为自定义
String authtoken = AuthServiceFactory.getAuthService("WX_CP").applyToken(credential); String authtoken = AuthServiceFactory.getAuthService("WX_CP").applyToken(credential);
~~~ ~~~
获取用户对象改为: 获取用户对象相关代码改为:
~~~java ~~~java
Employee currentUser = IamSecurityUtils.getCurrentUser(); Employee currentUser = IamSecurityUtils.getCurrentUser();
~~~ ~~~
或多种用户:
~~~java
// 获取当前登录用户抽象对象
BaseLoginUser currentUser = IamSecurityUtils.getCurrentUser();
// 查询用户角色
IamRoleVO roleVO = null;
if(currentUser instanceof IamUser){
IamUser user = (IamUser) currentUser;
// 角色权限数据
roleVO = iamUserService.buildRoleVo4FrontEnd(user);
}
else if(currentUser instanceof Employee){
List<IamRoleVO> roleVOList = iamUserRoleService.getAllRoleVOList(currentUser);
roleVO = IamHelper.buildRoleVo4FrontEnd(roleVOList);
}
...
~~~
## 3、替换缓存Manager ## 3、替换缓存Manager
组件默认缓存类为shiro的内存缓存实现MemoryConstrainedCacheManager如果需要替换为redis等自定义缓存 组件默认缓存类为shiro的内存缓存实现MemoryConstrainedCacheManager如果需要替换为redis等自定义缓存
需要创建缓存实现类实现CacheManager接口并配置参数diboot.iam.cache-manager-class为你的缓存类。 需要创建缓存实现类实现CacheManager接口 (可以参考MemoryConstrainedCacheManager的源码)并配置参数diboot.iam.cache-manager-class为你的缓存类。
``` ```
diboot.iam.cache-manager-class=com.xxx.MyCacheManager diboot.iam.cache-manager-class=com.xxx.MyCacheManager
``` ```

View File

@ -10,7 +10,7 @@ IAM的后端基础代码由devtools自动生成
* 启动项目进入devtools的组件初始化页面选择core及IAM等组件执行初始化 * 启动项目进入devtools的组件初始化页面选择core及IAM等组件执行初始化
* devtools将生成IAM基础的代码到你配置的路径下 * devtools将生成IAM基础的代码到你配置的路径下
注:[diboot-v2-example](https://github.com/dibo-software/diboot-v2-example) 中包含可供参考的后端示例diboot-iam-exampleIAM示例代码 注:[diboot-example](https://github.com/dibo-software/diboot-example) 中包含可供参考的后端示例diboot-iam-exampleIAM示例代码
及diboot-online-demo线上演示项目 及diboot-online-demo线上演示项目
## 如何自定义fastjson配置 ## 如何自定义fastjson配置
@ -176,7 +176,7 @@ public class BaseCustomServiceImpl<M extends BaseCrudMapper<T>, T> extends BaseS
} }
} }
~~~ ~~~
## 如何解决数据库无法自动设置更新时间 ## 如何解决数据库无法自动设置更新时间
* 通过Mybatis-plus的MetaObjectHandler接口自动填充示例 * 通过Mybatis-plus的MetaObjectHandler接口自动填充示例
~~~java ~~~java
@Component @Component
@ -187,5 +187,10 @@ public class FillMetaObjectHandler implements MetaObjectHandler {
} }
} }
~~~ ~~~
## 如何解决无法访问的swagger的问题
* 需要设置swagger相关的匿名配置如下
~~~java
diboot.iam.anon-urls=/swagger-ui.html,/swagger-resources/**,/webjars/springfox-swagger-ui/**,/v2/api-docs/**
~~~

View File

@ -488,7 +488,7 @@ attachMoreList: [
* 更新 *element-ui* 依赖: * 更新 *element-ui* 依赖:
```json ```json
{ {
"ant-design-vue": "2.13.2" "element-ui": "2.13.2"
} }
``` ```

View File

@ -138,6 +138,6 @@ diboot-file组件有以下一个配置项用于设置本地文件的存储起
files.storage.directory=/myfile files.storage.directory=/myfile
~~~ ~~~
## 样例参考 - [diboot-file-example](https://github.com/dibo-software/diboot-v2-example/tree/master/diboot-file-example) ## 样例参考 - [diboot-file-example](https://github.com/dibo-software/diboot-example/tree/master/diboot-file-example)
> 使用过程中遇到问题,可加群交流。 > 使用过程中遇到问题,可加群交流。

View File

@ -7,11 +7,11 @@
<parent> <parent>
<artifactId>diboot-root</artifactId> <artifactId>diboot-root</artifactId>
<groupId>com.diboot</groupId> <groupId>com.diboot</groupId>
<version>2.1.1</version> <version>2.1.2</version>
</parent> </parent>
<artifactId>diboot-file-spring-boot-starter</artifactId> <artifactId>diboot-file-spring-boot-starter</artifactId>
<version>2.1.1</version> <version>2.1.2</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<description>diboot file component project</description> <description>diboot file component project</description>
@ -25,7 +25,7 @@
<dependency> <dependency>
<groupId>com.diboot</groupId> <groupId>com.diboot</groupId>
<artifactId>diboot-core-spring-boot-starter</artifactId> <artifactId>diboot-core-spring-boot-starter</artifactId>
<version>2.1.1</version> <version>2.1.2</version>
</dependency> </dependency>
<!-- 文件上传 --> <!-- 文件上传 -->

View File

@ -89,6 +89,6 @@ diboot.iam.enable-permission-check=true
diboot.iam.cache-manager-class=org.apache.shiro.cache.MemoryConstrainedCacheManager diboot.iam.cache-manager-class=org.apache.shiro.cache.MemoryConstrainedCacheManager
``` ```
## 7、样例参考 - [diboot-iam-example](https://github.com/dibo-software/diboot-v2-example/tree/master/diboot-iam-example) ## 7、样例参考 - [diboot-iam-example](https://github.com/dibo-software/diboot-example/tree/master/diboot-iam-example)
> 使用过程中遇到问题,可加群交流。 > 使用过程中遇到问题,可加群交流。

View File

@ -7,11 +7,11 @@
<parent> <parent>
<groupId>com.diboot</groupId> <groupId>com.diboot</groupId>
<artifactId>diboot-root</artifactId> <artifactId>diboot-root</artifactId>
<version>2.1.1</version> <version>2.1.2</version>
</parent> </parent>
<artifactId>diboot-iam-base-spring-boot-starter</artifactId> <artifactId>diboot-iam-base-spring-boot-starter</artifactId>
<version>2.1.1</version> <version>2.1.2</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<description>diboot IAM base project</description> <description>diboot IAM base project</description>
@ -25,7 +25,7 @@
<dependency> <dependency>
<groupId>com.diboot</groupId> <groupId>com.diboot</groupId>
<artifactId>diboot-core-spring-boot-starter</artifactId> <artifactId>diboot-core-spring-boot-starter</artifactId>
<version>2.1.1</version> <version>2.1.2</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.squareup.okhttp3</groupId> <groupId>com.squareup.okhttp3</groupId>

View File

@ -19,6 +19,7 @@ import com.diboot.core.vo.KeyValue;
import com.diboot.iam.entity.IamRole; import com.diboot.iam.entity.IamRole;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* IAM扩展接口 * IAM扩展接口
@ -32,9 +33,10 @@ public interface IamExtensible {
* 获取用户扩展对象 (如当前岗位) * 获取用户扩展对象 (如当前岗位)
* @param userType * @param userType
* @param userId * @param userId
* @param extObj 登录扩展信息
* @return * @return
*/ */
KeyValue getUserExtentionObj(String userType, Long userId); KeyValue getUserExtentionObj(String userType, Long userId, Map<String, Object> extObj);
/** /**
* 获取可扩展的角色 * 获取可扩展的角色

View File

@ -130,8 +130,10 @@ public class PwdAuthServiceImpl implements AuthService {
private BaseJwtAuthToken initBaseJwtAuthToken(AuthCredential credential){ private BaseJwtAuthToken initBaseJwtAuthToken(AuthCredential credential){
BaseJwtAuthToken token = new BaseJwtAuthToken(getAuthType(), credential.getUserTypeClass()); BaseJwtAuthToken token = new BaseJwtAuthToken(getAuthType(), credential.getUserTypeClass());
// 设置账号密码 // 设置账号密码
token.setAuthAccount(credential.getAuthAccount()).setAuthSecret(credential.getAuthSecret()); token.setAuthAccount(credential.getAuthAccount())
token.setRememberMe(credential.isRememberMe()); .setAuthSecret(credential.getAuthSecret())
.setRememberMe(credential.isRememberMe())
.setExtObj(credential.getExtObj());
// 生成token // 生成token
return token.generateAuthtoken(getExpiresInMinutes()); return token.generateAuthtoken(getExpiresInMinutes());
} }

View File

@ -22,6 +22,7 @@ import lombok.experimental.Accessors;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import java.io.Serializable; import java.io.Serializable;
import java.util.Map;
/** /**
* 登录凭证 * 登录凭证
@ -50,6 +51,12 @@ public abstract class AuthCredential implements Serializable {
* 记住我 * 记住我
*/ */
private boolean rememberMe; private boolean rememberMe;
/**
* 扩展属性
*/
private Map<String, Object> extObj;
/** /**
* 账号 * 账号
* @return * @return

View File

@ -15,6 +15,7 @@
*/ */
package com.diboot.iam.jwt; package com.diboot.iam.jwt;
import com.diboot.core.vo.KeyValue;
import com.diboot.iam.config.Cons; import com.diboot.iam.config.Cons;
import com.diboot.iam.entity.IamUser; import com.diboot.iam.entity.IamUser;
import com.diboot.iam.util.JwtUtils; import com.diboot.iam.util.JwtUtils;
@ -24,6 +25,8 @@ import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.RememberMeAuthenticationToken; import org.apache.shiro.authc.RememberMeAuthenticationToken;
import java.util.Map;
/** /**
* @author Yangzhao * @author Yangzhao
* @version v2.0 * @version v2.0
@ -55,6 +58,11 @@ public class BaseJwtAuthToken implements RememberMeAuthenticationToken {
*/ */
private boolean rememberMe; private boolean rememberMe;
/**
* 扩展属性
*/
private Map<String, Object> extObj;
/**authz token*/ /**authz token*/
private String authtoken; private String authtoken;
@ -96,6 +104,8 @@ public class BaseJwtAuthToken implements RememberMeAuthenticationToken {
return userTypeClass.getSimpleName(); return userTypeClass.getSimpleName();
} }
/** /**
* 生成token * 生成token
* @param expiresInMinutes * @param expiresInMinutes

View File

@ -107,7 +107,7 @@ public class BaseJwtRealm extends AuthorizingRealm {
throw new AuthenticationException("用户不存在"); throw new AuthenticationException("用户不存在");
} }
if(iamUserRoleService.getIamExtensible() != null){ if(iamUserRoleService.getIamExtensible() != null){
KeyValue extentionObj = iamUserRoleService.getIamExtensible().getUserExtentionObj(jwtToken.getUserTypeClass().getSimpleName(), account.getUserId()); KeyValue extentionObj = iamUserRoleService.getIamExtensible().getUserExtentionObj(jwtToken.getUserTypeClass().getSimpleName(), account.getUserId(), jwtToken.getExtObj());
if(extentionObj != null){ if(extentionObj != null){
loginUser.setExtentionObj(extentionObj); loginUser.setExtentionObj(extentionObj);
} }

View File

@ -71,9 +71,9 @@ public class IamBaseAutoConfig {
* *
* @return * @return
*/ */
@Bean @Bean(name = "shiroCacheManager")
@ConditionalOnMissingBean(CacheManager.class) @ConditionalOnMissingBean(CacheManager.class)
public CacheManager cacheManager() { public CacheManager shiroCacheManager() {
String className = iamBaseProperties.getCacheManagerClass(); String className = iamBaseProperties.getCacheManagerClass();
if (V.isEmpty(className)) { if (V.isEmpty(className)) {
return null; return null;
@ -87,10 +87,10 @@ public class IamBaseAutoConfig {
} }
@Bean @Bean
@DependsOn({"cacheManager"}) @DependsOn({"shiroCacheManager"})
public Realm realm() { public Realm realm() {
BaseJwtRealm realm = new BaseJwtRealm(); BaseJwtRealm realm = new BaseJwtRealm();
CacheManager cacheManager = cacheManager(); CacheManager cacheManager = shiroCacheManager();
if (cacheManager != null) { if (cacheManager != null) {
realm.setCachingEnabled(true); realm.setCachingEnabled(true);
realm.setCacheManager(cacheManager); realm.setCacheManager(cacheManager);

View File

@ -13,7 +13,7 @@
<groupId>com.diboot</groupId> <groupId>com.diboot</groupId>
<artifactId>diboot-root</artifactId> <artifactId>diboot-root</artifactId>
<version>2.1.1</version> <version>2.1.2</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<modules> <modules>