https://blog.csdn.net/tengdazhang770960436/article/details/56834693
package com.test.field;
public class Test {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class GetFieldNamesUtils {
public static void main(String[] args) {
getFiledsNameWithBlankLine("com.test.field.Test");
System.out.println("===================");
getFiledsNameWithPoint("com.test.field.Test");
}
/**
* 把属性通过换行的方式输出出来
* @author ztd
* @param classPath
*/
private static void getFiledsNameWithBlankLine(String classPath) {
Class<?> clazz = null;
try {
clazz = Class.forName(classPath);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Field[] fields = clazz.getDeclaredFields();
for(Field f : fields) {
System.out.println(f.getName());
}
}
/**
* 把属性通过“,”连接起来输出
* @author ztd
* @param classPath
*/
private static void getFiledsNameWithPoint(String classPath) {
Class<?> clazz = null;
try {
clazz = Class.forName(classPath);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Field[] fields = clazz.getDeclaredFields();
StringBuffer sb = new StringBuffer();
for(Field f : fields) {
sb.append(f.getName()).append(",");
}
System.out.println(sb.toString());
}
}
https://www.cnblogs.com/qiuting/p/5373571.html
String a;
null
a != null
""
a.length()!=0
https://www.cnblogs.com/qianguyihao/p/3929585.html
https://www.cnblogs.com/qianguyihao/p/3929585.html
https://blog.csdn.net/tjcyjd/article/details/6981382#
Calendar ca = Calendar.getInstance();// 得到一个Calendar的实例
//ca.setTime(new Date()); // 设置时间为当前时间
ca.set(2011, 11, 17);// 月份是从0开始的,所以11表示12月
ca.add(Calendar.YEAR, -1); // 年份减1
ca.add(Calendar.MONTH, -1);// 月份减1
ca.add(Calendar.DATE, -1);// 日期减1
Date resultDate = ca.getTime(); // 结果
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
System.out.println(sdf.format(resultDate));
https://blog.csdn.net/mononoke111/article/details/81088472
https://www.cnblogs.com/xuezhaochang/p/14875275.html
public class MapTest {
public static void main(String[] args) {
HashMap<String, String> map = new HashMap<>();
map.put("1", "张三");
map.put("2", "李四");
map.put("3", "王五");
map.put("4", "赵六");
//1 通过map.keyset遍历输出集合
for (String s : map.keySet()) {
System.out.println("key: " + s + " value: " + map.get(s));
}
for (String s2 : map.values()) {//遍历map的值
System.out.println("值value :" + s2);
}
//2 Map.Entry的加强for循环遍历输出键key和值value
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println("key: " + entry.getKey() + ",value: " + entry.getValue());
}
//3 Iterator遍历获取,然后获取到Map.Entry,再得到getKey()和getValue()
Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
while (iterator.hasNext()){
Map.Entry<String, String> next = iterator.next();
System.out.println("key: " + next.getKey() + ",value: " + next.getValue());
}
}
}
https://www.jianshu.com/p/4a1515374a34
class MapTest {
// 1
private static final Map<String, String> TEST_1 =
Map.ofEntries(
Map.entry("1", "A"),
Map.entry("2", "B")
// Map.entry(null, null)
// 运行时空指针异常,不支持存放null key&&value
);
// 2
private static final Map<String, String> TEST_2 = new HashMap<>() {
{
put("1", "A");
put("2", "B");
}
};
// 3
private static HashMap<String,String> networkAttrMap;
static {
networkAttrMap = new HashMap<>();
networkAttrMap.put("08","企");
networkAttrMap.put("24","红");
networkAttrMap.put("2","区");
networkAttrMap.put("3","绿");
networkAttrMap.put("47","其它");
}
获取现在时间:
public void setTime(Map<String, Object> map, String key, int day) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date = new Date();
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.add(Calendar.DAY_OF_MONTH, day); // 前day天
date = calendar.getTime();
map.put(key, sdf.format(date));
}
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String formattedDate = sdf.format(date);
System.out.println("Formatted date: " + formattedDate);
获取字符串对应的时间 的前x天
public void setCustomTime(Map<String, Object> params, Date time, String key, int day) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date = sdf.parse(String.valueOf(time));
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.add(Calendar.DAY_OF_MONTH, day); // 前day天
date = calendar.getTime();
params.put(key, sdf.format(date));
}
Timeout.ofMilliseconds(5000L);
这里是5000毫秒=5秒
https://www.cnblogs.com/lanxuezaipiao/p/3369962.html
https://www.cnblogs.com/xzwblog/p/6959500.html
https://zhuanlan.zhihu.com/p/409379105
https://blog.csdn.net/gental_z/article/details/122303540
参数校验,不符合要求的要
throw new InvalidParameterException("field is error");
这样会返回400状态码
否则mybati 报错就返回500状态码了
类校验
private Order order;
用于mysql的排序字段
public class Order {
/**
* @排序字段
*
* @取值范围:lastModifiedTime 最后修改时间
* @默认为lastModifiedTime
*/
@Size(max = 512, message = "长度必须大于等于0或小于等于512")
private String field;
/**
* @升降序方式
* @asc 升序排列
* @desc 降序排列(默认)
*/
@Size(max = 4, message = "长度必须大于等于0或小于等于4")
private String direction;
public Order() {
this.setDirection("desc");
}
@Override
public String toString() {
return field + " " + direction;
}
}
public void checkParameter() {
boolean flag = false;
if (this.order != null) {
if (this.order.getField() != null && this.order.getField().length() != 0) {
FIELD[] fields = FIELD.values();
for (FIELD field : fields) {
if (field.toString().equals(this.order.getField())) {
flag = true;
break;
}
}
} else {
flag = true;
}
if (flag == false) {
throw new InvalidParameterException("field is error");
}
if (!this.getOrder().getDirection().equalsIgnoreCase("asc")
&& !this.getOrder().getDirection().equalsIgnoreCase("desc")) {
throw new InvalidParameterException("direction is error");
}
if (this.order.getField() != null
&& this.order.getField().length() == 0
&& this.order.getDirection() != null) {
this.order.setDirection("");
}
}
}
// 排序设置
request.checkParameter();
if (request.getOrder() != null) {
if (!request.getOrder().toString().equals(" ")) {
request.setOrderBy(request.getOrder().toString());
} else {
request.setOrderBy(null);
}
}
https://www.jianshu.com/p/4f7f191fe825
服务器字段和客户端字段名称区分,不用保持一一对应关系,客户端定义的字段不用根据服务端接口字段改变而改变,只需要更改@SerializedName中的取值即可
@SerializedName(value = "bookmarkId", alternate = {"bookmark_id"})
private String bookmarkId;
枚举的规范是 全大写
public enum FIELD {
ACCOUNTNAME("accountName"),
SECURITYROLEID("securityRoleId"),
OPERATIONDEVICEID("operationDeviceId"),
DEVICEID("deviceId"),
NETWORKATTRID("networkAttrId"),
OPERATIONIP("operationIp"),
OPERATIONTIME("operationTime"),
CREATETIME("createTime");
private FIELD(String type) {
this.setType(type);
}
public String getType() {
return type;
}
/**
* 功能说明:
*
* @param type type
*/
public void setType(String type) {
this.type = type;
}
private String type;
}
https://www.laobuluo.com/8372.html
校验数字的表达式
数字:^[0-9]*$
n位的数字:^\d{n}$
至少n位的数字:^\d{n,}$
m-n位的数字:^\d{m,n}$
零和非零开头的数字:^(0|[1-9][0-9]*)$
非零开头的最多带两位小数的数字:^([1-9][0-9]*)+(\.[0-9]{1,2})?$
带1-2位小数的正数或负数:^(\-)?\d+(\.\d{1,2})$
正数、负数、和小数:^(\-|\+)?\d+(\.\d+)?$
有两位小数的正实数:^[0-9]+(\.[0-9]{2})?$
有1~3位小数的正实数:^[0-9]+(\.[0-9]{1,3})?$
非零的正整数:^[1-9]\d*$ 或 ^([1-9][0-9]*){1,3}$ 或 ^\+?[1-9][0-9]*$
非零的负整数:^\-[1-9][]0-9"*$ 或 ^-[1-9]\d*$
非负整数:^\d+$ 或 ^[1-9]\d*|0$
非正整数:^-[1-9]\d*|0$ 或 ^((-\d+)|(0+))$
非负浮点数:^\d+(\.\d+)?$ 或 ^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$
非正浮点数:^((-\d+(\.\d+)?)|(0+(\.0+)?))$ 或 ^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$
正浮点数:^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$ 或 ^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$
负浮点数:^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$ 或 ^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$
浮点数:^(-?\d+)(\.\d+)?$ 或 ^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$
校验字符的表达式
汉字:^[\u4e00-\u9fa5]{0,}$
英文和数字:^[A-Za-z0-9]+$ 或 ^[A-Za-z0-9]{4,40}$
长度为3-20的所有字符:^.{3,20}$
由26个英文字母组成的字符串:^[A-Za-z]+$
由26个大写英文字母组成的字符串:^[A-Z]+$
由26个小写英文字母组成的字符串:^[a-z]+$
由数字和26个英文字母组成的字符串:^[A-Za-z0-9]+$
由数字、26个英文字母或者下划线组成的字符串:^\w+$ 或 ^\w{3,20}$
中文、英文、数字包括下划线:^[\u4E00-\u9FA5A-Za-z0-9_]+$
中文、英文、数字但不包括下划线等符号:^[\u4E00-\u9FA5A-Za-z0-9]+$ 或 ^[\u4E00-\u9FA5A-Za-z0-9]{2,20}$
可以输入含有^%&',;=?$\"等字符:[^%&',;=?$\x22]+
禁止输入含有~的字符:[^~]+
特殊需求表达式
Email地址:^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$
域名:[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+\.?
InternetURL:[a-zA-z]+://[^\s]* 或 ^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$
手机号码:^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$
电话号码("XXX-XXXXXXX"、"XXXX-XXXXXXXX"、"XXX-XXXXXXX"、"XXX-XXXXXXXX"、"XXXXXXX"和"XXXXXXXX):^(\(\d{3,4}-)|\d{3.4}-)?\d{7,8}$
国内电话号码(0511-4405222、021-87888822):\d{3}-\d{8}|\d{4}-\d{7}
电话号码正则表达式(支持手机号码,3-4位区号,7-8位直播号码,1-4位分机号): ((\d{11})|^((\d{7,8})|(\d{4}|\d{3})-(\d{7,8})|(\d{4}|\d{3})-(\d{7,8})-(\d{4}|\d{3}|\d{2}|\d{1})|(\d{7,8})-(\d{4}|\d{3}|\d{2}|\d{1}))$)
身份证号(15位、18位数字),最后一位是校验位,可能为数字或字符X:(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)
帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线):^[a-zA-Z]\w{5,17}$
强密码(必须包含大小写字母和数字的组合,不能使用特殊字符,长度在 8-10 之间):^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])[a-zA-Z0-9]{8,10}$
强密码(必须包含大小写字母和数字的组合,可以使用特殊字符,长度在8-10之间):^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$
日期格式:^\d{4}-\d{1,2}-\d{1,2}
一年的12个月(01~09和1~12):^(0?[1-9]|1[0-2])$
一个月的31天(01~09和1~31):^((0?[1-9])|((1|2)[0-9])|30|31)$
钱的输入格式:
1 有四种钱的表示形式我们可以接受:"10000.00" 和 "10,000.00", 和没有 "分" 的 "10000" 和 "10,000":^[1-9][0-9]*$
2 这表示任意一个不以0开头的数字,但是,这也意味着一个字符"0"不通过,所以我们采用下面的形式:^(0|[1-9][0-9]*)$
3 一个0或者一个不以0开头的数字.我们还可以允许开头有一个负号:^(0|-?[1-9][0-9]*)$
4 这表示一个0或者一个可能为负的开头不为0的数字.让用户以0开头好了.把负号的也去掉,因为钱总不能是负的吧。下面我们要加的是说明可能的小数部分:^[0-9]+(.[0-9]+)?$
5 必须说明的是,小数点后面至少应该有1位数,所以"10."是不通过的,但是 "10" 和 "10.2" 是通过的:^[0-9]+(.[0-9]{2})?$
6 这样我们规定小数点后面必须有两位,如果你认为太苛刻了,可以这样:^[0-9]+(.[0-9]{1,2})?$
7 这样就允许用户只写一位小数.下面我们该考虑数字中的逗号了,我们可以这样:^[0-9]{1,3}(,[0-9]{3})*(.[0-9]{1,2})?$
8 1到3个数字,后面跟着任意个 逗号+3个数字,逗号成为可选,而不是必须:^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(.[0-9]{1,2})?$
9 备注:这就是最终结果了,别忘了"+"可以用"*"替代如果你觉得空字符串也可以接受的话(奇怪,为什么?)最后,别忘了在用函数时去掉去掉那个反斜杠,一般的错误都在这里
xml文件:^([a-zA-Z]+-?)+[a-zA-Z0-9]+\\.[x|X][m|M][l|L]$
中文字符的正则表达式:[\u4e00-\u9fa5]
双字节字符:[^\x00-\xff] (包括汉字在内,可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1))
空白行的正则表达式:\n\s*\r (可以用来删除空白行)
HTML标记的正则表达式:<(\S*?)[^>]*>.*?|<.*? /> ( 首尾空白字符的正则表达式:^\s*|\s*$或(^\s*)|(\s*$) (可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式)
腾讯QQ号:[1-9][0-9]{4,} (腾讯QQ号从10000开始)
中国邮政编码:[1-9]\d{5}(?!\d) (中国邮政编码为6位数字)
IPv4地址:((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})(\.((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})){3}
https://blog.51cto.com/u_16175519/6885958
public class StringSubtractionExample {
public static String subtractOne(String str) {
StringBuilder sb = new StringBuilder(str);
int index = sb.length() - 1;
while (index >= 0) {
char c = sb.charAt(index);
if (c != '0') {
sb.setCharAt(index, (char) (c - 1));
break;
} else {
sb.setCharAt(index, '9');
index--;
}
}
return sb.toString();
}
public static void main(String[] args) {
String str = "100";
System.out.println("原始字符串: " + str);
String result = subtractOne(str);
System.out.println("减1后的字符串: " + result);
}
}
注解
https://juejin.cn/post/6844903902811275278
https://blog.csdn.net/suprezheng/article/details/104007310
https://blog.csdn.net/CSDN2497242041/article/details/122272752
https://juejin.cn/post/6977614729103540261
https://www.peiluming.com/article/24
注解太笨拙了
多重注解? 自定义注解? 顾汇宁
手动写方法进行参数校验
private CloseableHttpClient httpClient = HttpClients.createDefault();
private RequestConfig requestConfig = RequestConfig.custom()
//从连接池中获取连接的超时时间
.setConnectionRequestTimeout(Timeout.ofMilliseconds(timeout*2))
//建立连接的超时时间
.setConnectTimeout(Timeout.ofMilliseconds(timeout*2))
//设置响应超时时间
.setResponseTimeout(Timeout.ofMilliseconds(timeout*2))
// 是否自动重定向
.setRedirectsEnabled(false)
.build();
均是毫秒
1000毫秒=1秒
https://blog.csdn.net/T2080305/article/details/80551855
超时时间设置过短会造成:
java.net.SocketTimeoutException: Read timed out
at java.net.SocketInputStream.socketRead0(Native Method) ~[?:1.8.0_201]
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116) ~[?:1.8.0_201]
at java.net.SocketInputStream.read(SocketInputStream.java:171) ~[?:1.8.0_201]
at java.net.SocketInputStream.read(SocketInputStream.java:141) ~[?:1.8.0_201]
at org.apache.hc.core5.http.impl.io.SessionInputBufferImpl.fillBuffer(SessionInputBufferImpl.java:149) ~[httpcore5-5.1.5.jar:5.1.5]
at org.apache.hc.core5.http.impl.io.SessionInputBufferImpl.readLine(SessionInputBufferImpl.java:280) ~[httpcore5-5.1.5.jar:5.1.5]
at org.apache.hc.core5.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:241) ~[httpcore5-5.1.5.jar:5.1.5]
at org.apache.hc.core5.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:53) ~[httpcore5-5.1.5.jar:5.1.5]
at org.apache.hc.core5.http.impl.io.DefaultBHttpClientConnection.receiveResponseHeader(DefaultBHttpClientConnection.java:298) ~[httpcore5-5.1.5.jar:5.1.5]
at org.apache.hc.core5.http.impl.io.HttpRequestExecutor.execute(HttpRequestExecutor.java:175) ~[httpcore5-5.1.5.jar:5.1.5]
at org.apache.hc.core5.http.impl.io.HttpRequestExecutor.execute(HttpRequestExecutor.java:218) ~[httpcore5-5.1.5.jar:5.1.5]
at org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager$InternalConnectionEndpoint.execute(PoolingHttpClientConnectionManager.java:712) ~[httpclient5-5.2.1.jar:5.2.1]
at org.apache.hc.client5.http.impl.classic.InternalExecRuntime.execute(InternalExecRuntime.java:216) ~[httpclient5-5.2.1.jar:5.2.1]
at org.apache.hc.client5.http.impl.classic.MainClientExec.execute(MainClientExec.java:116) ~[httpclient5-5.2.1.jar:5.2.1]
at org.apache.hc.client5.http.impl.classic.ExecChainElement.execute(ExecChainElement.java:51) ~[httpclient5-5.2.1.jar:5.2.1]
at org.apache.hc.client5.http.impl.classic.ConnectExec.execute(ConnectExec.java:188) ~[httpclient5-...
https://developer.aliyun.com/article/644782
方法一: 直观, 方便, 但效率很低
if(s == null ||"".equals(s));
方法二: 效率高
if(s == null || s.length() <= 0);
方法三: Java SE 6.0 才开始提供的方法, 效率和方法二几乎相等, 但出于兼容性考虑, 推荐使用方法二.
if(s == null || s.isEmpty());
方法四:
if (s == null || s == "");
s == null 是有必要存在的
如果 String 类型为null, 而去进行 equals(String) 或 length() 等操作会抛出java.lang.NullPointerException.
s==null 的顺序必须出现在前面,不然同样会抛出java.lang.NullPointerException.
https://blog.csdn.net/sinat_32502451/article/details/133774582
类似登录客户端的处理,有时会出现网络抖动、连接超时等异常,这时候就需要进行多次重试
<dependency>
<groupId>org.springframework.retrygroupId>
<artifactId>spring-retryartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-aopartifactId>
dependency>
Application 启动类上,添加 @EnableRetry 注解
@SpringBootApplication(scanBasePackages = {"com.example.demo"})
@EnableRetry
public class DemoApplication {
}
@Slf4j
@Service
public class RetryServiceImpl {
@Retryable(value = Exception.class,maxAttempts = 3,backoff = @Backoff(delay = 3000,multiplier = 1.5))
public void doSomething() {
log.info("doSomething start.");
int result = 1/0;
log.info("doSomething end.");
}
/**
* @Recover 的返回类型,必须跟 @Retryable修饰的方法返回值一致。否则不生效。
*
*/
@Recover
public void recover(Exception e) {
log.info("retry failed recover");
log.info("retry Exception:"+e);
//是否需要入库记录
}
}
value:抛出指定异常才会重试
exclude:指定不处理的异常
maxAttempts:最大重试次数,默认3次
backoff:重试等待策略,默认使用@Backoff
@Backoff的value(相当于delay)表示隔多少毫秒后重试,默认为1000L
multiplier(指定延迟倍数)默认为0,表示固定暂停1秒后进行重试
@Retryable 底层使用的是 AOP,因此不能在同一个类里调用 @Retryable修饰的方法,不会生效
https://blog.csdn.net/qq_53158952/article/details/126911589
netstat -aon|findstr "xxxx"
taskkill /f /t /im xxxx
https://blog.csdn.net/Connie1451/article/details/120045474
用策略模式
volatile
https://blog.csdn.net/weixin_40598838/article/details/112861491
https://github.com/apache/shardingsphere/issues/5882
禁止安全检查
management:
health:
db:
enabled: false
lock、synchronize 只在单 jvm 有效,多集群 会失效
3中实现方式:
数据库
redis:
redis 的key 唯一
https://blog.csdn.net/weixin_30131185/article/details/115572186
https://blog.csdn.net/weixin_53972936/article/details/1238993682
https://blog.csdn.net/arjun_yu/article/details/115294665
@Scheduled(cron="${a.b.cron}")
定时任务 @Scheduled 不启动,解决办法:
https://blog.csdn.net/wenyichuan/article/details/119179364
定时任务 区分不同环境 是否启动
https://blog.csdn.net/qq_31122833/article/details/105431087
配置文件名必须是 application
application-log 就不行
@ConditionalOnProperty(prefix = "sence", name = "isBlue", havingValue = "true")
public class Task {
...
}
application.yml
sence:
isBlue: true
启动类注解:
@EnableSchedulin
public class Application {
...
}
配置类 不同环境 是否启动
@ConditionalOnProperty(value = "sence.isred")
public class Config {}
sence.isred = true
https://www.cnblogs.com/MrFugui/p/15610746.html
https://blog.csdn.net/weixin_45410366/article/details/126618512
序列化:将对象状态转换为可保持、传输的格式 = 对象转换为字节序列
反序列化:将流转换为对象 = 字节序列恢复为对象
这两个过程结合起来,可以轻松地存储和传输数据
一个类只有实现了 Serializable 接口,它的对象才是可序列化的
serialVersionUID 的作用:验证序列化和反序列化的过程中,对象是否保持一致
使用场景:
当我们需要把对象的状态信息:
A 通过网络进行传输(用套接字在网络上传送)
B 需要将对象的状态信息持久化(写入硬盘)
Serializable class without ‘serialVersionUID’
双击类名 → alt + enter
https://juejin.cn/post/6844903957186232327
https://blog.csdn.net/weixin_45155235/article/details/127320435
spring.datasource.db1.driver-class-name=
spring.datasource.db1.jdbc-url=
spring.datasource.db1.username=
spring.datasource.db1.password=
spring.datasource.db2.driver-class-name=
spring.datasource.db2.jdbc-url=
spring.datasource.db2.username=
spring.datasource.db2.password=
单个DataSource
spring.datasource.driver-class-name=
spring.datasource.jdbc-url=
spring.datasource.username=
spring.datasource.password=
long 对应 mysql 是 bigint(64)
java 中时间类型是 Date
mysql 中是 datetime
https://blog.csdn.net/weixin_47982446/article/details/121694366
https://blog.csdn.net/YIEBO/article/details/110881687
https://blog.csdn.net/Sibylsf/article/details/113138380
错误写法:
UPDATE Table_xxx
set Count=Count + 1
where 1=1
<if test="Id>0">
and Id = #{Id}
if>
<if test="text !=null">
and Text = #{text}
if>
当下面两个if条件都不满足时,会出现:
该表内所有数据都执行count+1,
故where 1=1 这种写法不可取
正确写法:
UPDATE Table_xxx
set Count=Count + 1
<where>
<if test="Id>0">
and Id = #{Id}
if>
<if test="text !=null">
and Text = #{text}
if>
where>
https://ask.csdn.net/questions/7741444
标签会过滤掉第1个在条件前的and或or,
也就是如果你在emp_name前写了一个and,它会自动过滤掉,后面的不会过滤
https://blog.csdn.net/weixin_38295272/article/details/117753097
https://blog.csdn.net/qq_40088250/article/details/88388715/
select a,b,c,d,e,f,g from biao where
java程序查询list,获取list.size(),如果数据量过大,会导致响应慢甚至404
应该 select count(*) from biao
一次只删除1000条数据
如果一次删除过多语句(如100万条数据),会影响这条sql语句的执行时间
可以一直删除,直到返回数为0
#{}
参数占位符,可防止sql注入,带引号
${}
纯 字符串替换,不带引号
https://blog.csdn.net/happy_cheng/article/details/41792985
<select id="find" resultType="JobLogVo">
<include refid="base"/>
where t.status='1'
AND <![CDATA[ t.createDate <= xxx ]]>
</select>
<![CDATA[ abc ]]>
abc中可以包含 < >
第一种写法(1):
原符号 < <= > >= & ' "
替换符号 < <= > >= & ' "
例如:sql如下:
create_date_time >= #{startTime} and create_date_time <= #{endTime}
第二种写法(2):
大于等于
<![CDATA[ >= ]]>
小于等于
<![CDATA[ <= ]]>
例如:sql如下:
create_date_time <![CDATA[ >= ]]> #{startTime} and create_date_time <![CDATA[ <= ]]> #{endTime}
get 请求,请求链接 放置参数
post 请求 才可以这样,参数不放在链接里:
search(@RequestBody XXX xx)
https://blog.csdn.net/u010476994/article/details/80986435
public class AnimalController {
@Autowired
private IAnimal dogImpl;
......
}
@Autowired 的注入方式是 byType 注入,
当要注入的类型在容器中存在多个时,Spring不知道要引入哪个实现类的,会报错
用 @Resource 或 @Qualifier 注解,byName 注入 不报错
public class AnimalController {
@Resource(name="dogImpl") //实现类1中 @Service注解中标定的名称
private IAnimal dogImpl;
......
}
public class AnimalController {
@Qualifier("DaoImpl") //实现类1的类名。注意区分与@Resource(name="dogImpl") 的区别。
private IAnimal dogImpl;
......
}
https://zhuanlan.zhihu.com/p/357050965
https://juejin.cn/post/6844904100111319054
1 项目在线的配置中心
2 配置文件xxx.properties
3 代码中的配置
4 vm options
http://www.javaboy.org/2019/0530/application.properties.html
resources 目录下创建 javaboy 目录,存放一个 application.properties 文件,
正常情况下,启动 Spring Boot 项目,这个配置文件是不会被自动加载的。
我们可以通过 spring.config.location 属性 指定配置文件位置,系统就会自动去指定目录下查找 application.properties 文件
项目已经打包成 jar ,在启动命令中加入位置参数即可:
java -jar properties-0.0.1-SNAPSHOT.jar --spring.config.location=classpath:/javaboy/
-Dspring.config.name 指定配置文件的文件名,默认是application.properties
属性注入
法1
@Component
@PropertySource("classpath:book.properties")
public class Book {
@Value("${book.id}")
private Long id;
@Value("${book.name}")
private String name;
@Value("${book.author}")
private String author;
}
法2
<context:property-placeholder location="classpath:book.properties"/>
@Component
public class Book {
@Value("${book.id}")
private Long id;
@Value("${book.name}")
private String name;
@Value("${book.author}")
private String author;
}
类型安全的属性注入
@Component
@PropertySource("classpath:book.properties")
@ConfigurationProperties(prefix = "book")
public class Book {
private Long id;
private String name;
private String author;
//省略getter/setter
}
@ConfigurationProperties(prefix = “book”) ,此时会自动将 Spring 容器中对应的数据注入到对象对应的属性中,不用通过 @Value 注解挨个注入了,减少工作量并且避免出错
application.properties:
spring.profiles.active=test
https://blog.csdn.net/u014163312/article/details/117049437
@ConditionalOnProperty(value = "sence.isBlue")
https://www.cnblogs.com/0201zcr/p/6262762.html
https://blog.csdn.net/u010316188/article/details/79598220
https://blog.csdn.net/u010316188/article/details/79598220
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.2</version>
<scope>provided</scope>
</dependency>
https://blog.csdn.net/londa/article/details/117906300
https://www.cnblogs.com/relucent/p/9792645.html
win10 的系统变量也可以读取,如果新加了系统变量,idea需要重启才能读取到
https://blog.csdn.net/vtopqx/article/details/79034835
所有的子模块使用依赖项的统一版本,必须确保应用的各个项目的依赖项和版本一致,才能保证测试的和发布的是相同的结果。
在父pom文件中,dependencyManagement元素 管理jar包的版本,让子项目中引用一个依赖而不用显示的列出版本号。
Maven会沿着父子层次向上走,直到找到一个拥有dependencyManagement元素的项目,然后它就会使用在这个dependencyManagement元素中指定的版本号
父pom
<dependencyManagement>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.44</version>
</dependency>
</dependencies>
</dependencyManagement>
子模块中只需要和即可
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
https://blog.csdn.net/sufu1065/article/details/126434530
afterPropertiesSet() 是 Spring 框架中的一个接口,它可以让开发人员在 Bean 实例化后,所有属性被设置后,执行自定义的初始化操作
https://www.cnblogs.com/hxgoto/p/16281052.html
https://blog.csdn.net/qq_42998034/article/details/115403048
pom
<dependency>
<groupId>com.github.ulisesbocchiogroupId>
<artifactId>jasypt-spring-boot-starterartifactId>
<version>2.1.2version>
dependency>
application.yml
spring:
data:
mongodb:
uri: mongodb://127.0.0.1:27017/bookmark
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/bookmarksdb3?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8
username: root
# password: "123456"
password: ENC(4DE4bFfmmsbqN/X12lrbwQ==)
server:
port: 8094
jasypt:
encryptor:
password: sad124f1f1rf1fgt5
property:
prefix: ENC(
suffix: )
# iv-generator-classname: org.jasypt.iv.NoIvGenerator
必须是yml文件!
application.properties、environment.properties 配置都不行!
config.xml 关联 application.yml
DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
关联application:
<properties resource="application.yml">properties>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC">transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${driver-class-name}">property>
<property name="url"
value="${url}">property>
<property name="username" value="${username}">property>
<property name="password" value="${password}">property>
value 对应 yml单个字段,不用写字段前的路径
dataSource>
environment>
environments>
<mappers>
<mapper resource="com/example/repository/mysqlRepository.xml">mapper>
mappers>
configuration>
jasypt-1.9.3.jar下载
https://download.csdn.net/download/qq_40893824/88062907
https://blog.csdn.net/qq_21118431/article/details/103551207
加密:
java -cp jasypt-1.9.3.jar org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI input="123456" password=sad124f1f1rf1fgt5 algorithm=PBEWithMD5AndDES
解密:
java -cp jasypt-1.9.3.jar org.jasypt.intf.cli.JasyptPBEStringDecryptionCLI input="加密串" password=sad124f1f1rf1fgt5 algorithm=PBEWithMD5AndDES
https://www.cnblogs.com/toutou/p/Jasypt.html
打包时隐藏jasypt.encryptor.password
,就需要打包时maven命令增加参数
clean package -Djasypt.encryptor.password=Bt%XJ^n1j8mz
部署时添加参数 Djasypt.encryptor.password
部署时完整命令 java -jar -Djasypt.encryptor.password=Bt%XJ^n1j8mz hello-0.0.1-SNAPSHOT.jar
private SqlSession getSqlSession() throws IOException {
InputStream inputStream = Mycontroller.class.getClassLoader().getResourceAsStream("config.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
InputStream in = Resources.getResourceAsStream("application.properties");
Properties props = new Properties();
props.load(in);
props.put("password", password);
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream, props);
return sqlSessionFactory.openSession(ExecutorType.BATCH, false);
}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.SecureRandom;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class HuaweiEncoding {
public static final String CHARSET_NAME = "UTF-8";
public static final String EXCEPTION = "exception";
public static final int IV_LENGTH = 16;
private static final int GCM_TAG_LENGTH = 128;
private static final Logger LOGGER = LoggerFactory.getLogger(HuaweiEncoding.class);
private static String AES = "秘钥"; 可以上网找
https://www.imaegoo.com/2020/aes-key-generator/
选128-bit
public static void main(String[] args) {
String encrypt = encrypt("8ffef99b85d64a768240be3fa23cf509b3285e54346e4e4292b31079c3720fb4");
System.out.println("加密后:" + encrypt);
String decrypt = decrypt(encrypt);
System.out.println("解密后:" + decrypt);
}
/**
* 解密字符串
*
* @param text 输入字符串
* @return 解密字符串
*/
public static String decrypt(String text) {
try {
byte[] data = Base64.getDecoder().decode(text);
byte[] decoded = decryptByGcm(data, AES);
return new String(decoded, CHARSET_NAME);
} catch (GeneralSecurityException | UnsupportedEncodingException exception) {
LOGGER.error(EXCEPTION, exception);
}
return "";
}
private static byte[] decryptByGcm(byte[] input, String key) throws GeneralSecurityException {
byte[] initVector = new byte[IV_LENGTH];
System.arraycopy(input, 0, initVector, 0, IV_LENGTH);
final Cipher gcmCipher = createGCM(key, initVector, Cipher.DECRYPT_MODE);
byte[] encrypted = new byte[input.length - IV_LENGTH];
System.arraycopy(input, IV_LENGTH, encrypted, 0, encrypted.length);
return gcmCipher.doFinal(encrypted);
}
private static Cipher createGCM(String key, byte[] initVector, int mode) throws GeneralSecurityException {
Cipher gcmCipher = Cipher.getInstance("AES/GCM/NoPadding");
gcmCipher.init(mode, getKey(key), new GCMParameterSpec(GCM_TAG_LENGTH, initVector));
return gcmCipher;
}
private static SecretKeySpec getKey(String myKey) {
int plus = 16 - myKey.trim().length();
byte[] data = myKey.trim().getBytes(StandardCharsets.UTF_8);
byte[] raw = new byte[16];
byte[] plusByte = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
};
for (int i = 0; i < 16; i++) {
raw[i] = i < data.length ? data[i] : plusByte[plus];
}
return new SecretKeySpec(raw, "AES");
}
/**
* 加密字符串
*
* @param text 输入字符串
* @return 加密字符串
*/
public static String encrypt(String text) {
try {
byte[] data = text.getBytes(CHARSET_NAME);
byte[] encoded = encryptByGcm(data, AES);
Base64.Encoder encoder = Base64.getEncoder();
return encoder.encodeToString(encoded);
} catch (UnsupportedEncodingException | GeneralSecurityException exception) {
LOGGER.error(EXCEPTION, exception);
}
return "";
}
private static byte[] encryptByGcm(byte[] input, String key) throws GeneralSecurityException {
byte[] initVector = generateSecureBytes(IV_LENGTH);
Cipher gcmCipher = createGCM(key, initVector, Cipher.ENCRYPT_MODE);
byte[] encrypted = gcmCipher.doFinal(input);
byte[] data = new byte[IV_LENGTH + encrypted.length];
System.arraycopy(initVector, 0, data, 0, IV_LENGTH);
System.arraycopy(encrypted, 0, data, IV_LENGTH, encrypted.length);
return data;
}
private static byte[] generateSecureBytes(int num) {
byte[] bytes = new byte[num];
new SecureRandom().nextBytes(bytes);
return bytes;
}
}
https://www.jianshu.com/p/941aee2a99cf
内容格式比较:
.yml文件,通过:来分层,结构上,有比较明显的层次感,最后key赋值的:后需要留一个空格
.properties文件,通过.来连接,通过=来赋值
2.执行顺序
如果工程中同时存在application.properties文件和 application.yml文件,yml文件会先加载,
后加载的properties文件会覆盖yml文件。所以建议工程中,只使用其中一种类型的文件即可
添加一下注解,该类成为启动类
@SpringBootApplication(exclude = {FlywayAutoConfiguration.class})
@ComponentScan({"com.huawei", "com.huawei.it"})
@MapperScan("com.huawei.onebox.bookmarks.dao")
1 加载配置文件,如 server.xml 文件
2 初始化服务器,创建并配置 Connector、Engine、Host 等对象
3 启动并初始化所有的插件,如 Valve
4 启动所有的应用程序,从配置文件中加载上下文配置和应用程序部署信息
5 启动完成,开始处理客户端请求
https://blog.csdn.net/qq_18769269/article/details/83095012
添加:
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<configuration>
<source>1.8source>
<target>1.8target>
configuration>
plugin>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<executions>
<execution>
<goals>
<goal>repackagegoal>
goals>
execution>
executions>
plugin>
https://blog.csdn.net/zhaozhao121a/article/details/122232333
https://blog.csdn.net/zhaozhao121a/article/details/122232333
https://www.jianshu.com/p/fed7a174bfb8
java -Dservice_authentication_url=http://apicenter-kwe-beta.huawei.com/umws4login/services/Authentication -Dapplication_appId=com.huawei.officeit.2e.bookmark -Dapplication_appName=bookmark -Ddocker_version=1.0 -Ddocker_region=kwe -Ddocker_env=kwe_dev -Dconfigcenter_url=http://appconfig-beta.huawei.com/ConfigCenter/services/ConfigCenterService -Dsub_app_id=ms-bookmarks -Dhwenvironment=uat -Dsgov.secret=20~A2~254A0CB5710D3863BB800DFE16360B163FF83E410804F65F28D09640CCA0FACB~C37F97E155636CB4BF046A416A09FD527AC787066CB42B910C5D06C85F595342142AA1AF94725843291B89DE890CDE93FE7CBB68C7CCBF8AAD8F5F9A423D3C4C768B87F98D03563499393B6E9505A088~DE5990B48C05F4693D0A69FDBC0D581EA4F317C4A16F3AAD0A1BE3C35BB00F47 -Dconfigcenter.config_parts=0e50896c4c27452e88b5c55f7d13fa07,5d548f011f00469da488b8a4589fe219 -Dconfigcenter.work_key_cipher=20~A2~5B5CD51FE5CF7A36C0BC57942F215031E088428F07C25FF204EC9E2393945C66~D42E63F1E6E3D6A85164E0ACA6404814D8491EAD9CF26A586753CE9FDB24C05A91A3C30B9FCDADD36F13DECE05B97EC9~96D856590F128486B3BD81DD40D8C9B8047D8B3EBA53B8824894B0910767B444 -jar ms-bookmarks.jar
HTTP 是短连接,每次请求获取完数据后就断开了,如果有多个用户访问,我们无法区分哪些调用是A用户的,哪些是B用户的,以及之前调用过什么接口 = http 连接是无状态的
为了解决这个问题,就有了 Token、Session、Cookie 这三个东西。
会话:确认用户状态
https://easydoc.net/a/token-session/
为了区分每个用户,或者说记住他们的状态,我们可以在服务端创建一块空间(创建 Session 对象)
Cookie:客户端存储机制之一
作用是在用户访问网站时,将一些数据存储在本地浏览器中,以便下次访问该网站时能够获取这些数据。
服务器通过HTTP响应头将cookie发送给浏览器,浏览器会将cookie保存在本地
每次请求该网站时,浏览器会自动将相关cookie发送给服务器,以便服务器识别用户身份和存取相关数据(如用户名、购物车、session id)。
cookie仅能存储文本格式数据,且存在安全问题(明文)。因此,开发者需谨慎使用cookie机制来存储敏感信息,如密码。
HTTP响应报文中包含一个Set-Cookie头部字段 = cookie → cookies由服务端产生
Token = 令牌:服务器-side session管理机制,原理类似于cookie
当用户进行登录等操作时,服务器会为用户生成唯一的Token,并将该Token发送给客户端,通常是以Cookie或者HTTP表头的形式发送。
客户端每次请求服务器时,会将该Token发送给服务器,服务器接收到Token后会对其进行验证,如果验证成功,就会认为当前用户已经登录,并且开启一个新的session,继而保存与该session相关的信息(例如用户订单等)。
Token机制相对于cookie机制来说,能够更好地保护用户隐私,并且不存在安全问题
Token 到底长什么样
eyJhbGciOiJIUzI1NiI.eyJzaWduVHMiOjE2MjM3MMwODEwfQ.s_CFOkQSmTLHUKLKJkjsdal
这是一段经过加密后的 Token,里面包含了 userid 等信息(可以自定义需要包含的数据)
cookie不能加密,是明文
token可以加密
Cookie:存储用户身份认证信息、用户偏好设置、购物车等临时性数据、跟踪用户行为和统计分析相关的信息
获取 cookies:
http = HyperText Transfer Protocol 超文本传输协议
https = Hyper Text Transfer Protocol Secure 超文本传输安全协议
采用SSL(Secure Sockets Layer) 或 TLS(Transport Layer Security)协议 来加密HTTP传输的数据
SSL证书:在Web服务器 客户端浏览器之间建立加密链接的数字证书
RASP = Runtime Application Self Protection 应用运行时防护服务
通过模拟攻击 来测试Web应用程序的安全性,并提供详细的报告和建议
Rasp可以检测常见的Web应用程序漏洞,如SQL注入、跨站点脚本攻击(XSS)、跨站点请求伪造(CSRF)
CSRF = Cross-Site Request Forgery)
是一种网络攻击方式,攻击者通过伪造用户的请求,让用户在不知情的情况下执行恶意操作
防止CSRF攻击的办法:
1 验证请求来源:在服务器端对请求来源进行验证,只接受来自合法来源的请求
2. 添加随机令牌:在每个表单中添加一个随机生成的令牌,每次提交表单时都要验证该令牌的有效性
3. 使用验证码:在关键操作前,要求用户输入验证码,以确保用户是真实的
4. 限制敏感操作:修改密码、删除数据等,要求用户进行二次确认
,以避免误操作
5. 及时更新软件
https://blog.csdn.net/qq_40893824/article/details/133092514
https://blog.csdn.net/qq_40893824/article/details/128632652
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.7.7version>
<relativePath/>
parent>
<groupId>com.examplegroupId>
<artifactId>demo1artifactId>
<version>0.0.1version>
<name>demo1name>
<packaging>jarpackaging>
https://blog.csdn.net/weixin_43671437/article/details/102736236
cmd 进入jar所在目录
java -jar jar包名
jar 文件路径 会找不到内部的相对路径
把jar当做一个文件,把txt文件和jar包放在同一目录里面
File file = new File("./data.xls");
即可
https://www.huoban.com/news/post/5151.html
:wq
:保存退出
:wq!
:强制保存退出
:x
:保存退出
:q
:vim中表示退出
:q!
:强制不保存退出,不对文件进行保存
https://cloud.tencent.com/developer/article/1579977
cpu参数 4C8T8G
4C = 4核 core
8T = 8线程
8G = 内存
https://cloud.tencent.com/developer/article/2148508
bs:Browser/Server(浏览器/服务器)
cs:Client/Server(客户机/服务器)
https://juejin.cn/post/7035957114396753951
https://zhuanlan.zhihu.com/p/34943332
https://blog.csdn.net/qq_32727095/article/details/127700111
https://blog.csdn.net/qq_27924553/article/details/122415184
https://www.woshipm.com/pmd/3631262.html
统一沟通 (Unified Communications = UC)
http://ee.mweda.com/ask/279107.html
https://www.microsoft.com/zh-cn/microsoft-365/skype-for-business/server-hybrid
后门程序:指绕过安全性控制 而获取对程序或系统访问权的程序方法。
在软件的开发阶段,程序员常常会在软件内创建后门程序
后门程序 可以修改程序设计中的缺陷。
但是,如果这些后门被其他人知道,或 在发布软件之前没有删除后门程序,那么它就成了安全风险,容易被黑客当成漏洞进行攻击
例子:
我写了一个数据迁移公共的web项目,通过postman调用接口,启动数据迁移的功能,这就是后门程序
解决办法:jar 包启动
https://www.zhihu.com/question/22129281
包图 - 基本架构组织,分层
类图 - 核心对象、接口,依赖关系
交互图 = 顺序图 - 执行流程,消息走向,调用关系
活动图(加强版流程图) - 核心算法,任务流程
状态图
https://www.google.com.hk/search?client=aff-cs-360se&ie=UTF-8&q=%E6%B3%A8%E5%85%A5%E6%94%BB%E5%87%BB&oq=%E6%B3%A8%E5%85%A5%E6%94%BB%E5%87%BB&aqs=chrome…69i57l4.1236j0j1
https://zhuanlan.zhihu.com/p/409379105
https://help.aliyun.com/document_detail/42216.html
加密算法得到的一个密钥对:1个公钥、1个私钥(世界范围内唯一)
用其中一个密钥加密一段数据,只能使用密钥对中的另一个密钥才能解密数据
公钥可对会话进行加密、验证数字签名
只有使用对应的私钥才能解密会话数据
公钥是密钥对外公开的部分
私钥是非公开
SSL证书采用公钥体制
密钥仅为本人所有,可以产生其他人无法生成的加密文件,也就是形成了数字签名
SSL证书是一个经证书授权中心(CA)数字签名的、包含公开密钥拥有者信息、公开密钥的文件
签名算法
系统鉴权
企业鉴权
应用鉴权
应用账户鉴权
用户token鉴权
外链用户鉴权
https://blog.csdn.net/u011583927/article/details/80905740
https://blog.51cto.com/u_12295205/3161360
横向越权:攻击者尝试访问与他拥有相同权限的用户的资源
纵向越权:低级别攻击者尝试访问高级别用户的资源
RPC协议 远程过程调用(Remote Procedure Call)
它使得在不同计算机上的程序之间可以像调用本地函数一样调用远程函数,程序员可以编写像本地函数一样简单的代码,并且不需要了解底层网络传输的细节。
RPC协议通常使用TCP/IP或UDP协议进行数据传输
现代化互联网公司业务逐渐扩大,服务逐渐细分,很多服务之间需要通过远程分布式接口调用通讯,
不同的服务不是部署在同一个服务器上,比如订单服务在 A 服务上,付款服务在另一个服务上,有同步调用、也有异步调用,这个时候我们就需要远程调用不同的服务,使用的时候调用远程服务就像调用本地服务一样,引入一个 jar 包,就能通过 this.xxx() 一样调用远程服务,这背后的机制就是通过 RPC 技术
好文:
https://blog.csdn.net/qq_34272760/article/details/120734068
SQL注入、XSS(跨站脚本攻击)
注入攻击的本质,把用户输入的数据当做代码执行。
这里有2个关键条件,
第1个是用户能够控制输入;
第2个是原本程序要执行的代码,拼接了用户输入的数据。
解决注入攻击的核心思想:数据与代码分离
https://juejin.cn/post/7033780851053690894
是web代理拦截工具
https://t0data.gitbooks.io/burpsuite/content/chapter8.html
https://blog.csdn.net/qq_40893824/article/details/106441068#253__443
网址后面加上 #xxxx(id)