解决”x packages are looking for funding”

解决npm install安装出现packages are looking for funding run npm fund for details问题

当我们运行npm install时,可能会收到类似以下的提示信息:“x packages are looking for funding.” 这并不是错误提示,也不会影响项目的正常运行。相反,这是提醒您,有一些软件包正在寻求资金支持。

这个提示的目的是让开发者们意识到,许多开源项目的开发是由志愿者进行的,他们投入了大量时间和精力。您可以选择通过为这些项目提供捐款来支持他们。—-(本人使用的这个)

1
npm config set fund false --location=global

如果您只想在特定项目中关闭此提示,请在项目目录中运行以下命令:

1
npm config set fund false 

这样,您就不会再收到有关捐款支持的提示了,但是请记住,支持开源项目的开发者们是非常重要的。


配置Nginx反向代理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
location ^~ /api/ {
proxy_pass http://127.0.0.1:8080/api/;
add_header 'Access-Control-Allow-Origin' $http_origin;
add_header 'Access-Control-Allow-Credentials' 'true';
add_header Access-Control-Allow-Methods 'GET,POST,OPTIONS';
add_header Access-Control-Allow-Headers '*';
if ($request_method = 'OPTIONS'){
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Origin' $http_origin;
add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
}


在Linux系统中查文件命令;

在Unⅸ系统当前的test目录中查找所有以test开头的文件?

1
find test -type f -name 'test*'

如果当前目录在test的父目录

1
ls test/test*



ArrayList和LinkedList的区别:
ArrayList基于动态数组实现,访问速度快,LinkedList基于链表,内存大,批量增删效果好

==和equals的区别:
==比较内存地址,equals比较内存地址的值。



注册逻辑

  1. 前端传入两个参数(账户密码以及校验密码)
  2. 检查是否为空,不为空检查是否符合长度规范,以及不能包含特殊字符,账户是否重复
  3. 密码加密Md5加密,插入数据,返回用户ID

登录逻辑

访问服务端—>登陆成功—>于是在服务器创建==SessionID==(没有规律的字符串)和会话结束时间—>服务器把SessionID 和会话结束时间发送给浏览器-就用到了Cookie—>设置Cookie,并且把SessionID和会话时间存到Cookie里—并且再把会话时间设置为这个Cookie的有效期——(浏览器没有保存账户和密码,保存的是无规律的字符串)


解决缓存不一致性问题:

主要解决方案是==旁路缓存模式==,也就是在更新数据库和删除缓存时,建议呢先更新数据库再删除缓存,避免缓存不一致性问题删除缓存就是减少不一致的概率吧,为什么是删除缓存呢,认为就是一种给懒加载思想,如果数据库在1小时内更新1000次,也要更新1000次缓存的,但1000次中我只请求了一次缓存,那就是没有必要的,反过来说删除缓存只删1次就可以了


String,StringBuider,StringBuffer

类型 特点 适用场景
String 不可变,线程安全 操作少量或==不需要==操作字符串
StringBuider 可变,线程不安全 需要==频繁操作==且不用考虑线程安全
StringBuffer (使用synchronized关键字)可变,安全,性能低 需频繁操作且考虑线程安全


创建线程的方式

1.继承Tread类,实现类,调用start(),重写run方法—缺点:类只能单继承,不能有其他父类

2.实现Runnable接口,接口可以多继承,好处就是没有继承限制,缺点:无法在线程中返回值

3.如果在线程中返回结果的话,实现Callable接口,需要结合FutureTask使用,将类传进来,再实现Tread传入futureTask,call方法可以返回值

HashMap

HashMap内部数组加链表,当数组>=64,链表>=8,就会把链表装换成红黑树提升数据查找性能


SpringMVC常用的注解有哪些?

@RequestMapping:用于处理请求URL映射的注解,用在类上表示所有的响应请求的方法都是以该路径作为父路径

@RequestBody:注解实现接受Http请求的json数据,将json转换为java对象

@ResponseBody:将controller对象返回对象转化为json对象响应给客户

@CrossOrigin:实现跨域请求

谈谈你对AOP的理解

与业务逻辑无关,却为业务模块共同调用的逻辑封装起来,像(事务处理,日式管理,权限控制)减少系统重复代码,降低耦合

Docker部署

Docker是容器,可以将项目的环境和项目的代码一起打包成镜像,所有人可下载镜像,便于分发移植,

在启动项目时,不需要瞧一堆命令,而是直接下载镜像,启动镜像就可以了,可以理解成软件安装包

  1. 用的宝塔,在宝塔 软件商店 下载Docker管理器,界面创建容器
  2. 后端 写DockerFile ,用于构建 Docker 镜像 的方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#引用基础镜像
#打包了maven3.5和JDK8依赖
FROM maven:3.5-jdk-8-alpine as builder

# Copy local code to the container image.
# 指定 镜像的工作目录-指定了app目录
WORKDIR /app
# 复制本地pom文件和源码
COPY pom.xml .
COPY src ./src
#
# Build a release artifact.
RUN mvn package -DskipTests

# Run the web service on container startup.
CMD ["java","-jar","/app/target/yupao-backend-0.0.1-SNAPSHOT.jar","--spring.profiles.active=prod"]
1
2
3
4
5
6
//1. 切换到 root目录
cd /www/wwwroot/
//2.检查git-安装宝塔自动装git-加上sudo命令 因为服务器提供的用户为普通用户
sudo git clone '项目地址'
// 进入目录-列出当前目录中的文件和子目录
ls

根据 Dockerfile 构建镜像

1
docker build -t user-center-backend:v0.0.1 .
  1. 前端 Dockerfile 和 Nginx配置文件

nginx.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
server {
listen 80;

# gzip config
gzip on;
gzip_min_length 1k;
gzip_comp_level 9;
gzip_types text/plain text/css text/javascript application/json application/javascript application/x-javascript application/xml;
gzip_vary on;
gzip_disable "MSIE [1-6]\.";

root /usr/share/nginx/html;
include /etc/nginx/mime.types;

location / {
try_files $uri /index.html;
}

}

Dockerfile:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 搞一个有Nginx的基础镜像
FROM nginx

WORKDIR /usr/share/nginx/html/
USER root
# 把本地Nginx配置 复制到基础镜像配置目录,覆盖掉
COPY ./docker/nginx.conf /etc/nginx/conf.d/default.conf

COPY ./dist /usr/share/nginx/html/

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]

继续Clone代码

1
2
3
4
5
6
7
sudo git clone '前端项目地址'
// 查看当前目录文件
ls
// 切换到user-center-fronted/目录
cd user-center-fronted/
// 再查看目录
ls

根据 Dockerfile 构建镜像:

1
docker build -t user-center-fronted:v0.0.1 .


1
2
# 查看当前机器已经拉取得镜
docker images

从名为user-center-frontend并带有v0.0.1标签的Docker镜像中启动一个新的容器实例,将宿主机的80 /(8080) 端口映射到容器的80/(8080) 端口,并在后台运行这个容器。

  • -t —->构建的镜像命名
  • -p —->用于指定端口映射
1
2
3
4
5
# 前端
docker run -p 80:80 -d user-center-frontend:v0.0.1

# 后端
docker run -p 8080:8080 user-center-backend:v0.0.1
1
2
3
4
# 查看进程(可以查看已经启动的容器ID,没有权限用sudo)
docker ps
# 查看日志 docker logs 容器ID
docker logs 容器ID


通用返回对象和自定义错误码

通用返回对象目的:简化错误处理,因为接口返回的对象类型不一,Long,User类型等

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@Data
public class BaseResponse<T> implements Serializable {
private int code;

private T data;

private String message;

private String description;

public BaseResponse(int code, T data, String message, String description) {
this.code = code;
this.data = data;
this.message = message;
this.description = description;
}
public BaseResponse(int code, T data, String message) {
this(code,data,message,"");
}
public BaseResponse(int code,T data){
this(code,data,"","");
}
public BaseResponse(ErrorCode errorCode){
this(errorCode.getCode(),null,errorCode.getMessage(),errorCode.getDescripton());
}
}

然后把所有的请求都用通用返回对象封装一下

自定义错误码:前端错误码少且不精确,要提供清晰的错误提示,也防止暴露敏感信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public enum ErrorCode {

SUCCESS(0,"OK",""),
PARAMS_ERROR(40000,"请求参数错误",""),
NULL_ERROR(40001,"请求数据为空",""),
NOT_LOGIN(40100,"未登录",""),
NO_AUTH(40101,"暂无权限",""),
FORBIDDEN(40301,"禁止操作",""),
INVALID_PASSWORD_ERROR(40102, "无效密码", ""),
OPERATION_ERROR(50001, "操作失败", "操作失败"),
SYSTEM_ERROR(50000,"系统内部异常","");

private final int code;
//状态码信息
private final String message;
//状态码描述(详情)
private final String descripton;


ErrorCode(int code, String message, String descripton) {
this.code = code;
this.message = message;
this.descripton = descripton;
}

public int getCode() {
return code;
}

public String getMessage() {
return message;
}

public String getDescripton() {
return descripton;
}
}

全局异常处理器:不把服务器内部错误返回给前端

封装全局异常处理

1.定义业务异常类

  1. 相对于java的异常类,支持更多字段
  2. 自定义构造函数,更灵活/快捷的设置字段
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    public class BusinessException extends RuntimeException {

    private final int code;
    private final String description;

    public BusinessException(int code, String description) {
    this.code = code;
    this.description = description;
    }

    public int getCode() {
    return code;
    }

    public String getDescription() {
    return description;
    }

    public BusinessException(ErrorCode errorCode) {
    super(errorCode.getMessage());
    this.code = errorCode.getCode();
    this.description = errorCode.getDescripton();
    }

    public BusinessException(ErrorCode errorCode, String description) {
    super(errorCode.getMessage());
    this.code = errorCode.getCode();
    this.description = description;
    }
    }

2.编写全局异常处理器
作用:

  1. 捕获代码中所有的异常,内部消化,集中处理,让前端得到更详细的业务报错/信息
  2. 同时屏蔽掉项目框架本身的异常(不暴露服务器内部状态)

    @RestControllerAdvice 是 Spring MVC 中的一个注解,用于实现面向切面编程(AOP)中的通知(advice)。它不是一个直接的AOP实现机制,但它确实利用了AOP的思想,即在不修改业务代码的情况下,对Controller层的行为进行增强或全局性的错误处理。

    @RestControllerAdvice 通常用于定义跨切面的控制器异常处理、参数校验、日志记录等通用逻辑,这些逻辑会被应用到所有使用了 @RestController 或 @RequestMapping 的方法上。它的具体实现是通过Spring AOP的@Around或@AfterReturning等通知类型来完成的。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    @Slf4j
    @RestControllerAdvice
    public class GlobalExceptionHandler {
    @ExceptionHandler(BusinessException.class)
    public BaseResponse businessExceptionHandler(BusinessException e){
    log.error("businessException:" + e.getMessage(),e);
    return ResultUtil.error(e.getCode(), e.getMessage(), e.getDescription());
    }

    @ExceptionHandler(RuntimeException.class)
    public BaseResponse runtimeExceptionHandler(BusinessException e){
    log.error("runtimeException",e);
    return ResultUtil.error(ErrorCode.SYSTEM_ERROR,e.getMessage(),"");
    }
    }


索引原理:就是把无序的数据变成有序的查询

MySQL的B树和B+树

B树查询效率不太稳定,有些在 根节点或者在根节点附近能找到 ,搜索起来就很快,如果在叶子节点上,就查询慢,有的快,有的慢,性能不稳定

B+树把数据全部放在了叶子节点上,这样不管查询哪个数据,最终都要走到叶子节点,解决了查询性能不稳定问题,上面的节点不存储数据,腾出来的空间用来存储指向其他节点的指针,中间的节点分叉更多,整个树变得更加扁平,进一步减少IO次数,最后把叶子节点用指针连接起来,解决范围查询问题


编辑距离算法

引入原有算法进行改造(将字符比较-变成tagList标签字符串)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public static int minDistance(List<String> tagList1, List<String> tagList2) {
int n = tagList1.size();
int m = tagList2.size();

if (n * m == 0) {
return n + m;
}

int[][] d = new int[n + 1][m + 1];
for (int i = 0; i < n + 1; i++) {
d[i][0] = i;
}

for (int j = 0; j < m + 1; j++) {
d[0][j] = j;
}

for (int i = 1; i < n + 1; i++) {
for (int j = 1; j < m + 1; j++) {
int left = d[i - 1][j] + 1;
int down = d[i][j - 1] + 1;
int left_down = d[i - 1][j - 1];
if (!Objects.equals(tagList1.get(i - 1), tagList2.get(j - 1))) {
left_down += 1;
}
d[i][j] = Math.min(left, Math.min(down, left_down));
}
}
return d[n][m];
}
目的

是计算用户列表中每个用户登录用户的标签列表之间的相似度或距离,并将这些相似度或距离按照用户索引的顺序存储在一个有序映射中。

然后查询用户列表-并取当前用户标签

1
2
List<User> userList = this.list();
String tags = loginUser.getTags();

使用Google的Gson库来将JSON格式的字符串(在这里是tags)反序列化为Java中的List对象。

1
2
3
4
Gson gson = new Gson();
List<String> tagList = gson.fromJson(tags, new TypeToken<List<String>>() {
}.getType());
System.out.println(tagList);

初始化有序映射:

1
SortedMap<Integer, Long> indexDistanceMap = new TreeMap<>();

遍历用户列表:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
for (int i = 0; i <userList.size(); i++) {
// 首先,从userList中获取索引为i的用户对象,并调用其getTags()方法获取该用户的标签字符串。
User user = userList.get(i);
String userTags = user.getTags();
//无标签的
if (StringUtils.isBlank(userTags)){
continue;
}
List<String> userTagList = gson.fromJson(userTags, new TypeToken<List<String>>() {
}.getType());
//计算相似度(或距离)
long distance = AlgorithmUtils.minDistance(tagList, userTagList);
//将相似度(或距离)存储在映射中:
indexDistanceMap.put(i,distance);
}
// TreeMap是有序的,所以这些键值对将按照键(即用户索引)的升序排序。