Shiro

shiro实现权限

其他框架:

sprintSecurity(还未研究,据说类似)

配置步骤:

  1. 导入maven
  2. 添加ShiroConfig
  3. 创建UserRealm

注意:

  • 在过滤器创建的时候是 LinkedHashMap 千万注意, 不然通配符不会匹配,会被覆盖掉
  • 过滤器创建时可设置未授权跳转页面,不适用于分离项目
  • 过滤工厂创建的时候可以放入自定义拦截器,用于项目自己的业务
  • 可以在subject.login()之前,通过对session设置来修改登录过期时间

核心:

  • Subject 获取当前对象
  • token可用username,password生成
  • 可使用Md5Hash进行加密
  • 在调用login后通过捕获异常来区别不同的登录情况
1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.7.1</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
package com.jcDemo.shiro;

import com.jcDemo.interceptor.MyFormAuthenticationFilter;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
*@author:gao_quansui
*@user:ASUS
*@date:2022/9/21- 10:57
*@projectName:jc_demo
*/

@Configuration
public class ShiroConfig {

@Bean
public UserRealm userRealm() {
return new UserRealm();
}

@Bean(name = "filterShiroFilterRegistrationBean")
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("SecurityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
//1.创建过滤工厂
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();

Map<String, Filter> filters = new LinkedHashMap<>();
filters.put("MyFormAuthenticationFilter", new MyFormAuthenticationFilter());
bean.setFilters(filters);
//2.设置安全管理器
bean.setSecurityManager(defaultWebSecurityManager);

//3.配置未授权跳转页面
// bean.setLoginUrl("/test");
// bean.setLoginUrl(null);

//4.设置filter
Map<String, String> filterMap = new LinkedHashMap<>();
filterMap.put("/api/user/login", "anon");

filterMap.put("/api/**", "MyFormAuthenticationFilter");

bean.setFilterChainDefinitionMap(filterMap);

return bean;
}

@Bean(name = "SecurityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(userRealm);
return securityManager;
}

//开启shiro注解
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
}

//开启aop注解支持
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
defaultAAP.setProxyTargetClass(true);
return defaultAAP;
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
package com.jcDemo.shiro;

import com.jcDemo.entity.entities.User;
import com.jcDemo.entity.vo.UidUsernameName;
import com.jcDemo.service.user.RoleService;
import com.jcDemo.service.user.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;

/**
*@author:gao_quansui
*@user:ASUS
*@date:2022/9/21- 10:07
*@projectName:jc_demo
*/
@Slf4j
public class UserRealm extends AuthorizingRealm {

@Autowired
UserService userService;

@Autowired
RoleService roleService;

//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
log.info("执行====================授权");
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

// Object data = roleService.getUserRoleById(1).getData();
// info.addStringPermission("");

Subject subject = SecurityUtils.getSubject();

User user = (User) subject.getPrincipal(); //下面方法传上来的user对象

//获取当前用户的权限数组
List<UidUsernameName> uidUsernameName = (List<UidUsernameName>) roleService.getUserRoleById(user.getId());

//遍历添加权限
uidUsernameName.forEach(e -> {
info.addStringPermission(e.getRoleName());
log.info("username:{}-------roleName:{}", e.getUsername(), e.getRoleName());
});

return info;
}

//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

UsernamePasswordToken userToken = (UsernamePasswordToken) token;

User user = userService.getUserByName(userToken.getUsername());

if (user == null) {
return null;
}

log.info("认证");

Subject subject = SecurityUtils.getSubject();
// subject.isPermitted("123");
// subject.hasRole("authc");

// if(!userToken.getUsername().equals(user.getUsername())){
// return null; //会在controller中捕获
// }
//
return new SimpleAuthenticationInfo(user, user.getPassword(), ""); //验证密码
// return null;
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package com.jcDemo.interceptor;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.jcDemo.entity.res.Result;
import com.jcDemo.entity.res.ResultCode;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
import org.springframework.util.StringUtils;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
*@author:gao_quansui
*@user:ASUS
*@date:2022/9/28- 10:07
*@projectName:jc_demo
*/
@Slf4j
public class MyFormAuthenticationFilter extends FormAuthenticationFilter {
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
log.info("被shiro拦截啦=================================");

PrintWriter out = null;
try {
HttpServletResponse res = (HttpServletResponse) response;
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
out = response.getWriter();
if (res.getStatus() == HttpServletResponse.SC_UNAUTHORIZED) {
out.println(JSON.toJSONString(new Result(ResultCode.UNAUTHORISE)));
} else {
if (StringUtils.isEmpty(((ShiroHttpServletRequest) request).getHeader("Authorization"))) {
log.info("未登录");
out.write(JSONObject.toJSONString(new Result(ResultCode.UNAUTHENTICATED, "")));
} else {
log.info("session已过期");
out.write(JSONObject.toJSONString(new Result(ResultCode.EXPIREDSESSION, "")));
}
}
} catch (IOException e) {
log.info("session异常");
} finally {
if (out != null) {
out.close();
}
}
return Boolean.FALSE;
}

@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
return super.isAccessAllowed(request, response, mappedValue);
}
}

整合swagger

整合swagger

Swagger简介

(12条消息) swagger使用教程——快速使用swagger_其实不会敲代码的博客-CSDN博客_swagger使用

Step

  1. maven依赖
  2. 配置SwaggerConfig(作者,项目名,邮件等)
  3. 启动后访问路径Swagger UI

使用

  • 实体类中
    • @ApiModel类描述
    • @ApiModelProperty类中字段描述
  • 控制器中
    • @Api控制器描述
    • @ApiOperation接口描述
1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package com.jcDemo.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

/**
*@author:gao_quansui
*@user:ASUS
*@date:2022/9/22- 10:08
*@projectName:jc_demo
*/
@Configuration
public class SwaggerConfig {
@Bean
public Docket docket() {
return new Docket(DocumentationType.OAS_30).apiInfo(
new ApiInfoBuilder()
.contact(new Contact("gqs", "", ""))
.title("JC_Demo")
.build()
);
}
}

整合redis缓存

整合redis缓存

分布式锁的实现和解析

(12条消息) 分布式锁之Redis实现_kuan_sun的博客-CSDN博客_redis锁的实现

整合步骤:

  1. 下载redis,解压,修改配置文件(redis.windows.conf)
  2. 导入redis启动依赖
  3. 创建redis配置类 (主要是对于kv的序列化和反序列化)
  4. 启动redis-server.exe (redis服务)(同时也可以通过指定配置文件进行启动—集群)
  5. 启动redis-cli.exe (操作客户端)

注意:

  • HashMap不能设置过期时间!!!
  • 使用device:No_001:Name 的方式来存放K
  • 在存放value(对象)时 需要导入FastJson来进行操作
  • redis操作都在redisTemplate中,有很多操作,需要熟悉

引入缓存可能导致的问题(目前能想到的)

  1. 在修改后,需要对缓存进行操作,不然缓存中的数据有误
    1. 在修改时判断是否有缓存 ?
      1. 有:改缓存,利用缓存来修改持久层的(可以慢慢操作,在缓存失效之前操作完)
      2. 没有:修改持久层的,存缓存(有修改,一定马上会用到)
  2. 删除两边都得删
  3. 新增时添加缓存(新增也一定马上会用到)
  4. 查找时:如果缓存有,是否需要更新过期时间?
  5. 分页需要做缓存吗,怎么做?

可以改进的方向:

  1. redis集群
    1. 利用redis中String来做
      1. setnx device:NO_001_Lock 1 ex time

        Untitled

      2. 0则再用,重试请求;1进行业务操作

      3. 设置过期时间,避免设置锁后宕机死锁 时间需合适

        1. 太短:还没操作完就释放了
        2. 太长:已经操作完了 还锁着
      4. 解决:线程守护

        1. 设置一定时长
        2. 例设置10s 8s时判断是否还在执行? 延长 : 不延长
1
2
3
4
5
<!-- redis依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package com.jcDemo.config;

import com.alibaba.fastjson2.support.spring.data.redis.FastJsonRedisSerializer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.serializer.GenericToStringSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
*@author:gao_quansui
*@user:ASUS
*@date:2022/9/28- 13:41
*@projectName:jc_demo
*/
@Configuration
public class RedisConfig {

@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
FastJsonRedisSerializer<Object> objectFastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// 自定义的RedisTemplate
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
// 设置key的序列化方法
redisTemplate.setKeySerializer(new StringRedisSerializer());
// 核心的设置 1.2.36版本自动提供
redisTemplate.setValueSerializer(objectFastJsonRedisSerializer);
// 对hash的序列化操作设置
redisTemplate.setHashKeySerializer(stringRedisSerializer);
redisTemplate.setHashValueSerializer(objectFastJsonRedisSerializer);
// 注册到工程类
redisTemplate.setConnectionFactory(factory);
return redisTemplate;
}

@Bean
public ValueOperations<String, Object> valueOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForValue();
}

@Bean
public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForHash();
}

@Bean
public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForList();
}

@Bean
public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForSet();
}

@Bean
public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForZSet();
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package com.jcDemo.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.jcDemo.commom.CommonException;
import com.jcDemo.entity.entities.Device;
import com.jcDemo.entity.res.PageResult;
import com.jcDemo.entity.res.Result;
import com.jcDemo.entity.res.ResultCode;
import com.jcDemo.service.device.DeviceService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import lombok.var;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.text.ParseException;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
*@author:gao_quansui
*@user:ASUS
*@date:2022/9/23- 10:51
*@projectName:jc_demo
*/
@Slf4j
@Api(tags = "设备管理")
@RestController
@RequestMapping("/api/device")
public class DeviceController {

@Autowired
DeviceService deviceService;

@Resource
RedisTemplate redisTemplate;

@ApiOperation("查找所有设备")
@GetMapping("/getDevices")
public Result getDevices(@RequestParam(defaultValue = "1") int pageNum,
@RequestParam(defaultValue = "10") int pageSize) {
PageResult pr = null;
try {
Page page = PageHelper.startPage(pageNum, pageSize);
List<Device> devices = deviceService.getDevices();

pr = new PageResult(page.getTotal(), devices);
log.info("pageNum:{},pageSize:{}", pageNum, pageSize);
} catch (CommonException e) {
e.printStackTrace();
return new Result(ResultCode.EMPTY);
}
return new Result(ResultCode.SUCCESS, pr);
}

//设备编号查询
@ApiOperation("查找设备ByNo")
@GetMapping("/getDeviceByNo/{no}")
public Result getDeviceByNo(@PathVariable("no") String no) throws CommonException {
Device device = null;
try {
if (redisTemplate.hasKey("devices:" + no)) {
log.info("重置时间->devices:{}", no);
redisTemplate.expire("devices:" + no, 300, TimeUnit.SECONDS);
log.info("从redis取出来的devices:{}", no);
device = JSON.parseObject(String.valueOf(redisTemplate.opsForValue().get("devices:" + no)), Device.class);
} else {
log.info("从mysql取出来的{}", no);
//mysql没有抛异常 下面捕获返回空
device = deviceService.getDeviceByNo(no);
//取出来存入缓存
redisTemplate.opsForValue().set("devices:" + no, JSON.toJSONString(device), 300, TimeUnit.SECONDS);
}
return new Result(ResultCode.SUCCESS, device);
} catch (CommonException e) {
e.printStackTrace();
return new Result(ResultCode.EMPTY);
}
}

//查询
@ApiOperation("头部查找")
@GetMapping("/searchDevice")
public Result searchDevice(@RequestBody Device device) {
List<Device> devices;
try {
devices = deviceService.searchDevice(device);
return new Result(ResultCode.SUCCESS, devices);
} catch (CommonException e) {
e.printStackTrace();
return new Result(ResultCode.EMPTY);
}
}

@ApiOperation("更新设备")
@PostMapping("/updateDevice")
public Result updateDevice(@RequestBody Device device) throws ParseException {
if (deviceService.updateDevice(device) == 1) {
//更新成功后判断是否有缓存 有就换
if (redisTemplate.hasKey("devices:" + device.getDeviceNo())) {
Boolean delete = redisTemplate.delete("devices:" + device.getDeviceNo());
if (delete) {
redisTemplate.opsForValue().set("devices:" + device.getDeviceNo(), JSON.toJSONString(device), 300, TimeUnit.SECONDS);
} else {
log.warn("缓存更新失败,请检查!");
}
} else {
redisTemplate.opsForValue().set("devices:" + device.getDeviceNo(), JSON.toJSONString(device), 300, TimeUnit.SECONDS);
}
return new Result(ResultCode.SUCCESS);
} else {
return new Result(ResultCode.ERROR);
}
}

@ApiOperation("删除设备")
@DeleteMapping("/delete/{no}")
public Result deleteDeviceById(@PathVariable("no") String no) {
if (deviceService.deleteDeviceByNo(no) == 1) {
//删除成功后处理redis
if (redisTemplate.delete("devices:" + no)) {
log.warn("缓存删除成功");
} else {
//缓存删除失败 or 从select里面取的数据,没有进redis 直接删除也会打印log
log.warn("缓存删除失败,请检查!");
}
return new Result(ResultCode.SUCCESS);
} else {
return new Result(ResultCode.ERROR);
}
}

@ApiOperation("新增设备")
@PostMapping("/insert")
public Result insertDevice(@RequestBody Device device) throws ParseException {
if (deviceService.insertDevice(device) == 1) {
redisTemplate.opsForValue().set("devices:" + device.getDeviceNo(), JSON.toJSONString(device), 300, TimeUnit.SECONDS);
return new Result(ResultCode.SUCCESS);
} else {
return new Result(ResultCode.ERROR);
}
}
}

任务调度框架

学习quartz任务调度框架

介绍

Quartz 是什么?一文带你入坑 - 知乎 (zhihu.com)

其他框架 —— 3千字带你搞懂XXL-JOB任务调度平台 (baidu.com)

  • xxl job (大众点评 许雪里)
  • elasticjob (依托zookeeper)

STEP

  1. 导入maven依赖
  2. 创建自定义Job类 实现Job 在execute中进行任务编写
  3. 创建任务调度工程工厂
  4. 创建定时器(startNow() or startAt(Date date))
  5. schedule.start()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.jcDemo.quartz;

import lombok.extern.slf4j.Slf4j;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
*@author:gao_quansui
*@user:ASUS
*@date:2022/9/29- 14:44
*@projectName:jc_demo
*/
@Slf4j
public class TestJob implements Job {
private static intindex= 1;

@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
String data = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
log.info("第{}次执行 Timed Task, current time :{}",index++, data);
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package com.jcDemo.controller.quartz;

import com.jcDemo.quartz.TestJob;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
*@author:gao_quansui
*@user:ASUS
*@date:2022/9/29- 14:47
*@projectName:jc_demo
*/
@Slf4j
@RestController
public class QuartzController {

@RequestMapping("/quartz/test")
public void test() throws SchedulerException {
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
// 定义任务调度实例, 并与TestJob绑定
JobDetail job = JobBuilder.newJob(TestJob.class)
.withIdentity("testJob", "testJobGroup")
.build();
// 定义触发器, 会马上执行一次, 接着5秒执行一次, 共十次
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("testTrigger", "testTriggerGroup")
.startNow()
.withSchedule(SimpleScheduleBuilder.repeatSecondlyForTotalCount(10, 1))
.build();
// 使用触发器调度任务的执行
scheduler.scheduleJob(job, trigger);
// 开启任务
scheduler.start();
}
}

Untitled

JPA & Java

JAP

  1. @Entity

  2. @Table

  3. @Id

  4. @Query

  5. Sort sort = new Sort(Sort.Direction.DESC, “id”); —→ findAll(sort)

  6. Pageable pageable=PageRequest.of(0,5); 第一页 一页5条

  7. extends JpaRepository<T, ID>

  8. List findByUsername(String username)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    interface PersonRepository extends Repository<User, Long> {
    // and 的查询关系
    List<User> findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname);
    // 包含 distinct 去重,or 的 sql 语法
    List<User> findDistinctPeopleByLastnameOrFirstname(String lastname, String firstname);
    // 根据 lastname 字段查询忽略大小写
    List<User> findByLastnameIgnoreCase(String lastname);
    // 根据 lastname 和 firstname 查询 equal 并且忽略大小写
    List<User> findByLastnameAndFirstnameAllIgnoreCase(String lastname, String firstname);
    // 对查询结果根据 lastname 排序,正序
    List<User> findByLastnameOrderByFirstnameAsc(String lastname);
    // 对查询结果根据 lastname 排序,倒序
    List<User> findByLastnameOrderByFirstnameDesc(String lastname);
    }

![Untitled](D:\hexo warehouse\myblog\source_posts\Untitled-16690181602452.png)

link: Spring Data JPA - Reference Documentation

(16条消息) SpringDataJpa的使用 – 条件查询、排序查询、分页查询_十⑧的博客-CSDN博客_jpa 条件查询

stream

  1. list.stream().map(People::getAge)
  2. filter(i -> i > 5)
  3. count()
  4. collect(Collectors.toList()
  5. People::getAge

tree

  1. code parent_code (queryProcessTree)

    1. 找父节点
    2. 遍历寻找子节点
    3. 递归
    4. 封装数据返回
  2. queryLazyProcessTree 懒加载去除孩子节点数据(估计前端点击展开后继续往下查询)

    1. 找父节点
    2. 找所有ChildNode
    3. isleaf = ChildNode.getParentCode.equals(ParentsCode).count==0 ? false : true
    4. 封装返回
  3. recursive sql

1
2
3
4
5
6
with recursive temp(id,username,pid,pname) AS (
SELECT k.id,k.username,k.pid,k.username from t_parent_kid k WHERE k.username='B'
UNION ALL
SELECT k.id,k.username,t.id,t.username from temp t,t_parent_kid k WHERE t.id=k.pid
)
SELECT * from temp

![Untitled 1](D:\hexo warehouse\myblog\source_posts\Untitled 1-16690181860235.png)

![Untitled 2](D:\hexo warehouse\myblog\source_posts\Untitled 2-16690181910378.png)

union all / union

uniall 整合两张表 上下连接,去重

uniall all 整合两张表 上下连接,列出全部

学习并发

学习并发

  1. 创建线程的方式

    • 继承Thread类创建

      • 已经继承的类无法使用

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        public class ExtendThread extends Thread {

        }

        @Test
        void test1() {
        ExtendThread extendThread = new ExtendThread();
        log.info("threadId:{}", extendThread.getId());
        log.info("threadName:{}", extendThread.getName());
        log.info("threadState:{}", extendThread.getState());
        log.info("threadPriority:{}", extendThread.getPriority());
        }
    • 实现Runnable接口

      • 可以使用匿名对象来进行实现,减少代码

        1
        2
        3
        4
        5
        6
        7
        @Test
        void test4(){
        Thread thread = new Thread(()->{
        System.out.println("lambda+匿名对象类");
        },"threadName");
        thread.start();
        }
    • 利用Callable和FutureTask创建

      • 异步?
    • 通过线程池创建

      • 减少线程创建、销毁时间

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        private static ExecutorServicepool= Executors.newFixedThreadPool(3);

        static class DemoThread implements Runnable{
        @SneakyThrows
        @Override
        public void run() {
        for (int i = 0; i < 10; i++) {
        log.info("execute times of runnable thread:{}",i);
        }
        }
        }

        static class ReturnableTask implements Callable<Long>{
        public Long call() throws Exception{
        long startTime = System.currentTimeMillis();
        for (int i = 0; i <10; i++) {
        log.info("execute times of Callable Thread:{}",i);
        }
        long used = System.currentTimeMillis() - startTime;
        return used;
        }
        }

        @Test
        public void test5() throws ExecutionException, InterruptedException {
        pool.execute(new DemoThread());
        // 无返回值

        Future future =pool.submit(new ReturnableTask());
        Long result = (Long) future.get();
        log.info("异步的结果为:{}",result);
        // 有返回值
        }
  2. 线程池

    1. 创建线程池

      1. 固定数量线程池

        1. ExecutorService pool = Executors.newFixedThreadPool(3);
      2. 缓存线程池

        1. ExecutorService pool = Executors.newCachedThreadPool();
      3. 定时执行线程池

        1. ScheduledExecutorService pool = Executors.newScheduledThreadPool(2);
      4. 线程池标准创建方式

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        public class ThreadPoolExecutor{
        // 核心线程数,即使线程空闲(Idle),也不会回收;
        int corePoolSize;

        // 线程数的上限;
        int maximumPoolSize;

        // 线程最大空闲(Idle)时长
        long keepAliveTime;

        //单位?
        TimeUnit unit;

        // 任务的排队队列
        BlockingQueue<Runnable> workQueue;

        // 新线程的产生方式
        ThreadFactory threadFactory;

        // 拒绝策略
        RejectedExecutionHandler handler;
        }
    2. 向线程池提交的方式

      1. execute
        1. 只能接收Runnable类型的参数
        2. 没有返回值
        3. 不利于异常捕获
      2. submit
        1. 能接受Runnable 和 Callable
        2. 有返回值
        3. 可以通过返回的Future(异步执行实例)对象来进行异常捕获
    3. 线程工厂

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Test
    public void test9() {
    ExecutorService my_pool = Executors.newFixedThreadPool(2, new My_thread_factory());

    for (int i = 0; i < 5; i++) {
    my_pool.execute(new Task());
    }
    pool.shutdown();
    }
  3. 线程安全

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    package com.example.jc_demo.ThreadTest;

    import lombok.extern.slf4j.Slf4j;
    import org.junit.jupiter.api.Test;

    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;

    /**
    *@AUTHOR:gao_quansui
    *@USER:ASUS
    *@DATE:2022/10/13 - 15:43
    *@PROJECT_NAME:jc_demo
    */

    @Slf4j
    public class ThreadSecurity {

    private static intcount= 0;

    class increaseVariable implements Runnable {
    @Override
    public void run() {
    plus();
    }
    }

    // synchronized 关键字设置同步方法 为粗粒度 整个方法都保护为一个线程执行
    // 相反 synchronized 代码块为细粒度 只保证代码块中的被一个线程执行
    public synchronized void plus() {
    count++;
    }

    @Test
    public void test1() throws InterruptedException {
    ExecutorService pool = Executors.newFixedThreadPool(30);
    for (int i = 0; i < 10000; i++) {
    pool.submit(new increaseVariable());
    }

    Thread.sleep(500);

    pool.shutdown();

    log.info(String.valueOf(count));
    }

    }

学习rabbitMQ

学习rabbitMQ

介绍:

(12条消息) windows环境下安装RabbitMQ(超详细)_luckySnow-julyo的博客-CSDN博客_windows安装rabbitmq

其他框架

Kafka、RabbitMQ、RocketMQ 全方位对比 - 龘人上天 - 博客园 (cnblogs.com)

整合步骤:

  1. 下载rabbitMQ,解压
  2. maven依赖
  3. 添加config类(生产者消费者应该不同项目)
  4. 启动rabbitMQ Rabbitmq的启动和停止 - .未央 - 博客园 (cnblogs.com)
  5. 访问 http://localhost:15672 usernname: guest password: guest

其他

1
2
3
4
5
6
7
8
9
<!--rabbitmq-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package com.jcDemo.config;

import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
* @author: gao_quansui
* @user:ASUS
* @date:2022/9/27 - 14:15
* @projectName:jc_demo
*/
@Configuration
public class DirectRabbitMQConfig {
// 创建队列
@Bean
public Queue TestDirectQueue() {
return new Queue("DirectQueue", true);
}

@Bean
public Queue TopicQueue() {
return new Queue("TopicQueue", true);
}

@Bean Queue FanoutQueue1(){
return new Queue("Fanout.Queue1");
}

@Bean Queue FanoutQueue2(){
return new Queue("Fanout.Queue2");
}

// 创建交换机
@Bean
DirectExchange DirectExchange() {
return new DirectExchange("DirectExchange", true, false);
}

@Bean
TopicExchange TopicExchange(){
return new TopicExchange("TopicExchange",true,false);
}

@Bean
FanoutExchange FanoutExchange(){
return new FanoutExchange("FanoutExchange",true,false);
}

// 建立连接绑定
// 直连为一个连接,即一对一
@Bean
Binding bindingDirect() {
return BindingBuilder.bind(TestDirectQueue()).to(DirectExchange()).with("DirectRoutingKey");
}

// 队列可以绑定多个生产者
@Bean
Binding bindingTopic(){
return BindingBuilder.bind(TopicQueue()).to(TopicExchange()).with("TopicRoutingKey.#");
// 匹配多个路由,使得消费者可以收到多个生产者的消息
}

// 交换机可以绑定多个队列(广播模式) (没有路由key)
@Bean
Binding bindingFanout1(){
return BindingBuilder.bind(FanoutQueue1()).to(FanoutExchange());
}

@Bean
Binding bindingFanout2(){
return BindingBuilder.bind(FanoutQueue2()).to(FanoutExchange());
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
package com.jcDemo.controller.mq;

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
* @author: gao_quansui
* @user:ASUS
* @date:2022/9/27 - 14:18
* @projectName:jc_demo
*/
@RestController
public class MQTest {

//使用RabbitTemplate,这提供了接收/发送等等方法
@Autowired
RabbitTemplate rabbitTemplate;

@GetMapping("/sendDirectMessage")
public String sendDirectMessage() {
String messageId = String.valueOf(UUID.randomUUID());
String messageData = "direct producer message, hello!";
String createTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
Map<String, Object> map = new HashMap<>();
map.put("messageId", messageId);
map.put("messageData", messageData);
map.put("createTime", createTime);
//将消息携带绑定键值
rabbitTemplate.convertAndSend("DirectExchange", "DirectRoutingKey", map);
return "ok";
}

@GetMapping("/sendTopicMessage1")
public String sendTopicMessage1() {
String messageId = String.valueOf(UUID.randomUUID());
String messageData = "topic producer1 message, hello!";
String createTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
Map<String, Object> map = new HashMap<>();
map.put("messageId", messageId);
map.put("messageData", messageData);
map.put("createTime", createTime);
//将消息携带绑定键值
rabbitTemplate.convertAndSend("TopicExchange", "TopicRoutingKey.test1", map);
return "ok";
}

@GetMapping("/sendTopicMessage2")
public String sendTopicMessage2() {
String messageId = String.valueOf(UUID.randomUUID());
String messageData = "topic producer2 message, hello!";
String createTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
Map<String, Object> map = new HashMap<>();
map.put("messageId", messageId);
map.put("messageData", messageData);
map.put("createTime", createTime);
//将消息携带绑定键值
rabbitTemplate.convertAndSend("TopicExchange", "TopicRoutingKey.test2", map);
return "ok";
}

@GetMapping("/sendFanoutMessage")
public String sendFanoutMessage() {
String messageId = String.valueOf(UUID.randomUUID());
String messageData = "fanout producer message, hello!";
String createTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
Map<String, Object> map = new HashMap<>();
map.put("messageId", messageId);
map.put("messageData", messageData);
map.put("createTime", createTime);
rabbitTemplate.convertAndSend("FanoutExchange","",map);
return "ok";
}
}

消费者-Direct

1
2
3
4
5
6
7
8
9
10
@Slf4j
@Component
@RabbitListener(queues = "DirectQueue")
public class ConsumerDirect {

@RabbitHandler
public void process(Map testMessage) {
log.info("DirectQueue的消费者收到消息{}",testMessage.toString());
}
}

消费者-Topic

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package com.rabbit_consumer.mq;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.annotation.RabbitListeners;
import org.springframework.stereotype.Component;

import javax.naming.Binding;
import java.util.Map;

/**
* @author: gao_quansui
* @user:ASUS
* @date:2022/10/9 - 9:59
* @projectName:rabbit_consumer
*/

@Slf4j
@Component
@RabbitListener(queues = "TopicQueue")
// 该队列对应的生产者有两个, 能够收到两个生产者的消息,不同于直连的一一对应关系
public class ConsumerTopic {

@RabbitHandler
public void process(Map map){
log.info("TopicQueue received:{}",map.toString());
}
}

消费者-Fanout

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package com.rabbit_consumer.mq;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

import java.util.Map;

/**
* @author: gao_quansui
* @user:ASUS
* @date:2022/10/9 - 13:45
* @projectName:rabbit_consumer
*/

@Slf4j
@Component
public class ConsumerFanout {

@RabbitListener(queues = "Fanout.Queue1")
// @RabbitHandler
public void process1(Map map) {
log.info("Consumer1 receive from FanoutQueue:{}", map);
}

@RabbitListener(queues = "Fanout.Queue2")
// @RabbitHandler
public void process(Map map){
log.info("Consumer2 receive from FanoutQueue:{}",map);
}
}

总结

  1. 三种模式

    1. Direct 直连 一一对应
    2. Topic 主题连接 利用*,# 进行匹配 一个交换机对应多个生产者
      • )只能向后匹配一个单词 即 a. → a.a(可以) a.a.a(不可以)
      • (#)只能向后匹配多个单词 即 a.* → a.a(可以) a.a.a(可以)
    3. Fanout 广播模式 一个交换机分发到多个队列,队列对应到相应的消费者
  2. 疑问:

    1. 能否实现一个生产者,一个交换机,一个队列,分发多个消费者?

Hutool

Hutool工具类学习

工具类,大杂烩

入门和安装 (hutool.cn)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
package com.example.jc_demo;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.Month;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Console;
import cn.hutool.core.util.*;
import jdk.nashorn.internal.runtime.regexp.joni.ast.StringNode;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;

import java.io.File;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Slf4j
public class UtilsTest {

@Test
void Convert() {
int a = 1;
String str_a = Convert.toStr(a);
log.info(String.valueOf(str_a instanceof String));

log.info("=========================================");

String[] b = {"1", "2"};
Integer[] integers = Convert.toIntArray(b);
for (int i = 0; i < integers.length; i++) {
log.info(String.valueOf(integers[i] instanceof Integer));
}

log.info("=========================================");

String c = "2022-10-10";
log.info(String.valueOf(Convert.toDate(c) instanceof Date));

log.info("=========================================");

Object[] d = {"1", 2, "牛", "jc"};
List<?> list = Convert.convert(List.class, d);
list.forEach(e -> {
log.info(e.toString() + ":" + e.getClass().toString());
});
log.info(list.getClass().toString());

log.info("=========================================");

String e = "123456789";
log.info(Convert.toSBC(e));
log.info(Convert.toDBC(Convert.toSBC(e)));

log.info("=========================================");

String f = "STRING";
log.info(Convert.toHex(f, CharsetUtil.CHARSET_UTF_8));
log.info(Convert.hexToStr(Convert.toHex(f, CharsetUtil.CHARSET_UTF_8), CharsetUtil.CHARSET_UTF_8));

log.info("=========================================");

String g = "字符串";
String result = Convert.convertCharset(g, CharsetUtil.UTF_8, CharsetUtil.ISO_8859_1);
String raw = Convert.convertCharset(result, CharsetUtil.ISO_8859_1, "UTF-8");
log.info(result);
log.info(raw);

log.info("=========================================");

long l = 23466543;
log.info(String.valueOf(Convert.convertTime(l, TimeUnit.MILLISECONDS, TimeUnit.MINUTES)));

log.info("=========================================");

double h = 1231.452;
log.info(Convert.digitToChinese(h));
log.info(Convert.numberToWord(h));
log.info(Convert.numberToSimple(h));
log.info(Convert.numberToChinese(12341., false));
log.info(Convert.numberToChinese(1234.1, true));
log.info(String.valueOf(Convert.chineseToNumber("一万二千三百四十一")));

log.info("=========================================");
log.info("=========================================");
}

@Test
void My_Date() {
log.info(String.valueOf(Month.of(Calendar.JANUARY).getLastDay(false)));
log.info(String.valueOf(Month.of(Calendar.JANUARY).getLastDay(true)));
log.info(DateUtil.date().toString());
log.info(DateUtil.date().toDateStr());
log.info(DateUtil.date(System.currentTimeMillis()).toString());
log.info(DateUtil.now().toString());
log.info(DateUtil.today().toString());
log.info(DateUtil.parse("2022-10-10", "yyyy-MM-dd").getClass().toString());
String date = "2022-10-10";
Date date1 = DateUtil.parse(date);

log.info(DateUtil.format(date1, "yyyy/MM/dd"));
log.info(DateUtil.formatDate(date1));
log.info(DateUtil.formatDateTime(date1));
log.info(DateUtil.formatTime(date1));

log.info(String.valueOf(DateUtil.year(date1)));
log.info(String.valueOf(DateUtil.month(date1)));

}

@Test
void File_utils() {
File[] ls = FileUtil.ls("C:\\Users");
for (int i = 0; i < ls.length; i++) {
log.info(ls[i].getName());
}
}

@Test
void StrUtils() {
log.info(StrUtil.removeSuffix("a.jpg", ".jpg"));
log.info(StrUtil.removePrefix("a.jpg", "a."));
String str = "123abc";
log.info(StrUtil.sub(str, 2, 4));
}

@Test
void IDCard() {
String id1 = "110101199003076413";
log.info(String.valueOf(IdcardUtil.isValidCard(id1)));

log.info(String.valueOf(IdcardUtil.getAgeByIdCard(id1)));
log.info(String.valueOf(IdcardUtil.getBirthByIdCard(id1)));
log.info(String.valueOf(IdcardUtil.getProvinceByIdCard(id1)));
log.info(String.valueOf(IdcardUtil.getProvinceCodeByIdCard(id1)));

}

@Test
void securityUtils() {
log.info(DesensitizedUtil.idCardNum("110101199003076413", 4, 4));
log.info(DesensitizedUtil.mobilePhone("15157547799"));
log.info(DesensitizedUtil.password("15157547799"));
}

@Test
void CreditCode() {
log.info(String.valueOf(CreditCodeUtil.isCreditCode("91310110666007217T")));
log.info(CreditCodeUtil.randomCreditCode());
}

@Test
void outUtils() {
Console.log("还能console 真不错");
Console.log("还能{} 真不错", "format");
Console.error("还能{} 真不错", "error");
}
}

Guava相关操作

Guava相关操作

Description

(12条消息) Guava的基础功能与集合_鲲鹏飞九万里的博客-CSDN博客_guava

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
package com.example.jc_demo;

import cn.hutool.core.date.DateUtil;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Ordering;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;

import java.util.*;

@Slf4j
public class GuavaTest {
@Data
@AllArgsConstructor
@NoArgsConstructor
class User {
String name;
}

@Test
public void my_Optional() {
Optional<Integer> op = Optional.ofNullable(new Integer(123));
log.info(op.get().toString());
}

@Test
public void returnUser() {
User u = new User();
u = null;
// 如果不用ofNullable会有空指针异常 用ofNullable能够在get()的时候报出空元素异常
Optional<User> op = Optional.ofNullable(u);
User u1 = op.get();
log.info(u1.toString());
}

@Test
public void orElse() {
// ???防止空指针 备用值??? IFNULL???
Optional<String> op = Optional.of("aaa");
log.info(String.valueOf(op.isPresent()));
log.info(op.orElse(null));
}

@Test
public void isPresent() {
Optional<String> op = Optional.of("2322");
log.info(String.valueOf(op.isPresent()));

Optional<String> op1 = Optional.ofNullable(null);
log.info(String.valueOf(op1.isPresent()));
}

//

@Test
public void my_Preconditions() {
int i = -1;
int j = 10;
String k = null;
// Preconditions.checkArgument(i > j, "%s is not bigger than %s", i, j);
// Preconditions.checkNotNull(k,"k is null");
// Preconditions.checkArgument("1".equals("2"),"1 is not equals 2");

// int[] arr = new int[10];
// Preconditions.checkElementIndex(20,arr.length);
}

@Test
public void myImmutableSet() {
/**
* 三种方式创建 只读数组
* 1.of
* 2.builder
* 3.copy
*
* 注意:不可放入null
*/
ImmutableSet<String> immutableSet = ImmutableSet.of("a", "b", "c");
immutableSet.forEach(e->{
log.info(e);
});
// java.lang.UnsupportedOperationException 不允许操作数组, 只读
// immutableSet.add("d");

ImmutableSet<String> immutableSet1 = ImmutableSet.<String>builder()
.add("a")
.add("b")
.add("c")
.build();

immutableSet1.forEach(e->{
log.info(e);
});
// java.lang.UnsupportedOperationException 不允许操作数组, 只读
// immutableSet1.add("d");

// ImmutableSet<String> immutableSet3 = ImmutableSet.copyOf(arrayList);

}

@Data
@AllArgsConstructor
@NoArgsConstructor
private class Device {
Date CreatTime;
Date UpdateTime;
}

@Test
public void my_Order() {
Ordering ordering = new Ordering<String>() {
// order by length
@Override
public int compare(String s, String t1) {
return s.length() > t1.length() ? new Integer(1) : new Integer(-1);
}
};

ArrayList<String> list = new ArrayList<>();
list.add("sadewf");
list.add("sadewfsda");
list.add("sadewfsdaasdfeao");
list.add("aadewfsdaasdfea");
list.add("zoad");
list.add("zoadnas");
list.add("doadn");
list.add("doadnsadasda");
list.add("zoadnasodnaosndaosd");

//ascii ?
Collections.sort(list);
My_ForEach(list);

Collections.sort(list, ordering);
My_ForEach(list);

Collections.reverse(list);
My_ForEach(list);

}

@Test
public void order2() {
// 链式调用 从右往左调用,先orderBy XXX 将Null放最前或最后 对剩下的自然排序
Ordering<Device> ordering1 = Ordering.natural().nullsFirst().onResultOf((Device device) -> device.CreatTime);
Ordering<Device> ordering2 = Ordering.natural().nullsLast().onResultOf((Device device) -> device.CreatTime);
List<Device> list1 = new ArrayList<>();
list1.add(new Device(DateUtil.parse("2022-1-1", "yyyy-MM-dd"), null));
list1.add(new Device(null, null));
list1.add(new Device(DateUtil.parse("2022-1-8", "yyyy-MM-dd"), null));
list1.add(new Device(DateUtil.parse("2021-1-7", "yyyy-MM-dd"), null));
list1.add(new Device(DateUtil.parse("2022-5-1", "yyyy-MM-dd"), null));
list1.add(new Device(DateUtil.parse("2022-1-7", "yyyy-MM-dd"), null));
list1.add(new Device(DateUtil.parse("2022-3-1", "yyyy-MM-dd"), null));
list1.add(new Device(DateUtil.parse("2022-6-1", "yyyy-MM-dd"), null));

Collections.sort(list1, ordering2);

My_ForEach(list1);
}

@Test
public void isOrder() {
List<String> list = new ArrayList<>(Arrays.asList("a", "asd", "b", "asdve"));

// 返回降序前两个
List<String> list1 = Ordering.natural().greatestOf(list, 2);
// 返回升序后两个
List<String> list2 = Ordering.natural().leastOf(list, 2);

My_ForEach(list1);
My_ForEach(list2);
}

public void My_ForEach(List list) {
if (list.size() > 0) {
list.forEach(e -> {
log.info(e.toString());
});
} else {
log.error("空集合");
}
log.info("=======================================================");
}
}