杂记

104 阅读6分钟

------------------------------idea------------------------------------ gradle/maven仓库地址 services www.cnblogs.com/sxdcgaq8080… 背景色 www.cnblogs.com/zhuitian/p/… 字体 www.cnblogs.com/loveyoulx/p… 编码 www.cnblogs.com/zzw3014/p/1… 智能提示 blog.csdn.net/fred_kang/a… mybatis blog.csdn.net/zz153417230… 修改内存 blog.csdn.net/qq_35973977…

------------------------------端口占用------------------------------------ netstat -aon | findstr :80 tasklist|findstr "12824"
------------------------------Java8------------------------------------ Optional.ofNullable(user).orElseGet(() -> createNewUser()); user可为空,如果为空create,不为空不执行。

actApproveUserInfo = actApproveUserInfo1.orElseGet(ActApproveUserInfo::new); actApproveUserInfo1为空new,不为空不执行。

actRoleInfoOptional.ifPresent(actRoleInfoSet::add); actRoleInfoOptional是否存在,存在set.add。

assertTrue(opt.isPresent()); assertEquals(user.getEmail(), opt.get().getEmail()); 断言 opt.ifPresent( u -> assertEquals(user.getEmail(), u.getEmail()));

Java 8 并行流(Parallel Stream) .reduce(0,Integer::sum) 把stream中的元素给组合起来。(没有起始值时返回为Optional类型/可以给一个起始种子值) final static ZoneId ZONE_ID = ZoneId.of("Asia/Shanghai"); final static AtomicInteger SEQ = new AtomicInteger(1000); final static DateTimeFormatter DF_FMT_PREFIX = DateTimeFormatter.ofPattern("yyMMddHHmmssSS");

public static String generateOrderNo() {
    LocalDateTime dataTime = LocalDateTime.now(ZONE_ID);
    if (SEQ.intValue() > 9990) {
        SEQ.getAndSet(1000);
    }
    return dataTime.format(DF_FMT_PREFIX) + SEQ.getAndIncrement();
}

HttpUtil/URLUtil/IntStream


String time = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss"); String dateStr = DateDealUtil.toDateTime(Long.parseLong(createTimestamp)); 时间操作

FileInfo fileInfo = storageClient.get_file_info(groupName,remoteFileName); String jsonStr = JSONObject.toJSONString(fileInfo); JSONObject json = JSONObject.parseObject(jsonStr); json转换

@Slf4j 相当于private final Logger logger = LoggerFactory.getLogger(当前类名.class); lombok

${SPRING_PROFILES_ACTIVE:dev} yml文件中按照SPRING_PROFILES_ACTIVE目录取值,没有的话按照:后的值 ------------------------------注解@------------------------------------ @Entity //@Table @Data @Id @Column @ManyToOne/@JoinColumn

@Transient不和数据库关联 @JsonIgnore不序列化

@ApiImplicitParams

@Api:用在请求的类上,表示对类的说明 tags="说明该类的作用,可以在UI界面上看到的注解" value="该参数没什么意义,在UI界面上也看到,所以不需要配置"

@ApiOperation:用在请求的方法上,说明方法的用途、作用 value="说明方法的用途、作用" notes="方法的备注说明"

@ApiImplicitParams:用在请求的方法上,表示一组参数说明 @ApiImplicitParam:用在@ApiImplicitParams注解中,指定一个请求参数的各个方面 name:参数名 value:参数的汉字说明、解释 required:参数是否必须传 paramType:参数放在哪个地方 · header --> 请求参数的获取:@RequestHeader · query --> 请求参数的获取:@RequestParam · path(用于restful接口)--> 请求参数的获取:@PathVariable · body(不常用) · form(不常用)
dataType:参数类型,默认String,其它值dataType="Integer"
defaultValue:参数的默认值

@ApiResponses:用在请求的方法上,表示一组响应 @ApiResponse:用在@ApiResponses中,一般用于表达一个错误的响应信息 code:数字,例如400 message:信息,例如"请求参数没填好" response:抛出异常的类

@ApiModel:用于响应类上,表示一个返回响应数据的信息 (这种一般用在post创建的时候,使用@RequestBody这样的场景, 请求参数无法使用@ApiImplicitParam注解进行描述的时候) @ApiModelProperty:用在属性上,描述响应类的属性

/**

  • Profile:
  •  Spring为我们提供的可以根据当前环境,动态的激活和切换一系列组件的功能;
    
  • 开发环境develop、测试环境test、生产环境master
  • 数据源:(/dev) (/test) (/master)
  • @Profile:指定组件在哪个环境的情况下才能被注册到容器中,不指定,任何环境下都能注册这个组件
    1. 加了环境标识的bean,只有这个环境被激活的时候才能注册到容器中。默认是default环境
    1. 写在配置类上,只有是指定的环境的时候,整个配置类里面的所有配置才能开始生效

*/

Example ExampleMatcher ------------------------------some------------------------------------

------------------------------activiti------------------------------------ extension延伸 execution执行

//部署 //获取流程存储服务组件 RepositoryService repositoryService = processEngine.getRepositoryService(); //部署流程描述文件 DeploymentBuilder builder = repositoryService.createDeployment(); Deployment deployment = builder.addInputStream(org.springframework.web.multipart.MultipartFile.file.getOriginalFilename(),org.springframework.web.multipart.MultipartFile.file.getInputStream()).deploy();

//开启 ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(instanceKey, businessKey, variables); 开启流程:instanceKey定义流程主键;businessKey业务主键id;variables流程变量 第一个参数流程图key/流程主键,第二个参数businessKey,第三个参数流程变量

// 强行停止服务 processEngine.getRuntimeService().deleteProcessInstance(createTaskForm.getInstanceKey(), "7天无理由停服务");

//设置查询条件 taskService.taskAssignee

//全局变量 taskService.setVariable //局部变量 taskService.setVariableLocal

//执行

//完成taskId(对应act_ru_task中的id_),variables(下一次任务所需要的参数),作用是完成这一次任务,并且下一步任务需要流程变量的。 public void complete(String taskId, Map<String, Object> variables); public void complete(String taskId, Map<String, Object> variables, boolean localScope); //localScope(存储范围:本任务) 。当这个布尔值为true表示作用范围为当前任务,当任务结束后,再也取不到这个值了,act_ru_variables这个表中也没有这个参数的信息了;如果为//false表示这个变量是全局的,任务结束后在act_ru_variables表中仍然能查到变量信息。

//task代码解析

List processInstanceList = runtimeService.createProcessInstanceQuery().processInstanceId(instanceId).list(); 根据流程ID查询,为什么会有list,因为多分支流程会有统一的instanceId。

------------------------------git------------------------------------

1.查看所有分支

git branch -a

2.查看当前使用分支(结果列表中前面标*号的表示当前使用分支)

git branch

3.切换分支

git checkout 分支名

git checkout -b 分支名称:创建本地分支 git push origin 分支名称:将本地分支推送到远程地址 git branch --set-upstream-to=origin 分支名称:将本地代码上传路径改为分支路径 git branch --unset-upstream master:取消对master的跟踪

git add ./git add xxx.java:添加文件到暂存区 git ls-files:查看暂存区文件 git rm --cache 文件名:删除暂存区里的文件 git commit -m 修改备注:提交代码 git push origin 分支名称:提交代码到远程地址 删除错误提交的commit //仅仅只是撤销已提交的版本库,不会修改暂存区和工作区 git reset --soft 版本库ID //仅仅只是撤销已提交的版本库和暂存区,不会修改工作区 git reset --mixed 版本库ID //彻底将工作区、暂存区和版本库记录恢复到指定的版本库 git reset --hard 版本库ID

git pull origin 分支名称:拉取代码

------------------------------JPA------------------------------------ 瞬时状态:实际上就是new了一个普通的JavaBean对象。

托管状态:1.当瞬时对象调用了管理器的persist()后,即可将一般的JavaBean做为了持久Bean,该Bean的任何属性改动都会牵涉到数据库记录的改动。2. 一旦该记录flush到数据库之后,并且事务提交了,那么此对象不在持久化上下文中,即:变为了游离(没人管的孩子)状态了。在游离状态的时候调用更新、刷新方法后,游离状态对象就变为了在持久化上下文的托管状态了。3.通过管理器的find方法,将实体从数据库查询出来后,该实体也就变为了托管形态。

持久化状态:当处在托管状态的实体Bean被管理器flush了,那么就在极短暂的时间进入了持久化状态,事务提交之后,立刻变为了游离状态。您可以把持久化状态当做实实在在的数据库记录。

游离状态:游离状态就是提交到数据库后,事务commit后实体的状态,因为事务已经提交了,此时实体的属性任你如何改变,也不会同步到数据库,因为游离是没人管的孩子,不在持久化上下文中。

销毁对象:一般要删除一个持久化对象的时候都是先find出来,之后调用remove方法删之,此时这个对象就是销毁对象,实际上就是瞬时对象的另一种形态罢了。

4种状态 设置entityManager @JoinColumn

------------------------------正则表达式------------------------------------ regex正则表达式 text内容 Pattern r = Pattern.compile(regex); Matcher m = r.matcher(text); if(m.find()){ indexEnd = m.end(); indexStart = m.start(); }

------------------------------SPRING TEST------------------------------------ compile group: 'org.springframework.boot', name: 'spring-boot-starter-test', version: '1.5.9.RELEASE' ------------------------------paramType------------------------------------ dataType="int" 代表请求参数类型为int类型,当然也可以是Map、User、String等;

paramType="body" 代表参数应该放在请求的什么地方:

? ?

@ApiParam

header-->放在请求头。请求参数的获取:@RequestHeader(代码中接收注解) ? ? query-->用于get请求的参数拼接。请求参数的获取:@RequestParam(代码中接收注解) ? ? path(用于restful接口)-->请求参数的获取:@PathVariable(代码中接收注解) ? ? body-->放在请求体。请求参数的获取:@RequestBody(代码中接收注解) ? ? form(不常用)表示FormData,其实很常用了,任何@RequestParam注解修饰的字段,都可以用FormData来传,可以说比query更加推荐,但是swagger不用form是因为swagger-ui.html还不能发送formData -----------------------------数值计算-BigDecimal(String)----------------------------------- 构造器 描述
BigDecimal(int) 创建一个具有参数所指定整数值的对象。
BigDecimal(double) 创建一个具有参数所指定双精度值的对象。
BigDecimal(long) 创建一个具有参数所指定长整数值的对象。
BigDecimal(String) 创建一个具有参数所指定以字符串表示的数值的对象。

方法 描述
add(BigDecimal) BigDecimal对象中的值相加,然后返回这个对象。
subtract(BigDecimal) BigDecimal对象中的值相减,然后返回这个对象。
multiply(BigDecimal) BigDecimal对象中的值相乘,然后返回这个对象。
divide(BigDecimal) BigDecimal对象中的值相除,然后返回这个对象。
toString() 将BigDecimal对象的数值转换成字符串。
doubleValue() 将BigDecimal对象中的值以双精度数返回。
floatValue() 将BigDecimal对象中的值以单精度数返回。
longValue() 将BigDecimal对象中的值以长整数返回。
intValue() 将BigDecimal对象中的值以整数返回。
-----------------------------Duration ---------------------------------------- Duration duration = java.time.Duration.ofMillis(long millis); System.out.println(duration.getSeconds()); -----------------------------.longValue---------------------------------------- .longValue()是Long类的一个方法,用来得到Long类中的数值;也就是将包装类中的数据拆箱成基本数据类型。 Long.valueOf(参数)是将参数转换成long的包装类——Long;也就是把基本数据类型转换成包装类。 -----------------------------RestTemplate---------------------------------------- //复杂构造函数的使用 SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory(); requestFactory.setConnectTimeout(60000);// 设置超时 requestFactory.setReadTimeout(60000); //利用复杂构造器可以实现超时设置,内部实际实现为 HttpClient RestTemplate restTemplate = new RestTemplate(requestFactory);

String username = clientId; String password = clientSecret; String loginUrl = videoServerUrl + oauthUrl; String base64Str = Base64.encodeBase64String((username + ":" + password).getBytes("UTF-8")); String authorization = "Basic " + base64Str; //复杂构造函数的使用 SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory(); //requestFactory.setConnectTimeout(60000);// 设置超时 //requestFactory.setReadTimeout(60000); //利用复杂构造器可以实现超时设置,内部实际实现为 HttpClient RestTemplate restTemplate = new RestTemplate(requestFactory); //设置HTTP请求头信息,实现编码等 HttpHeaders requestHeaders = new HttpHeaders(); requestHeaders.set("Authorization", authorization); requestHeaders.set("Content-Type", MediaType.APPLICATION_FORM_URLENCODED_VALUE); MultiValueMap<String, String> map = new LinkedMultiValueMap<>(); map.add("grant_type", "client_credentials"); map.add("client_id", username); map.add("client_secret", password); map.add("scope", "all"); HttpEntity<MultiValueMap<String, String>> httpEntity = new HttpEntity<>(map, requestHeaders); ResponseEntity request = restTemplate.postForEntity(loginUrl, httpEntity, String.class); return JSON.parseObject(request.getBody(), CacheTokenDTO.class); -----------------------------Redis---------------------------------------- TTL KEY_NAME Redis TTL 命令以秒为单位返回 key 的剩余过期时间。

-----------------------------Redis订阅---------------------------------------- Redis数据库有很高的性能,这样就有人想让它充当消息组件的角色,所以Redis数据库提供有一种发布与订阅模式。 Redis-A:开启订阅模式   subscribe my-channel Redis-B:利用指定通道开启发布者模式,进行内容传输   publish my-channel HELLOWORLD -----------------------------ThreadPool---------------------------------------- import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; @Bean public ThreadPoolExecutor systemThreanPool() { int size = Runtime.getRuntime().availableProcessors(); return new ThreadPoolExecutor(size, size, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>()); } -----------------------------DestroyConfig---------------------------------------- import com.tzwy.contactjudge.api.common.constants.AppConstant; import com.tzwy.contactjudge.api.common.utils.SpringUtil; import com.tzwy.contactjudge.api.modules.websocket.ChatHandler; import com.tzwy.contactjudge.api.modules.websocket.endpoint.SocketData; import com.tzwy.contactjudge.api.modules.websocket.endpoint.SocketMessage; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; import org.springframework.data.redis.core.RedisTemplate;

import javax.annotation.PreDestroy; import java.util.concurrent.ThreadPoolExecutor;

@Slf4j @Order(9999) @Configuration public class DestroyConfig {

public DestroyConfig() {
}

/**
 * Redis
 */
@Autowired
private RedisTemplate redisTemplate;

@PreDestroy
public void preDestroy() {
    log.info("--------------------------- application ready shutdown --------------------------");
    ChatHandler chatHandler = SpringUtil.getBean(ChatHandler.class);
    if (null != chatHandler) {
        log.info("--------------------------- 清空redis --------------------------");
        redisTemplate.delete("user:token:*");
        log.info("--------------------------- 升级通知 --------------------------");
        SocketData notice = new SocketData();
        notice.setType(AppConstant.TYPE_NOTIFY);
        SocketMessage body = new SocketMessage();
        body.setContent("后台服务正在升级,请稍后...");
        notice.setBody(body);
        chatHandler.notifyAllClient(notice);
    }
    ThreadPoolExecutor systemThreanPool = SpringUtil.getBean(ThreadPoolExecutor.class);
    if (null != systemThreanPool) {
        systemThreanPool.shutdown();
    }
}

} -----------------------------RestTemplateConfig---------------------------------------- import org.apache.http.client.HttpClient; import org.apache.http.client.config.RequestConfig; import org.apache.http.config.Registry; import org.apache.http.config.RegistryBuilder; import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.conn.socket.PlainConnectionSocketFactory; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.client.ClientHttpRequestFactory; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.web.client.RestTemplate;

@Configuration public class RestTemplateConfig {

@Value("${app.rest.pool.maxTotal:400}")
private int maxTotal;

@Value("${app.rest.pool.defaultMaxPerRoute:100}")
private int defaultMaxPerRoute;

@Value("${app.rest.socketTimeout:30000}")
private int socketTimeout;

@Value("${app.rest.connectTimeout:10000}")
private int connectTimeout;

@Value("${app.rest.connectionRequestTimeout:1000}")
private int connectionRequestTimeout;

@Bean
public RestTemplate restTemplate() {
    return new RestTemplate(httpRequestFactory());
}

@Bean
public ClientHttpRequestFactory httpRequestFactory() {
    return new HttpComponentsClientHttpRequestFactory(httpClient());
}

@Bean
public HttpClient httpClient() {
    Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
            .register("http", PlainConnectionSocketFactory.getSocketFactory())
            .register("https", SSLConnectionSocketFactory.getSocketFactory())
            .build();
    PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
    //设置整个连接池最大连接数
    connectionManager.setMaxTotal(maxTotal);

    //路由是对maxTotal的细分
    connectionManager.setDefaultMaxPerRoute(defaultMaxPerRoute);
    RequestConfig requestConfig = RequestConfig.custom()
            .setSocketTimeout(socketTimeout)  //返回数据的超时时间
            .setConnectTimeout(connectTimeout) //连接上服务器的超时时间
            .setConnectionRequestTimeout(connectionRequestTimeout) //从连接池中获取连接的超时时间
            .build();
    return HttpClientBuilder.create()
            .setDefaultRequestConfig(requestConfig)
            .setConnectionManager(connectionManager)
            .build();
}

} -----------------------------RedisConfig ---------------------------------------- import com.alibaba.fastjson.support.spring.FastJsonRedisSerializer; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.tzwy.contactjudge.api.modules.websocket.MessageReceiver; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.cache.CacheProperties; import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ResourceLoader; import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.ReactiveRedisTemplate; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.listener.PatternTopic; import org.springframework.data.redis.listener.RedisMessageListenerContainer; import org.springframework.data.redis.listener.adapter.MessageListenerAdapter; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializationContext; import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.util.ErrorHandler;

/**

  • redis公共配置 */ @Slf4j @Configuration @EnableCaching public class RedisConfig {

    @Value("${app.ws.channel}") private String channel;

    /**

    • 功能:指定redis工具类中序列化方式


    • 参数:

    • 返回:

    • 创建日期:

    • @version 1.0 */ // @Bean // public RedisTemplate<Object, Object> redisTemplate( // RedisConnectionFactory redisConnectionFactory) { // RedisTemplate<Object, Object> template = new RedisTemplate<>(); // // // value值的序列化采用fastJsonRedisSerializer // template.setValueSerializer(jackson2JsonRedisSerializer()); // template.setHashValueSerializer(jackson2JsonRedisSerializer()); // // key的序列化采用StringRedisSerializer // StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); // template.setKeySerializer(stringRedisSerializer); // template.setHashKeySerializer(stringRedisSerializer); // // template.setConnectionFactory(redisConnectionFactory); // return template; // } @Bean public RedisTemplate<String, Object> redisTemplate( RedisConnectionFactory redisConnectionFactory) { RedisTemplate<String, Object> template = new RedisTemplate<>();

      //使用fastjson序列化 FastJsonRedisSerializer fastJsonRedisSerializer = new FastJsonRedisSerializer(Object.class); // value值的序列化采用fastJsonRedisSerializer template.setValueSerializer(fastJsonRedisSerializer); template.setHashValueSerializer(fastJsonRedisSerializer); // key的序列化采用StringRedisSerializer template.setKeySerializer(new StringRedisSerializer()); template.setHashKeySerializer(new StringRedisSerializer());

      template.setConnectionFactory(redisConnectionFactory); return template; }

    /**

    • 功能:创建默认配置 指定spring提供的缓存相关注解使用时的序列化方式

    • 参数:
    • 返回:
    • 创建日期:
    • @version 1.0 */ @Bean public org.springframework.data.redis.cache.RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties, ResourceLoader resourceLoader) { //创建CacheConfig CacheProperties.Redis redisProperties = cacheProperties.getRedis(); org.springframework.data.redis.cache.RedisCacheConfiguration config = org.springframework.data.redis.cache.RedisCacheConfiguration .defaultCacheConfig(); config = config.serializeValuesWith( RedisSerializationContext.SerializationPair.fromSerializer(new FastJsonRedisSerializer(Object.class))); if (redisProperties.getTimeToLive() != null) { config = config.entryTtl(redisProperties.getTimeToLive()); } if (redisProperties.getKeyPrefix() != null) { config = config.prefixKeysWith(redisProperties.getKeyPrefix()); } if (!redisProperties.isCacheNullValues()) { config = config.disableCachingNullValues(); } if (!redisProperties.isUseKeyPrefix()) { config = config.disableKeyPrefix(); } return config; }

    @Bean(name = "reactiveRedisTemplate") public ReactiveRedisTemplate<String, Object> reactiveRedisTemplate( ReactiveRedisConnectionFactory reactiveRedisConnectionFactory) { RedisSerializationContext<String, Object> serializationContext = RedisSerializationContext.<String, Object> newSerializationContext() .key(new StringRedisSerializer()) .value(new FastJsonRedisSerializer(Object.class)) // GenericJackson2JsonRedisSerializer .hashKey(new StringRedisSerializer()) .hashValue(new FastJsonRedisSerializer(Object.class)) // jackson2JsonRedisSerializer() .build(); return new ReactiveRedisTemplate<>(reactiveRedisConnectionFactory, serializationContext); }

    /**

    • 功能:创建jackson进行json转换的序列化对象

    • 参数:
    • 返回:
    • 创建日期:
      */ private Jackson2JsonRedisSerializer jackson2JsonRedisSerializer() { Jackson2JsonRedisSerializer j2jrs = new Jackson2JsonRedisSerializer<>(Object.class); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); // 解决jackson2无法反序列化LocalDateTime的问题 om.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); om.registerModule(new JavaTimeModule()); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY); j2jrs.setObjectMapper(om); return j2jrs; }

      /**

      • 监听
      • @param connectionFactory
      • @param listenerAdapter
      • @return */ @Bean RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory, MessageListenerAdapter listenerAdapter) { try { return getRedisMessageListenerContainer(connectionFactory, listenerAdapter); } catch (Exception e) { log.error("+++++++++++++++++++++++++++++redis 订阅异常", e); return getRedisMessageListenerContainer(connectionFactory, listenerAdapter); } }

      private RedisMessageListenerContainer getRedisMessageListenerContainer(RedisConnectionFactory connectionFactory, MessageListenerAdapter listenerAdapter) { RedisMessageListenerContainer container = new RedisMessageListenerContainer(); container.setConnectionFactory(connectionFactory); // 所有订阅该主题的节点都能收到消息 container.addMessageListener(listenerAdapter, new PatternTopic(channel)); // 重连时间 container.setRecoveryInterval(5000); container.setErrorHandler(new ErrorHandler() { @Override public void handleError(Throwable t) { log.error("redis 订阅异常", t); container.addMessageListener(listenerAdapter, new PatternTopic(channel)); } }); return container; }

      @Bean MessageListenerAdapter listenerAdapter(MessageReceiver receiver) { // 这个地方 是给messageListenerAdapter 传入一个消息接受的处理器,利用反射的方法调用“receiveMessage” // 也有好几个重载方法,这边默认调用处理器的方法 叫handleMessage 可以自己到源码里面看 return new MessageListenerAdapter(receiver, "receiveMessage"); } } -----------------------------WebFluxConfig---------------------------------------- import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpHeaders; import org.springframework.http.codec.ServerCodecConfigurer; import org.springframework.http.codec.multipart.MultipartHttpMessageReader; import org.springframework.http.codec.multipart.SynchronossPartHttpMessageReader; import org.springframework.web.reactive.config.CorsRegistry; import org.springframework.web.reactive.config.ResourceHandlerRegistry; import org.springframework.web.reactive.config.WebFluxConfigurer;

      import java.io.File;

      @Configuration public class WebFluxConfig implements WebFluxConfigurer {

      /**
       * 文件缓存根路径
       */
      @Value("${app.file.save-path}")
      private String savePath;
      
      /**
       * 法院代码
       */
      @Value("${params-sys.courtNo}")
      private String courtNo;
      
      /**
       * swagger静态资源访问路径配置
       *
       * @param registry
       */
      @Override
      public void addResourceHandlers(ResourceHandlerRegistry registry) {
          registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
          registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
          registry.addResourceHandler("/attachment/**").addResourceLocations("file:" + savePath + File.separator + courtNo + File.separator);
          registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
      }
      
      /**
       * 跨域访问配置
       *
       * @param registry
       */
      @Override
      public void addCorsMappings(CorsRegistry registry) {
          registry.addMapping("/**")
                  .allowCredentials(true)
                  .allowedOrigins("*")
                  .allowedHeaders("*")
                  .allowedMethods("*")
                  .exposedHeaders(HttpHeaders.SET_COOKIE);
      }
      
      /**
       * 配置上传文件大小
       *
       * @param configurer
       */
      @Override
      public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
          SynchronossPartHttpMessageReader partReader = new SynchronossPartHttpMessageReader();
          // 单次上传文件数量
          partReader.setMaxParts(10);
          // 单个文件上传最大限制 单位是Byte
          partReader.setMaxInMemorySize(256 * 1024 * 1024);
          // 单个文件上传最大限制 单位是Byte
          partReader.setMaxDiskUsagePerPart(500L * 1024L * 1024L);
          partReader.setEnableLoggingRequestDetails(true);
      
          MultipartHttpMessageReader multipartReader = new MultipartHttpMessageReader(partReader);
          multipartReader.setEnableLoggingRequestDetails(true);
      
          configurer.defaultCodecs().multipartReader(multipartReader);
      }
      

      } -----------------------------WebSocketConfig---------------------------------------- package com.tzwy.contactjudge.api.config;

      import com.tzwy.contactjudge.api.modules.websocket.ChatHandler; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.reactive.HandlerMapping; import org.springframework.web.reactive.handler.SimpleUrlHandlerMapping; import org.springframework.web.reactive.socket.WebSocketHandler; import org.springframework.web.reactive.socket.server.support.WebSocketHandlerAdapter;

      import java.util.LinkedHashMap; import java.util.Map;

      /**

      • websocket 配置 */ @Configuration public class WebSocketConfig {

        @Bean public HandlerMapping webSocketMapping() { SimpleUrlHandlerMapping simpleUrlHandlerMapping = new SimpleUrlHandlerMapping(); Map<String, WebSocketHandler> handlerMap = new LinkedHashMap<>(); handlerMap.put("/ws/chat", new ChatHandler()); simpleUrlHandlerMapping.setUrlMap(handlerMap); simpleUrlHandlerMapping.setOrder(-1); return simpleUrlHandlerMapping; }

        @Bean public WebSocketHandlerAdapter handlerAdapter() { return new WebSocketHandlerAdapter(); } } -----------------------------ChronoUnit---------------------------------------- ChronoUnit 一组标准的日期时间单位。

      这组单元提供基于单元的访问来操纵日期,时间或日期时间。 可以通过实现TemporalUnit来扩展标准单元集。

      这些单元适用于多个日历系统。

      例如,大多数非ISO日历系统定义年,月和日的单位,只是略有不同的规则。 每个单元的文档说明了它的运作方式。

      这是一个最终的、不可变的和线程安全的枚举。 @Test public void testChromoUnitsPlus() { //Get the current date LocalDate today = LocalDate.now(); System.out.println("Current date: " + today); //add 1 week to the current date LocalDate nextWeek = today.plus(1, ChronoUnit.WEEKS); System.out.println("Next week: " + nextWeek); //add 1 month to the current date LocalDate nextMonth = today.plus(1, ChronoUnit.MONTHS); System.out.println("Next month: " + nextMonth); //add 1 year to the current date LocalDate nextYear = today.plus(1, ChronoUnit.YEARS); System.out.println("Next year: " + nextYear); //add 10 years to the current date LocalDate nextDecade = today.plus(1, ChronoUnit.DECADES); System.out.println("Date after ten year: " + nextDecade); } @Test public void testChromoUnitsBetween() { //Get the current date LocalDate today = LocalDate.now(); LocalDate nextWeek = today.plus(1, ChronoUnit.WEEKS); long diff = ChronoUnit.WEEKS.between(today, nextWeek); Assert.assertEquals(1, diff); } -----------------------------@Accessors---------------------------------------- @Accessors(chain = true) 这个注解是来至于lombok里面的 只需要在实体类加上就可以开启链式编程了 -----------------------------WebFluxConfig---------------------------------------- Map.getOrDefault(key,defaultValue); -----------------------------WebFlux WebSocket---------------------------------------- 当一个 WebSocket 请求到达 WebFlux 时,首先由 DispatcherHandler 进行处理,它会根据已有的 HandlerMapping 找到这个 WebSocket 请求对应的 handler, 接着发现该 handler 实现了 WebSocketHandler 接口,于是会通过 WebSocketHandlerAdapter 来完成该 handler 的调用。 -----------------------------Reactor---------------------------------------- Flux generate(Callable stateSupplier, BiFunction<S, SynchronousSink, S> generator) stateSupplier作为参数,通过BiFunction修改 create(Consumer> emitter) 与generate(Consumer> generator)的sink不同,create的FluxSink 支持同步和异步的消息产生,并且可以在一次调用中产生多个元素。可多次调用next(),而generate只能调用一次. Mono fromCallable()、fromCompletionStage()、fromFuture()、fromRunnable()和 fromSupplier() delay(Duration duration)和 delayMillis(long duration) 创建一个 Mono 序列,在指定的延迟时间之后,产生数字 0 作为唯一值。 ignoreElements(Publisher source) 创建一个 Mono 序列,忽略作为源的 Publisher 中的所有元素,只产生结束消息。 justOrEmpty(Optional data)和 justOrEmpty(T data) 从一个 Optional 对象或可能为 null 的对象中创建 Mono。只有 Optional 对象中包含值或对象不为 null 时,Mono 序列才产生对应的元素。 filter 对流中包含的元素进行过滤,只留下满足 Predicate 指定条件的元素。 window 操作符的作用类似于 buffer,所不同的是 window 操作符是把当前流中的元素收集到另外的 Flux 序列中,因此返回值类型是 Flux>。 zipWith 操作符把当前流中的元素与另外一个流中的元素按照一对一的方式进行合并。在合并时可以不做任何处理,由此得到的是一个元素类型为 Tuple2 的流;也可以通过一个 BiFunction 函数对合并的元素进行处理,所得到的流的元素类型为该函数的返回值。 take 操作符用来从当前流中提取元素。take(long n),take(Duration timespan)和 takeMillis(long timespan):按照指定的数量或时间间隔来提取。 takeLast(long n):提取流中的最后 N 个元素。 takeUntil(Predicate predicate):提取元素直到 Predicate 返回 true。 takeWhile(Predicate continuePredicate): 当 Predicate 返回 true 时才进行提取。 takeUntilOther(Publisher other):提取元素直到另外一个流开始产生元素。 reduce 和 reduceWith 操作符对流中包含的所有元素进行累积操作,得到一个包含计算结果的 Mono 序列。累积操作是通过一个 BiFunction 来表示的。在操作时可以指定一个初始值。如果没有初始值,则序列的第一个元素作为初始值。 merge 和 mergeSequential 操作符用来把多个流合并成一个 Flux 序列。不同之处在于 merge 按照所有流中元素的实际产生顺序来合并,而 mergeSequential 则按照所有流被订阅的顺序,以流为单位进行合并。 flatMap 和 flatMapSequential 操作符把流中的每个元素转换成一个流,再把所有流中的元素进行合并。flatMapSequential 和 flatMap 之间的区别与 mergeSequential 和 merge 之间的区别是一样的。 concatMap 操作符的作用也是把流中的每个元素转换成一个流,再把所有流进行合并。与 flatMap 不同的是,concatMap 会根据原始流中的元素顺序依次把转换之后的流进行合并;与 flatMapSequential 不同的是,concatMap 对转换之后的流的订阅是动态进行的,而 flatMapSequential 在合并之前就已经订阅了所有的流。 combineLatest 操作符把所有流中的最新产生的元素合并成一个新的元素,作为返回结果流中的元素。只要其中任何一个流中产生了新的元素,合并操作就会被执行一次,结果流中就会产生新的元素。

      -----------------------------netty---------------------------------------- JAVA NIO 死磕系列:NIO简介、NIO Buffer、 NIO channel、 NIO Selector reactor 模式 死磕系列: Reactor模式 Netty 源码 死磕系列: 环境搭建 、 EventLoop、 ChannelHandler 、 Pipeline模式、Pipeline inbound、 Pipeline outbound Java 类加载器 死磕系列:双亲委托、 文件系统类加载器、 网络类加载器、 加密类加载器、 AOP 类加载器

      【基础篇】netty 源码死磕1.1: JAVA NIO简介 www.cnblogs.com/crazymakerc… 【基础篇】netty 源码死磕1.2: NIO Buffer www.cnblogs.com/crazymakerc… 【正文】 netty 源码死磕1.3: Java NIO Channel www.cnblogs.com/crazymakerc… 【正文】 netty 源码死磕1.4: Java NIO Selector www.cnblogs.com/crazymakerc… 【正文】 netty 源码死磕2: 环境搭建 www.cnblogs.com/crazymakerc… 【基础篇】netty 源码死磕3: 传说中神一样的Reactor反应器模式 www.cnblogs.com/crazymakerc… 【精进篇】netty 源码死磕4: EventLoop的鬼斧神工 www.cnblogs.com/crazymakerc… 【精进篇】netty 源码死磕5: 揭开 ChannelHandler 的神秘面纱 www.cnblogs.com/crazymakerc… 【精进篇】netty 源码死磕6: 巧夺天工——Pipeline模式揭秘 www.cnblogs.com/crazymakerc… 【精进篇】netty 源码死磕7: 巧夺天工——Pipeline入站流程详解 www.cnblogs.com/crazymakerc… 【精进篇】netty 源码死磕8: Pipeline outbound 出站流程揭秘 www.cnblogs.com/crazymakerc… 【精进篇】netty 源码死磕9: Pipeline 入站流程详解 www.cnblogs.com/crazymakerc… 【精进篇】netty 源码死磕9: Future Promise 模式详解 www.cnblogs.com/crazymakerc… 【精进篇】netty 源码死磕11: Spring Netty 整合实战 www.cnblogs.com/crazymakerc… 【精进篇】netty 源码死磕12: Protobuf 消息设计 www.cnblogs.com/crazymakerc… Java类加载器(CLassLoader)死磕5:自定义一个文件系统classLoader www.cnblogs.com/crazymakerc…