项目中常用技术点
Nginx
-
反向代理
#反向代理
server {
#监听端口
listen 90;
location /{
#跨域问题
add_header 'Access-Control-Allow-Origin' '$http_origin';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'POST, GET, OPTIONS, DELETE, PUT';
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
#跨域OPTIONS请求,set response header后直接204返回
if ($request_method = 'OPTIONS') {
return 204;
}
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#代理的地址(此处代理的是负载均衡的两个地址)
proxy_pass http://test;
}
}-
负载均衡
-
轮询(默认)
-
权重自己设置(weight)
-
ip_hash(访问ip跟服务器绑定)
-
#负载均衡
upstream test {
#权重数字越大接收请求越多
server localhost:8081 weight=9;
#ip_hash
ip_hash
server localhost:8082;
} -
-
静态服务器搭建
server {
#监听端口
listen 8888;
location / {
#本地存放的位置
root E:/static_server/img;
autoindex on;
}
}
-
静态资源的部署
将前端打包部署到html文件夹下
redis查询时是一个单线程的,持久化时,开启的时多线程。多线程中有3种方案:同步阻塞IO、同步非阻塞IO、异步非阻塞IO
redis集群搭建 1.主从同步:一主一从 数据一致(高可用) 2.主从分离:一主两从 数据存在不同redis中 3.集群搭建:3主3从:使用哨兵模式,进行主节点选举
Redis五种数据存储类型
Sting(字符串)
Hash(对象)
List(可重复集合)
Set(无序、不可重复)
Zset(有序、去重)
-
导包
-
配置
#端口号
Spring.redis.prot=6379
#服务器
Spring.redis.host=
-
使用
-
缓存同步
当数据库修改后怎么同步redis
1.修改数据库时首先判断redis中是否有该值对应的key如果有的直接删除key
2.修改数据库时同时修改redis中的数据
-
缓存穿透
当用户使用数据库不存在的key进行访问时,会穿过redis直接访问数据库
1.给这个key设置null值 并设置定时
-
缓存击穿
当redis中的key被高并发请求访问时 该key突然失效 请求会全部访问到数据库 造成数据库压力增大
1.可以设置key永不失效
-
缓存雪崩
和缓存击穿相差不大 雪崩是大量key失效
1.设置加长失效时间
2.避免缓存同一时间失效
-
redis持久化
-
AOF
持续的日志添加,操作一次redis就会记录一次日志
-
RDB
快照,每30秒,对当前redis中的内存进行保存记录到磁盘中
-
支付宝支付
-
导包
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.22.57.ALL</version>
</dependency>
-
配置
alipay:
#支付宝appid
appid: 2021000119603005
#公钥
publickey: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhj/8JJXO9tXArnzvUr2gqSqO+o4pnGeZUumhnsbF5gl8dwp6MlxpZO2VHwhnzte/lQXH8hsGS8WotUypbaqaks7S6GHmMgcoseTeq8kPbAIu8SCmlO/tPG8XCGWWqcr2IKuFUdzLgx9UDphtbLCFr6Pm76N2OTHFMcsvJHyBY+GEQbnP050mmH+39ft19F49vWzC7BAzlHWI4g2+KNgPCBlrgrhbcd1ydofJEIAj7UGvV8DwtlIg27Dmw58F4NW3CDtDIAsqT1TPIiFSjNo+VTrXE4IMSZm7a/oZIXdB8rKrXh7O1zd7zmfFeVhwftCqJ/MeDX0/0750ckmX5bTmNQIDAQAB
#私钥
securitykey: MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCGP/wklc721cCufO9SvaCpKo76jimcZ5lS6aGexsXmCXx3CnoyXGlk7ZUfCGfO17+VBcfyGwZLxai1TKltqpqSztLoYeYyByix5N6ryQ9sAi7xIKaU7+08bxcIZZapyvYgq4VR3MuDH1QOmG1ssIWvo+bvo3Y5McUxyy8kfIFj4YRBuc/TnSaYf7f1+3X0Xj29bMLsEDOUdYjiDb4o2A8IGWuCuFtx3XJ2h8kQgCPtQa9XwPC2UiDbsObDnwXg1bcIO0MgCypPVM8iIVKM2j5VOtcTggxJmbtr+hkhd0HysqteHs7XN3vOZ8V5WHB+0Kon8x4NfT/TvnRySZfltOY1AgMBAAECggEAU1kGQfCAPd8XcT0/mC8CwAQcIJKCYwguuLs0DE98LgVVsNJga0PUa0TVgB7H1DM+Tlb4e+crUX+17llaFywEK4EckAm30PeA3HErjZuWZ4gzfKC4y17p+ss9kYkAsQnBJSdX7isWbqHUnfskdIZjeVhY2A60J24u72smKZDjBA7naVUZ5jo+X6N1IsjuBisQCuiBH5OyG3KlTae5F+eU2x/xkC4I5NadzdgkEmt6CoaBsU1bLrmn8ygnJeA5tt/ef8YBFWcSXDFSaCzpaNvuWCVXFe4RsQ+VkkfEhDQrdZdK62O+t62OSw6gJMGmnVCD12IlIhM4H2ewL14t0q3lQQKBgQDO36rNFzVWynXhQXyS1RCTXqoyZmU3lHPAIlauvabLaqvCs4BmXnhElds6wzzsM0gMnArFjzjOMKy5dcJrPKtk2yLt4KlNaCpYXFz50+j3VMV1f6D4nLYX8cFhi83dexPjhoIRqZ00IwcReQyQ4kLs0IjRi5aHrYG2GEOpOYrRHwKBgQCmIVnJfCcnUwKPfj9cO27ynNGW0DuiaRMx8hFrB4bAhwy8iima9Zm2J5uhqhTutDvMdifYbYlTMQFk4rQ9E1f9neqGAAKurPTRAy3WUgaS4VQqVyTHX8TkmSS987tqCxUQGvfHxvG5K1jHz8NLoqZLoxSNHCxrHxdMJjBuneV6KwKBgBm/kwW11si3qFZiDTxFUqvVA4AEaKKzUnjejUVwi3sUCs7QArI7HeMDd+bneAS6GUSgg2K1gc+AFW977bflNDv4Xm+XH9tnlKWs0VGzA3MNVQpb2VA4SR3P1E7s1LG1aPNPwY6rOsrLdUzCcULzNns9NVpHcnPur49Xk8xTQijnAoGBAJiDQ49yV+uFDHO5PeepdFhsWQkwD58xAXs3tH/if/XdxXaNDFcDI+MTB5BpuR/O/Jre2gOZw5lJAvOgIEF1sbDWOYhdGBlOFM6RMZJw6TIMhJz+NXiHVhVa9l0gFazrkaGgcFrKK/2HatC8zphwMGR9yY8mDy0kdNnmsU3LzPDTAoGAVi37NXztwq+orACzS9tVvGExRCeMHZW/2Y8uUZMtz153vMWFOO5NcQpDXpvROBHKoCRJxDTeV5g2ZTwqrC4CUNqX0IMjW/agX/B0SqSqBtplR72VOOd+Q9fSip4imAnKlmYBJTodbYn6Xl8p7/C95QR9aBr4HwAhlbsVDS9FUpo=
#支付宝公钥
alipaypublickey: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAh71b3Xa142+fdvEZL6klvehRuV8Tj1q6nzKI90XafhkCb0pCq/Lxj8UBchsglaDgfKp/MGe4gUZahUQYs6NZCcCkf/CL0uN87u85OebVW/J0UNSUroXNzqsLKchPTLCzsdC+NQL7D4BAljDNDdq14DFbR5oOpsKrY6SJz8zsVQG9/mC620Pq0Gj0bW3+lgh6y4HQnFIPwLQ2wzNIUtjBFiNBWa3IjgOXPGQHqNHcnPk95d9m5hZxK900tCB9T6ll7SgEnltNVLYZORYCHVJ74yyHv/FyhRrvPXcs3xVQLqBBpvsxrt9oc+mJf2VqeDB+foY+0F/tOg29Mgd6zSDPpQIDAQAB
#异步回调的地址,后端接口的地址
notifyUrl: http://pc38k4.natappfree.cc/pay/callback
#同步回调的地址,前端页面的地址
returnUrl: http://localhost:8081/#/orderinfo
#支付宝网关
serverUrl: https://openapi.alipaydev.com/gateway.do
-
使用(工具类)
流程:1.将订单传入支付(pay)方法 同时修改订单状态为正在支付
2.在回调函数中执行验签(callback)方法,验签完毕执行逻辑将订单状态修改为已支付
//将订单传入支付
//从配置文件中获取值
@Value("${alipay.appid}")
private String appid;
@Value("${alipay.publickey}")
private String publickey;
@Value("${alipay.securitykey}")
private String securitykey;
@Value("${alipay.alipaypublickey}")
private String alipaypublickey;
@Value("${alipay.notifyUrl}")
private String notifyUrl;
@Value("${alipay.returnUrl}")
private String returnUrl;
@Value("${alipay.serverUrl}")
private String serverUrl;
private static Logger logger = LoggerFactory.getLogger(AlipayUtils.class);
public String pay(QfOrder order){
AlipayClient alipayClient = new DefaultAlipayClient( serverUrl , appid, securitykey, "json", " utf-8", alipaypublickey, "RSA2"); //获得初始化的AlipayClient
AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest(); //创建API对应的request
alipayRequest.setReturnUrl( returnUrl );
alipayRequest.setNotifyUrl( notifyUrl ); //在公共参数中设置回跳和通知地址
JSONObject jsonObject = new JSONObject();
jsonObject.put("out_trade_no",order.getOrderid());
jsonObject.put("product_code","FAST_INSTANT_TRADE_PAY");
jsonObject.put("total_amount",order.getOrderPay());
jsonObject.put("subject","课程购买!");
jsonObject.put("body","课程购买!");
alipayRequest.setBizContent(jsonObject.toJSONString()); //填充业务参数
String form= "" ;
try {
form = alipayClient.pageExecute(alipayRequest).getBody(); //调用SDK生成表单
} catch (AlipayApiException e) {
e.printStackTrace();
}
return form;
}
//验签操作
public Map callBack(HttpServletRequest request){
Map map = verfiryCallbackReq(request);
logger.debug("进入了支付宝的验签:参数为{}"+map);
try {
boolean signVerified = AlipaySignature.rsaCheckV1(map, alipaypublickey, "utf-8", "RSA2");
logger.debug("进入了支付宝的验签结果为:"+signVerified);
if (signVerified){
return map;
}else{
return null;
}
} catch (AlipayApiException e) {
e.printStackTrace();
}
return null;
}
//
public Map verfiryCallbackReq(HttpServletRequest request){
Map<String, String> retMap = new HashMap<String, String>();
Set<Map.Entry<String, String[]>> entrySet = request.getParameterMap().entrySet();
for (Map.Entry<String, String[]> entry : entrySet) {
String name = entry.getKey();
String[] values = entry.getValue();
int valLen = values.length;
if (valLen == 1) {
retMap.put(name, values[0]);
} else if (valLen > 1) {
StringBuilder sb = new StringBuilder();
for (String val : values) {
sb.append(",").append(val);
}
retMap.put(name, sb.toString().substring(1));
} else {
retMap.put(name, "");
}
}
return retMap;
}
MyBatis分页插件
1.导包
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.3.0</version>
</dependency>
2.使用
//page页数 size每页大小
PageHelper.startPage(page,size);
进行数据库查询得到结果
PageInfo.of(查询结果)
JWT使用
-
导包
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.19.1</version>
</dependency>
-
使用
//获得令牌
//map中存储的是用户信息
public String signToken(Map map){
//1.声明 算法以及 密钥
Algorithm algorithm = Algorithm.HMAC256(securt);
//2.声明头部信息
Map headMap = new HashMap<>();
headMap.put("typ","JWT");
headMap.put("alg","HS256");
//3.创建token 载荷信息
String token = JWT.create().withHeader(headMap)
//1.签发人
.withIssuer("gzs")
//2.主题
.withSubject("login")
//3.受众
.withAudience("users")
//自定义载荷
.withClaim("name", map.get("name").toString())
.withClaim("id",map.get("id").toString())
.sign(algorithm);
return token;
}
//解密将令牌传入返回不等于0解密成功
public Integer verfiy(String token){
try {
//1.声明算法
Algorithm algorithm = Algorithm.HMAC256(securt);
//声明解密对象
JWTVerifier jwtVerifier = JWT.require(algorithm).withIssuer("gzs").build();
//使用解密对象对token进行解密
DecodedJWT verify = jwtVerifier.verify(token);
String id = verify.getClaim("id").asString();
return Integer.valueOf(id);
}catch (Exception e){
System.out.println(e.getMessage());
return 0;
}
}
拦截器
实现HandlerInterceptor(局部拦截)
实现WebMvcConfigurer(全局拦截 针对跨域)
HandlerInterceptor
preHandle
调用controller之前 一般用来拦截未登录用户
postHandle
调用方法视图渲染前
afterCompletion
视图渲染后
WebMvcConfigurer
addInterceptors
设置拦截放行
public void addInterceptors(InterceptorRegistry registry) {
//拦截所有/** 放行/user/**
registry.addInterceptor(myInterceptor).addPathPatterns("/**")
.excludePathPatterns("/user/**","/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**")
.excludePathPatterns("/pay/callback");
}
addCorsMappings
配置全局跨域
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowCredentials(true).allowedOrigins("http://localhost:8080").allowedMethods("GET","POST");
}
Linux部署
-
docker安装
-
docke 运行数据库
docker run -d -p 3306:3306 --name mysql -e MYSQL_ROOT_PASSWORD=密码 数据库标识
-
连接数据库 将本地数据库内容导入云数据库
-
修改本地端口为云服务器端口
-
打包上传项目
-
使用nohup启动
nohup java -jar 项目包 &
查看日志 tail -f nohup.out
-
可以使用nginx代理
首先在/opt/nginx下建html conf包
映射到docker中
前端放入nginx中html
在conf中 配置nginx中的代理
启动nginx并映射
docker run -d -p 8000:8000 -p 9000:9000 --name nginx -v /opt/nginx/html:/usr/share/nginx/html -v /opt/nginx/conf:/etc/nginx/conf.d fa5269854a5e
Aop实现
@Aspect类上加注解表示切面类
//定义切面方法
使用@Pointcut()定义路径
第一个*表示返回值 剩下表示路径
@Pointcut(value = "execution(* *.*.*.*.impl.*.*(..))")
public void pt1(){
}
//在方法上加
@Around(value = "pt1()")
@Component
@Aspect
public class LoggerAop {
private Logger logger = LoggerFactory.getLogger(LoggerAop.class);
/**
* 定义切点
* 第一个*返回值
* *.*.*.*.impl.*.*(..)表示路径到方法参数
*/
/**
* 1.定义切面类@Aspect
* 2.定义切点方法使用@Pointcut()注解 切点就是日志的使用域
* 3.定义日志使用方式@Around(value="切点")
* 4.在定义的方法中传参ProceedingJoinPoint 通过getSignature获取执行的方法 通过getArgs获取方法的参数
*/
@Pointcut(value = "execution(* *.*.*.*.impl.*.*(..))")
public void pt1(){
}
@Around(value = "pt1()")
public Object around(ProceedingJoinPoint proceedingJoinPoint){
logger.debug("进入");
//获取执行方法
MethodSignature signature = (MethodSignature)proceedingJoinPoint.getSignature();
//获得参数
Object[] args = proceedingJoinPoint.getArgs();
Date date = new Date();
String s = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date);
logger.debug("进入时间:"+s);
logger.debug("进入执行的方法:"+signature.getMethod());
logger.debug("当前参数:"+ Arrays.toString(args));
Object proceed = null;
try {
proceed = proceedingJoinPoint.proceed();
logger.debug("返回的参数:"+signature.getReturnType());
return proceed;
}catch (Throwable e) {
e.printStackTrace();
logger.error("方法:"+signature.getMethod()+"发生异常:"+e.getMessage());
}finally {
return proceed;
}
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理