开发小记6

一、@RequestBody 问题

1.Post 请求的content-type为Application/json时,后端使用@RequestBody接收。

@RequestBody 接收post请求体中的json字符串。
@RequestBody 修饰一个对象时。将json字符串的属性和值封装到对象中。

需要注意!

@RequestBody 修饰一个String 类型的字符串时,字符串会接收整个json串作为他的值。
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
1.可以通过Map 接收单个json 参数。
2.通过自定义注解完成接收。优雅的接收单个参数的 post 请求

1.2 前端传递日期,requestbody接收

一般都是使用@DateTimeFormat把传给后台的时间字符串转成Date,使用@JsonFormat把后台传出的Date转成时间字符串,但是@DateTimeFormat只会在类似@RequestParam的请求参数(url拼接的参数才生效,如果是放到RequestBody中的form-data也是无效的)上生效,如果@DateTimeFormat放到@RequestBody下是无效的。

在@RequestBody中则可以使用@JsonFormat把传给后台的时间字符串转成Date,也就是说@JsonFormat其实既可以把传给后台的时间字符串转成Date也可以把后台传出的Date转成时间字符串。

@JsonFormat(pattern = “yyyy-MM-dd HH:mm:ss”, timezone = “GMT+8”)
private Date time;

1.3 前后端 数据库时间问题

一文搞定springboot处理时间日期格式化、序列化问题(从数据库至前端)

二、springcloud bus

现在有三个服务,3355,3366,3377,如果我想一次性通知3355和3366

curl -X POST 
"http://localhost:3344/actuator/bus-refresh/
{config-client:3355,config-client:3366}
{服务名称:端口号}

三、线程池问题

newSingleThreadExecutor:
	创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。
	 如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。

newFixedThreadPool:
	创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。
	 线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。

newCachedThreadPool:
	创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60秒不执行任务)的线程,

	当任务数增加时,此线程池又可以智能的添加新线程来处理任务。
	 此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。

newScheduledThreadPool:
	创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。

newSingleThreadExecutor:
	创建一个单线程的线程池。此线程池支持定时以及周期性执行任务的需求。

3.1 线程池队列

  1. 直接提交的任务队列(SynchronousQueue)coreporesize 失效

加到maximumPoolSize——>拒绝

2.有界的任务队列(ArrayBlockingQueue)

指定队列大小 ,

加到corePoolSize——>加到队列中——>加到maximumPoolSize——>拒绝

3.无界的任务队列(LinkedBlockingQueue) maxPoreSixe 失效

加到corePoolSize——>加到队列中···直到资源耗尽的尽头
————————————————

五、workQueue 工作队列

新任务被提交后,会先进入到此工作队列中,任务调度时再从队列中取出任务。jdk中提供了四种工作队列:

①ArrayBlockingQueue

基于数组的有界阻塞队列,按FIFO排序。新任务进来后,会放到该队列的队尾,有界的数组可以防止资源耗尽问题。当线程池中线程数量达到corePoolSize后,再有新任务进来,则会将任务放入该队列的队尾,等待被调度。如果队列已经是满的,则创建一个新线程,如果线程数量已经达到maxPoolSize,则会执行拒绝策略。

②LinkedBlockingQuene

基于链表的无界阻塞队列(其实最大容量为Interger.MAX),按照FIFO排序。由于该队列的近似无界性,当线程池中线程数量达到corePoolSize后,再有新任务进来,会一直存入该队列,而基本不会去创建新线程直到maxPoolSize(很难达到Interger.MAX这个数),因此使用该工作队列时,参数maxPoolSize其实是不起作用的。

③SynchronousQuene

一个不缓存任务的阻塞队列,生产者放入一个任务必须等到消费者取出这个任务。也就是说新任务进来时,不会缓存,而是直接被调度执行该任务,如果没有可用线程,则创建新线程,如果线程数量达到maxPoolSize,则执行拒绝策略。

四 replace into

链接 replace into

 对表进行replace into操作的时候,
如果表只包含主键:
   当不存在冲突时,replace into 相当于insert操作。
   当存在冲突时,replace into 相当于update操作。
如果表包含主键和唯一性索引:
   当不存在冲突时,replace into 相当于insert操作。 
   当存在主键冲突的时候是先delete再insert,如果主键是自增的,则自增主键会做 +1 操作。
   当存在唯一性索引冲突的时候是直接update。将update。
主键和唯一键同时冲突,如果需要插入的值的主键 和唯一和表中已经存在记录同时冲突。
replace into yyz values(1,3,6);
    可以看到,replace中id=1和第一条记录冲突,
而b=3,c=6和最后一天记录冲突,我们可以看看binlog中的结果:
    我们可以看到,相当于删除了id=1的记录,
然后将最后一条记录的id进行了一个update的操作,改为了1。
### DELETE FROM test.yyz
### WHERE
### @1=1 /* INT meta=0 nullable=0 is_null=0 */
### @2=2 /* INT meta=0 nullable=1 is_null=0 */
### @3=4 /* INT meta=0 nullable=1 is_null=0 */
B5JhVRiWYHC+OAAAAP4BAAAAAMoMAAAAAAEAA///+AUAAAADAAAABgAAAPgBAAAAAwAAAAYAAAA=
\'/*!*/;
### UPDATE test.yyz
### WHERE
### @1=5 /* INT meta=0 nullable=0 is_null=0 */
### @2=3 /* INT meta=0 nullable=1 is_null=0 */
### @3=6 /* INT meta=0 nullable=1 is_null=0 */
### SET
### @1=1 /* INT meta=0 nullable=0 is_null=0 */
### @2=3 /* INT meta=0 nullable=1 is_null=0 */
### @3=6 /* INT meta=0 nullable=1 is_null=0 */

4.1 ON DUPLICATE KEY UPDATE

总结:

1:ON DUPLICATE KEY UPDATE需要有在INSERT语句中有存在主键或者唯一索引的列,并且对应的数据已经在表中才会执行更新操作。而且如果要更新的字段是主键或者唯一索引,不能和表中已有的数据重复,否则插入更新都失败。

2:不管是更新还是增加语句都不允许将主键或者唯一索引的对应字段的数据变成表中已经存在的数据。

五、map hashtable concurrent null 问题

HashMap,HashTable,ConcurrentHashMap关于null键值对存储的剖析
那么我就开始思考,为什么这样设计呢?后来翻阅很多资料和分析得出这样一个我个人觉得比较合理的结论:
ConcurrentHashmap和Hashtable都是线程安全用来做支持并发的,这样会有一个问题,当你通过get(k)获取对应的value时,如果获取到的是null时,你无法判断,它是put(k,v)的时候value为null,还是这个key从来没有做过映射。而HashMap是非并发的,可以通过contains(key)来做这个判断。而支持并发的Map在调用m.contains(key)和m.get(key),m很可能已经不同了

六 修改jar 包源码

根据类的加载顺序不同。
JAVA-如何修改源码(重写JAR包里的类)

6.1 validate 统一异常

Springboot配置捕捉validate校验参数异常统一处理并自定义validate校验返回格式
Spring 参数校验的异常处理

BindException
请求参数绑定到java bean上失败时抛出

关键词 : @Valid 、 Java bean 、表单(Content-Type: multipart/form-data)

aa

MethodArgumentNotValidException
请求体绑定到java bean上失败时抛出

关键词 : @Valid 、 @RequestBody、Java bean 、
表单(Content-Type: application/json、Content-Type: application/xml)

aa
ca

ConstraintViolationException

注意,@Validated 注解需要打在类上

普通参数(非 java bean)校验出错时抛出	
关键词 : @Validated 、 非Java bean

aa

6.2 递归查询 父子节点

如何通过递归找父节点或子节点详解

7 spring源码

Spring源码环境构建及相应的报错解决
spring 源码下载
Spring 源码(spring-5.2.9.RELEASE)编译及 IDEA 环境搭建

IDEA构建Spring源码,不成功你来抓我
测试aop

8.mybatis in很多个

解决in操作参数超过1000条出现bug的方案

9.springboot websocket

springboot websocket 入门到集群

10. hashmap 对象存储问题

一个Long对象占内存计算:在HashMap<Long,Long>结构中,只有Key和Value所存放的两个长整型数据是有效数据,共16字节(2×8字节)。这两个长整型数据包装成java.lang.Long对象之后,就分别具有8字节的MarkWord、8字节的Klass指针,再加8字节存储数据的long值(一个包装对象占24字节)。
然后这2个Long对象组成Map.Entry之后,又多了16字节的对象头(8字节MarkWord+8字节Klass指针=16字节),然后一个8字节的next字段和4字节的int型的hash字段(8字节next指针+4字节hash字段+4字节填充=16字节),为了对齐,还必须添加4字节的空白填充,最后还有HashMap中对这个Entry的8字节的引用,这样增加两个长整型数字,实际耗费的内存为(Long(24byte)×2)+Entry(32byte)+HashMapRef(8byte)=88byte,空间效率为有效数据除以全部内存空间,即16字节/88字节=18%。
——《深入理解Java虚拟机》5.2.6

接入第三方登录是让用户方便快捷地使用已有账号登录你的网站或应用程序,提高用户体验的一种方式。本文将介绍如何使用 PHP 实现微信公众号第三方登录。 1. 获取微信授权 首先,需要获取微信用户的授权。具体步骤如下: 1)引导用户打开微信授权页面: ```php $appid = 'your_appid'; $redirect_uri = urlencode('http://yourdomain.com/callback.php'); $scope = 'snsapi_userinfo'; $url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=$appid&redirect_uri=$redirect_uri&response_type=code&scope=$scope&state=STATE#wechat_redirect"; header("Location: $url"); ``` 其中,`$appid` 是你的微信公众号的 AppID,`$redirect_uri` 是授权后回调的 URL,`$scope` 是授权作用域,可以是 `snsapi_base` 或 `snsapi_userinfo`,`$state` 是自定义参数,用于防止 CSRF 攻击。 2)获取授权码: 用户同意授权后,会重定向到 `$redirect_uri` 指定的 URL,带上授权码 `code` 和 `state` 参数。 ```php $code = $_GET['code']; $state = $_GET['state']; ``` 3)获取 access_token 和 openid: 使用授权码 `code` 获取 `access_token` 和 `openid`。 ```php $access_token_url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=$appid&secret=$secret&code=$code&grant_type=authorization_code"; $response = file_get_contents($access_token_url); $result = json_decode($response, true); $access_token = $result['access_token']; $openid = $result['openid']; ``` 其中,`$secret` 是你的微信公众号的 AppSecret。 2. 获取用户信息 获取到 `access_token` 和 `openid` 后,可以使用以下代码获取用户信息: ```php $userinfo_url = "https://api.weixin.qq.com/sns/userinfo?access_token=$access_token&openid=$openid&lang=zh_CN"; $response = file_get_contents($userinfo_url); $userinfo = json_decode($response, true); ``` 其中,`$userinfo` 包含用户的昵称、头像等信息。 3. 将用户信息保存到数据库 最后,将获取到的用户信息保存到数据库中,以便下次使用时快速登录。 ```php // 连接数据库 $con = mysqli_connect('localhost', 'username', 'password', 'database'); mysqli_set_charset($con, "utf8"); // 查询用户是否已存在 $sql = "SELECT * FROM users WHERE openid='$openid'"; $result = mysqli_query($con, $sql); if (mysqli_num_rows($result) == 0) { // 用户不存在,插入新用户信息 $nickname = mysqli_real_escape_string($con, $userinfo['nickname']); $headimgurl = mysqli_real_escape_string($con, $userinfo['headimgurl']); $sql = "INSERT INTO users (openid, nickname, headimgurl) VALUES ('$openid', '$nickname', '$headimgurl')"; mysqli_query($con, $sql); } // 保存用户登录状态 $_SESSION['openid'] = $openid; ``` 以上就是使用 PHP 实现微信公众号第三方登录的步骤。需要注意的是,为了确保安全性,应该对用户输入的数据进行过滤和验证,防止 SQL 注入和 XSS 攻击等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值