【已失效】Microsoft Office 365个人版订阅仅需39元持续免费续期白嫖方法(非E5订阅)

【已失效】Microsoft Office 365个人版订阅仅需39元持续免费续期白嫖方法(非E5订阅)

2023年3月30日更新

!!!该方法已于2023年3月30日失效,不会再有免费续期的横幅了,大家不用再试了!!!


以下为原文:

众所周知,Microsoft 365是微软推出的一个订阅制收费模式,个人版以及家庭版均需几百元一年的订阅费

但不知道从什么时候开始,微软出现了一个可以免费续期的入口,仅需39元的总成本即可每天免费续期2个月,以下为教程

注册微软账号

相信能看到本文的读者都应该有自己的微软账号了,这里就不过多描述了。
注册网址: account.microsoft.com

开通Microsoft 365个人版月度订阅

打开 订阅页面,在该页面开启Microsoft 365个人版月度订阅,可以用支付宝开,银行卡应该也可以,但是没有测试过。
注意:此处需要支付39元,截止到发文时间该方法可用,请自行决定再开通
该方法在2023年3月30日已失效,请勿尝试

免费续期

  • 打开 订阅页面,点击Microsoft 365处的管理按钮,如下图

阅读更多
使用Canal进行MySQL到MySQL数据库全量+增量同步以及踩坑指南

使用Canal进行MySQL到MySQL数据库全量+增量同步以及踩坑指南

背景

最近工作中遇到一个迁移数据库的需求,需要将数据库从A服务器迁移至B服务器,为了尽量减少迁移导致的停机时间,考虑使用全量迁移+增量同步的方式,最终选择使用Canal作为迁移工具

准备工作

1. 数据库

两台服务器的数据库都需要提前准备好数据库账号,用于Canal进行数据库连接,因为Canal是伪装成从库读取源数据的,所以需要对源库进行一些配置,比如账号需要授予从库权限(如果给的是最高权限账号,那基本不用担心这个)、保证Canal部署的程序与数据库网络互通、以及最重要的!开启ROW格式的Binlog,这个非常重要!

2.Canal安装

使用Canal进行全量和增量同步需要用到两个组件,Canal adapter、Canal deployer,可自行前往github仓库下载。

Canal配置启动增量同步和全量同步

1.deployer配置

将下载的两个组件解压,首先配置deployer

主要关注conf目录

进入example目录,编辑instance.properties文件:

重点关注这几个参数:canal.instance.master.addresscanal.instance.dbUsernamecanal.instance.dbPasswordcanal.instance.filter.regex(重要)

阅读更多

Spring Cache @Cacheable 缓存在部分Service中不生效的解决办法

1. 背景

最近开发的项目中,需要大量的使用到缓存以提升性能

其中,有个活动controller,需要查询所有的活动,代码如下:

1
2
3
4
5
@GetMapping("/list")
public RestResult<List<ActivityInfoDTO>> list() {
List<ActivityInfoDTO> list = activityService.getAllActivity();
return addRestResult(list);
}

对应的ActivityService方法如下:

1
2
3
4
5
6
@Override
@Cacheable(value = "ActivityInfoDTO", key = "'getAllActivity'")
public List<ActivityInfoDTO> getAllActivity() {
List<ActivityInfoDTO> allActivity = activityDefMapper.getAllActivity();
return allActivity;
}

结构十分简单,但是奇怪的是,ActivityService里的方法完全不会走缓存

而另一个service,BannerInfoService则可以正常缓存

调试时可以看到,正常的BannerInfoService是有被cglib代理的

而ActivityService是没有被代理的

2. 解决方法

漫长的搜索过后,没能在网上找到解决方案

最终将目光瞄向了ActivityService的其他引用,于是猜测是否是循环引用导致ActivityService没有被代理

结果发现,在另一个OpusService中,有引用该ActivityService

同时OpusService也引用了MessagePushService,而这个MessagePushService又引用了OpusService

于是选择将OpusService中的ActivityService改为懒加载,加上@Lazy注解:

发现成功触发了缓存机制,调试信息也可以看到被cglib代理

3. 总结

之前遇到的缓存不生效大多都是因为在类内部通过this进行调用

这次遇到的情况确实不太常见,循环依赖会导致cglib无法成功代理被依赖的对象,导致缓存失效。

Java在ElasticSearch中使用LocalDatetime类型

问题

最近在开发一个搜索功能的需求的时候,遇到了LocalDatetime类型不能保存到ElasticSearch中的问题,报错如下:

1
2
ElasticsearchStatusException[Elasticsearch exception [type=mapper_parsing_exception, reason=failed to parse field [createTime] of type [date] in document with id '3000']
]; nested: ElasticsearchException[Elasticsearch exception [type=illegal_state_exception, reason=Can't get text on a START_OBJECT at 1:125]];

从网上查找尝试第一个办法:

将以下注解加到时间字段上,依然无效

1
2
3
4
@Field(type = FieldType.Date, index = FieldIndex.not_analyzed, store = true,
format = DateFormat.custom, pattern = "yyyy-MM-dd HH:mm:ss.SSS")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern ="yyyy-MM-dd HH:mm:ss.SSS")
private LocalDateTime createTime;

解决办法

在项目中添加以下依赖:

1
2
3
4
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>

在字段上加上以下注解

1
2
3
4
5
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
@JsonSerialize(using = LocalDateTimeSerializer.class)
@Field(type = FieldType.Date, store = true, format = DateFormat.custom, pattern = "yyyy-MM-dd HH:mm:ss.SSS")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss.SSS")
private LocalDateTime createTime;

完美解决

ajax跨域请求中设置header的一个坑

今天晚上有同事反馈,线上一个登记系统出现错误

提示的报错内容为:

1
2
3
4
5
6
{
"readyState": 0,
"responseText": "",
"status": 0,
"statusText": "error"
}

第一眼直觉就是ajax跨域请求失败了,触发了CORS限制。

印象中自己已经做好了跨域相关的配置呀,怎么还会触发呢?

由于是在微信浏览器上才会出现,使用vconsole也没有找到详细的错误原因,又粗略检查了下代码,java后端代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 工具类中的统一返回
httpResponse.addHeader("Access-Control-Allow-Origin", "*");
httpResponse.addHeader("Access-Control-Allow-Headers", "*");
httpResponse.addHeader("Access-Control-Allow-Credentials", "true");
httpResponse.addHeader("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS");
httpResponse.addHeader("Access-Control-Max-Age", "3600");

//继承WebMvcConfigurationSupport的configurer
registry.addMapping("/**")// 设置允许跨域的路径
.allowedOrigins("*")// 设置允许跨域请求的域名
.allowCredentials(true)// 是否允许证书 不再默认开启
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")// 设置允许的方法
.allowedHeaders("*")

origin和method都已经配置上了需要配置的header,可是微信浏览器的options预校验死活不通过!

最终,将目光锁定在了Access-Control-Allow-Headers参数上

查阅资料后发现,Access-Control-Allow-Headers请求头的值设置成 “*” 是不生效的,只能设置成具体的值,比如token等等
image.png
最终代码修改如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 工具类中的统一返回
httpResponse.addHeader("Access-Control-Allow-Origin", "*");
httpResponse.addHeader("Access-Control-Allow-Headers", "X-Token");
httpResponse.addHeader("Access-Control-Allow-Credentials", "true");
httpResponse.addHeader("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS");
httpResponse.addHeader("Access-Control-Max-Age", "3600");

//继承WebMvcConfigurationSupport的configurer
registry.addMapping("/**")// 设置允许跨域的路径
.allowedOrigins("*")// 设置允许跨域请求的域名
.allowCredentials(true)// 是否允许证书 不再默认开启
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")// 设置允许的方法
.allowedHeaders("X-Token")

指定明确的Access-Control-Allow-Headers请求头的值即可

JAVA使用腾讯企业邮箱发送邮件时报错Could not connect to SMTP host

最近做一个邮件发送功能的时候,发现腾讯企业邮的邮箱,用java发送邮件的时候一直报错:
Mail server connection failed; nested exception is javax.mail.MessagingException: Could not connect to SMTP host: smtp.exmail.qq.com, port: 465, response: -1. Failed messages: javax.mail.MessagingException: Could not connect to SMTP host: smtp.exmail.qq.com, port: 465, response: -1

发邮件使用的spring-boot-starter-mail,配置文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 设置邮箱主机
spring.mail.host=smtp.exmail.qq.com
spring.mail.port=465
spring.mail.protocol=smtp

# 设置用户名
spring.mail.username=xxxxxx
# 设置密码,是客户端专用密码,非网页登录密码
spring.mail.password=xxxxxx

# true代表邮箱需要认证
spring.mail.properties.mail.smtp.auth=true

#启用SSL
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true

查阅各种资料后发现,配置文件应当加入下面的配置:

1
2
3
spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory
spring.mail.properties.mail.smtp.port=465
spring.mail.properties.mail.smtp.socketFactory.port=465

将这三行加入到配置文件里就可以正常发送邮件了

Mybatis使用collection标签进行树形结构数据查询时如何携带外部参数查询

1. 背景

最近更新博客的评论功能,想实现这么一个需求:

评论使用树形结构展示,评论提交后,需要后台审核后才展示到前台,但是用户自己可以显示自己提交的未审核的评论

2. 实施

最初的实现方法是想使用collection进行树形结构查询

为了实现树形查询,需要两个resultMap,一个为最外层的查询结果,另一个是集合里的查询结果,也就是对象中的children对应的List,因为是树形结构,所以外层和里层的结构基本一样,下方代码为两个resultMap代码(示例):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<resultMap type="com.stonewu.blog.core.entity.custom.ReplyTree" id="replyTree">
<id column="id" property="id"/>
<result column="content" property="content"/>
<result column="article_id" property="articleId"/>
<result column="author_id" property="authorId"/>
<result column="parent_reply_id" property="parentReplyId"/>
<result column="check_reply" property="checkReply"/>
<collection column="id=id,authorId=author_id" property="children" ofType="com.stonewu.blog.core.entity.custom.ReplyTree" javaType="java.util.ArrayList" select="getReplyChildren">

</collection>
</resultMap>

<resultMap type="com.stonewu.blog.core.entity.custom.ReplyTree" id="replyTreeChild">
<id column="id" property="id"/>
<result column="content" property="content"/>
<result column="article_id" property="articleId"/>
<result column="author_id" property="authorId"/>
<result column="parent_reply_id" property="parentReplyId"/>
<result column="check_reply" property="checkReply"/>
<collection column="id=id,authorId=author_id" property="children" ofType="com.stonewu.blog.core.entity.custom.ReplyTree" javaType="java.util.ArrayList" select="getReplyChildren">

</collection>
</resultMap>

因为父查询中,需要查出顶层的评论,所以parent_reply_id应该为null,同时为了查询出自己评论的,但是未审核的,就需要下方<if test="param.authorId != null">的代码

阅读更多

Spring中的ThreadPoolTaskExecutor的参数:corePoolSize、maxPoolSize、queueCapacity分别是什么意思

问题:

今天线上爆出了一个问题,很多的异步线程都跑的非常慢

多线程使用的是Spring的ThreadPoolTaskExecutor

配置如下

1
2
3
corePoolSize: 5
maxPoolSize: 500
queueCapacity: 100

错误逻辑

之前以为的逻辑(错误逻辑):
corePoolSize:默认创建线程数量:5个,

maxPoolSize:如果线程数量超过5个后,在maxPoolSize大小内继续增加线程,直到线程数量到达500个,

queueCapacity:线程数量到达maxPoolSize以后,再添加线程,将会进入queueCapacity进行等待,当等待队列超过queueCapacity设定的值,抛出异常。

可是。。。。现实狠狠的抽了我一巴掌

因为线上发现,线程执行的速度非常慢,很多线程创建了以后并没有执行,而且可以确定线程没有超过500个

百度了一堆,都没有找到这几个参数的正确解释,直到最终看了看源码,发现正确的逻辑是这样的:

正确逻辑

corePoolSize:当线程数小于corePoolSize个的时候,正常创建线程

queueCapacity:当线程大于corePoolSize个的时候,将线程放入queueCapacity大小的队列

maxPoolSize:当queueCapacity队列已满,将会继续创建线程,直到线程数超过maxPoolSize的大小,将抛出异常

于是线上的问题就找到了,实际上,线程在跑的一直只有5个,所以导致线程一直不执行

解决办法:

也简单,把corePoolSize的大小增大到500即可。

dmesg命令查看java程序突然挂掉的原因

最近做项目,总是发现项目突然挂掉,但是java的日志又没有显示任何内容。

网上搜索了一波才知道了这个命令

1
2
3
4
5
# 按时间格式显示
dmesg -T

# 显示跟java 有关的日志
dmesg -T | grep "(java)"

最终打印的信息如下

1
2
[Wed May  8 09:40:57 2019] Out of memory: Kill process 5348 (java) score 125 or sacrifice child
[Wed May 8 09:40:57 2019] Killed process 5348 (java) total-vm:6105560kB, anon-rss:1032792kB, file-rss:0kB, shmem-rss:0kB

看来的确是因为内存不足导致的进程被杀

mongodb用户管理以及连接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 使用帐户名连接
mongo -u 用户名 -p 密码 --host 数据库地址

# 创建账户
# 创建超级管理员,角色:root
db.createUser({user:"用户名",pwd:"密码",roles:["root"]})

# 创建账户管理员
db.createUser({user:"用户名",pwd:"密码",roles:["userAdminAnyDatabase"]})

# 创建名为test的数据库拥有者账户
# 先切换到需要创建的数据库
use test
db.createUser({user:"用户名",pwd:"密码",roles:[{role:"dbOwner",db:"test"}]})

#查看用户
show users

#删除单个用户
db.system.users.remove({user:"用户名"})

# 创建数据库
use 数据库名
# 如果不存在该数据库,就会创建一个