Hutool
测试代码在sl-express-ms-base-service
的测试用例中,点击查看。
树结构工具-TreeUtil
构建Tree示例
package com.sl.transport.common.util;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import java.util.List;
@Slf4j
class TreeUtilTest {
@Test
void treeTest() {
// 构建node列表
List<TreeNode<String>> nodeList = CollUtil.newArrayList();
nodeList.add(new TreeNode<>("1", "0", "系统管理", 5));
nodeList.add(new TreeNode<>("11", "1", "用户管理", 222222));
nodeList.add(new TreeNode<>("111", "11", "用户添加", 0));
nodeList.add(new TreeNode<>("2", "0", "店铺管理", 1));
nodeList.add(new TreeNode<>("21", "2", "商品管理", 44));
nodeList.add(new TreeNode<>("221", "2", "添加商品", 2));
//配置
TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
// 自定义属性名 都要默认值的
treeNodeConfig.setWeightKey("weight");
treeNodeConfig.setIdKey("id");
// 最大递归深度
treeNodeConfig.setDeep(3);
//构造树结构
List<Tree<String>> treeNodes = TreeUtil.build(nodeList, "0",
(treeNode, tree) -> {
tree.setId(treeNode.getId());
tree.setParentId(treeNode.getParentId());
tree.putAll(BeanUtil.beanToMap(treeNode));
tree.remove("bid");
});
log.info("treeNodes {}", JSONUtil.toJsonStr(treeNodes));
}
}
输出结果
[{
"id": "2",
"parentId": "0",
"name": "店铺管理",
"weight": 1,
"children": [{
"id": "221",
"parentId": "2",
"name": "添加商品",
"weight": 2
}, {
"id": "21",
"parentId": "2",
"name": "商品管理",
"weight": 44
}]
}, {
"id": "1",
"parentId": "0",
"name": "系统管理",
"weight": 5,
"children": [{
"id": "11",
"parentId": "1",
"name": "用户管理",
"weight": 222222,
"children": [{
"id": "111",
"parentId": "11",
"name": "用户添加",
"weight": 0
}]
}]
}]
Bean工具-BeanUtil
对象转Bean
@Slf4j
public class BeanUtilTest {
@Getter
@Setter
public static class SubPerson extends Person {
public static final String SUBNAME = "TEST";
private UUID id;
private String subName;
private Boolean slow;
private LocalDateTime date;
private LocalDate date2;
}
@Getter
@Setter
public static class Person {
private String name;
private int age;
private String openid;
}
/**
* 对象转Bean
*/
@Test
public void toBeanTest() {
SubPerson person = new SubPerson();
person.setAge(14);
person.setOpenid("11213232");
person.setName("测试A11");
person.setSubName("sub名字");
Map<?, ?> map = BeanUtil.toBean(person, Map.class);
Assert.assertEquals("测试A11", map.get("name"));
Assert.assertEquals(14, map.get("age"));
Assert.assertEquals("11213232", map.get("openid"));
// static属性应被忽略
log.info("map是否包含名为SUBNAME的key {}", map.containsKey("SUBNAME"));
}
}
输出结果
map是否包含名为SUBNAME的key false
验证码工具-CaptchaUtil
生成验证码
package com.sl.transport.common.util;
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import lombok.extern.slf4j.Slf4j;
import org.junit.Assert;
import org.junit.Test;
/**
* 直线干扰验证码单元测试
*
* @author looly
*/
@Slf4j
public class CaptchaTest {
/**
* 生成验证码
*/
@Test
public void lineCaptchaTest1() {
// 定义图形验证码的长和宽
LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(200, 100);
Assert.assertNotNull(lineCaptcha.getCode());
log.info("直线干扰验证码: {}", lineCaptcha.getCode());
log.info("直线干扰验证码验证结果: {}",lineCaptcha.verify(lineCaptcha.getCode()));
}
}
输出结果
直线干扰验证码: 5ku0o
直线干扰验证码验证结果: true
类型转换工具类-Convert
转换值为指定类型
/**
* 转换值为指定类型
*/
@Test
public void toObjectTest() {
final Object result = Convert.convert(Object.class, "aaaa");
log.info(result + "");
}
输出结果
aaaa
对象工具-ObjectUtil
对象相等
/**
* 比较两个对象是否相等
*/
@Test
public void equalsTest() {
Object a = null;
Object b = null;
log.info("是否相等:{}" , ObjectUtil.equals(a, b));
}
输出结果
是否相等:true
数字工具-NumberUtil
加法运算
/**
* 提供精确的加法运算
*/
@Test
public void addTest() {
final Float a = 3.15f;
final Double b = 4.22;
final double result = NumberUtil.add(a, b).doubleValue();
log.info(result + "");
}
输出结果
7.37
日期时间工具-DateUtil
当前时间
/**
* 当前时间
*/
@Test
public void nowTest() {
// 当前时间
final Date date = DateUtil.date();
Assert.assertNotNull(date);
// 当前时间
final Date date2 = DateUtil.date(Calendar.getInstance());
Assert.assertNotNull(date2);
// 当前时间
final Date date3 = DateUtil.date(System.currentTimeMillis());
Assert.assertNotNull(date3);
// 当前日期字符串,格式:yyyy-MM-dd HH:mm:ss
final String now = DateUtil.now();
Assert.assertNotNull(now);
// 当前日期字符串,格式:yyyy-MM-dd
final String today = DateUtil.today();
log.info(today);
}
输出结果
2023-03-10
集合工具-CollUtil
自定义函数判断集合是否包含某类值
/**
* 自定义函数判断集合是否包含某类值
*/
@Test
public void testPredicateContains() {
final ArrayList<String> list = CollUtil.newArrayList("bbbbb", "aaaaa", "ccccc");
log.info( "" + CollUtil.contains(list, s -> s.startsWith("a")));
log.info( "" + CollUtil.contains(list, s -> s.startsWith("d")));
}
输出结果
true
false
集合串行流工具-CollStreamUtil
将Collection转化为map
/**
* 将Collection转化为map(value类型与collection的泛型不同)
*/
@Test
public void testToMap() {
Map<Long, String> map = CollStreamUtil.toMap(null, Student::getStudentId, Student::getName);
Assert.assertEquals(map, Collections.EMPTY_MAP);
List<Student> list = new ArrayList<>();
map = CollStreamUtil.toMap(list, Student::getStudentId, Student::getName);
Assert.assertEquals(map, Collections.EMPTY_MAP);
list.add(new Student(1, 1, 1, "张三"));
list.add(new Student(1, 1, 2, "李四"));
list.add(new Student(1, 1, 3, "王五"));
map = CollStreamUtil.toMap(list, Student::getStudentId, Student::getName);
Assert.assertEquals(map.get(1L), "张三");
Assert.assertEquals(map.get(2L), "李四");
Assert.assertEquals(map.get(3L), "王五");
Assert.assertNull(map.get(4L));
// 测试value为空时
list.add(new Student(1, 1, 4, null));
map = CollStreamUtil.toMap(list, Student::getStudentId, Student::getName);
log.info(map.get(4L));
}
输出结果
null
JSON工具-JSONUtil
JSON字符串转JSONObject对象
/**
* JSON字符串转JSONObject对象
*/
@Test
public void toJsonStrTest2() {
final Map<String, Object> model = new HashMap<>();
model.put("mobile", "17610836523");
model.put("type", 1);
final Map<String, Object> data = new HashMap<>();
data.put("model", model);
data.put("model2", model);
final JSONObject jsonObject = JSONUtil.parseObj(data);
log.info("是否相等{}", ObjectUtil.equals( "17610836523", jsonObject.getJSONObject("model").getStr("mobile")));
}
输出结果
是否相等true
唯一ID工具-IdUtil
获取随机UUID
/**
*获取随机UUID
*/
@Test
public void randomUUIDTest() {
String randomUUID = IdUtil.randomUUID();
log.info(randomUUID);
}
输出结果
e514518b-21d7-4918-9b34-792b21b0b64f
枚举工具-EnumUtil
枚举类中所有枚举对象的name列表
public enum TestEnum{
TEST1("type1"), TEST2("type2"), TEST3("type3");
TestEnum(String type) {
this.type = type;
}
private final String type;
@SuppressWarnings("unused")
private String name;
public String getType() {
return this.type;
}
public String getName() {
return this.name;
}
}
/**
* 枚举类中所有枚举对象的name列表
*/
@Test
public void getNamesTest() {
List<String> names = EnumUtil.getNames(TestEnum.class);
boolean equalList = CollUtil.isEqualList(CollUtil.newArrayList("TEST1", "TEST2", "TEST3"), names);
log.info(equalList + "");
}
输出结果
true
了解权限管家
介绍
公司有多个业务系统,这些业务系统的公共部分包括组织、用户、权限等系统管理: 这个公共的系统管理,可以剥离出一套基础组件服务,即权限管家。
传智权限管家是一个通用的权限管理中台服务,在神领物流项目中,我们使用权限系统管理企业内部员工,比如:快递员、司机、管理员等。
在权限管家中可以管理用户,管理后台系统的菜单,以及角色的管理。
逻辑模型
权限管家的接口根据管理范围分为公司级、应用级和系统接口,如下图:
部署安装
参考:https://sl-express.itheima.net/#/zh-cn/base-service?id=权限管家
登录
登录地址:http://auth.sl-express.com/api/authority/static/index.html#/login
用户名密码:admin/123456
应用管理
权限管家是一个多应用的管理系统,所以要接入权限管家首先需要创建应用。
【应用管理】 => 【添加应用】
创建成功:
查看应用所对应的ID和CODE:
组织管理
一般公司会设置不同的组织结构用来管理人员,比如:总部、分公司、人事部、行政部、财务部、物流部、物流转运等。
添加组织,组织是一颗树,所以需要选择上级组织:
添加完成:
进入应用
对于应用的操作需要进入到应用中才能操作:
进入应用后,可以看到左侧菜单有3项管理:【用户管理】、【菜单管理】、【角色管理】
对应的后台系统的菜单列表:(不要修改)
应用中的角色:
新增用户
新增用户需要【返回权限管家】进行操作,在【用户管理】中【新增用户】:
新增用户:
添加成功:
分配角色
现在为【test01】分配快递员角色,怎么操作呢?
首先需要进入到【神领物流】应用,在【用户管理】中分配角色:
这样,test01就拥有了【快递员】角色了。
同理,可以添加其他的用户了。
SDK使用说明
关于authority-sdk
authority-sdk是基于authority-sdk的restful接口实现的Java SDK的封装,实现了token、组织、菜单、角色等功能。
快速集成使用
authority-sdk提供了两种方式与业务系统对接,分别是:
- java sdk方式
- Spring Boot集成方式
使用方法
java sdk方式
第一步,导入maven依赖
<dependency>
<groupId>com.itheima.em.auth</groupId>
<artifactId>authority-sdk</artifactId>
<version>{version}</version>
</dependency>
第二步,实例化AuthTemplate对象
String host = "127.0.0.1"; //Authority服务地址
int port = 8764; //Authority服务端口
int timeout = 1000; //http请求的超时时间,不传值默认为10S
//token,非登录请求都需要带上,一般情况下登录成功后将该数据放入缓存中
String token = "eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiIxIiwiYWNjb3VudCI6ImFkbWluIiwibmFtZSI6IuW5s-WPsOeuoeeQhuWRmCIsIm9yZ2lkIjo4NzQyMjc2MTUxNzM0NDk4MjUsInN0YXRpb25pZCI6ODU3OTQwMTU3NDYwOTU3NTM3LCJhZG1pbmlzdHJhdG9yIjp0cnVlLCJleHAiOjE2NTEyNTkyODB9.anqT0MD9zAr13KG9OE4mqHHK2UMCOXUjeMrEsN1wy9_a14zFbjPkiDZ8dM7JirsAgj61yvshoP6pqBImdmyilQN-iFSa_ci15Ii4HhfFE1mcaRon3ojX_T9ncjHKuF9Y9ZPKT68NOzOfCwvhDrG_sDiaI1C-TwEJmhLM78FhwAI";
//应用ID,非登录请求都需要带上,该参数表示你需要查询哪个应用相关数据,一般情况下置于配置文件中
Long applicationId = 1L;
//登录获取token
AuthTemplate authTemplate = new AuthTemplate(host,port,TIME_OUT);
Result<LoginDTO> result = authTemplate.opsForLogin().token("admin","123456");
//后续基于AuthTemplate可以调用各种服务
AuthTemplate authTemplate = new AuthTemplate(host,port,TIME_OUT,token,applicationId);
Result<List<MenuDTO>> result = authTemplate.opsForPermission().getMenu();
log.info("菜单:{}", JSONObject.toJSONString(result));
Spring Boot集成方式
第一步,导入maven依赖
<dependency>
<groupId>com.itheima.em.auth</groupId>
<artifactId>itcast-auth-spring-boot-starter</artifactId>
<version>1.0</version>
</dependency>
<!-- 如果是SNAPSHOT版本,如要在项目的pom.xml文件中引入快照版源 -->
<repositories>
<repository>
<id>sonatypeSnapshots</id>
<name>Sonatype Snapshots</name>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
<url>https://s01.oss.sonatype.org/content/repositories/snapshots/</url>
</repository>
</repositories>
第二步,配置application.yml文件
itcast:
authority:
host: 127.0.0.1 #authority服务地址,根据实际情况更改
port: 8764 #authority服务端口
timeout: 10000 #http请求的超时时间
第三步,使用用例
package com.example.demo.service;
import com.alibaba.fastjson.JSONObject;
import com.itheima.auth.sdk.AuthTemplate;
import com.itheima.auth.sdk.common.Result;
import com.itheima.auth.sdk.dto.LoginDTO;
import com.itheima.auth.sdk.dto.MenuDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.List;
@Slf4j
@Service
public class AuthService {
@Value("${itcast.authority.host}")
private String host;
@Value("${itcast.authority.port}")
private int port;
private final static int TIME_OUT = 10000;
/**
* 登录获取token
* @param account
* @param password
*/
public void login(String account, String password) {
AuthTemplate authTemplate = new AuthTemplate(host,port);
Result<LoginDTO> loginDTO = authTemplate.opsForLogin().token(account, password);
log.info("登录结果:{}", JSONObject.toJSONString(loginDTO));
}
}