HTTP有哪些请求方式?

  • PUT:将数据存储在服务器,覆盖指定URL,常用于更新资源
  • GET:从服务器获取数据,GET请求是幂等的,即多次请求相同的URL会返回相同的结果
  • POST:向服务器提交数据,通常用于向服务器发送数据,比如提交表单
  • DELETE:从服务器删除指定的URL资源。
  • HEAD:类似于GET请求,但服务器只返回头部信息,不返回实际数据。主要用于检查资源的元数据,例如确认资源是否存在或最后修改日期等。
  • OPTIONS:获取目标URL支持的请求方法信息。用于查询服务器支持哪些HTTP方法。
  • PATCH:用于对资源进行局部更新,更新指定的字段而不是像PUT一样更新整个资源。
  • TRACE:用于目标服务器上执行一个消息环回测试,主要用于诊断。
  • CONNECT:用于代理服务器请求,通常用于建立代理服务器的隧道。

POST和GET的使用场景及区别?

POST主要用于客户端向服务端提交数据的时候使用,GET主要用于客户端向服务端获取请求的时候使用。

POST和GET实际上没有什么区别,如果硬要说有区别可见如下:

  • GET方法产生一个数据包,POST方法产生两个数据包。
    • GET方法会将header和data一并发给服务器,服务器响应200。
    • POST方法会先发送header给服务器,等服务器返回100之后发送data给服务器,然后服务器响应200。此方法在网络差的情况下,会稍微好一点,因为分两次发可能丢包率会小一些。(POST请求,数据包Firefox只会发一次)
  • GET请求URL传递的参数会有长度限制,POST没有
  • GET请求传递参数放在URL中,POST放在Body部分
  • GET请求只接受ASCII字符,POST无限制
  • GET请求比POST更不安全,因为参数会外漏在URL,所以不能传递敏感信息。

Token在HTTP请求的时候会放在什么位置?

一般存在header里面的Authorization字段,Java获取的此字段信息的代码一般如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
// 获取Authorization头的值
String authorizationHeader = request.getHeader("Authorization");
System.out.println(authorizationHeader);

response.getWriter().write("Hello World!");
}
}

GET请求的时候URL有长度限制?是HTTP本身限制了这个URL长度吗?怎么去解决URL超长的问题?

  1. 有长度限制。
  2. 不是HTTP本身限制了这个URL长度,一般是指定的浏览器或者服务器对它进行了长度的限制,超过一定的限制,服务器可能会直接返回错误或者截断URL,发生错误的请求。
  3. 解决URL超长问题方法如下:
    1. 采取POST请求,因为POST请求对数据传输的长度没有限制
    2. 分割请求,如果传输的数据量很大,可以分割成很多小的请求分批次进行数据发送,然后服务端进行整合。
    3. 避免GET请求传输大量的数据。
    4. 压缩URL参数:通过将GET请求的URL参数进行压缩,转换成Base64来压缩参数,减少URL长度。

介绍一下对Spring的理解

是一款开源的轻量级开发框架,是多个模块的集合,比如:Spring IOC、Spring AOP等。

  1. SpringIOC(DI)
  2. SpringAOP
  3. 可以整合其他技术开发

Spring、SpringMVC、SpringleBoot的区别

  • Spring的核心模块就是Spring-Core(主要负责SpringIOC容器的依赖注入的支持),Spring其他所有功能都依赖此模块(包括SpringMVC)。
  • SpringMVC是Spring中得一个模块,主要赋予Spring快速构建MVC架构的Web程序能力,MVC(Model、View、Controller),其核心思想就是将业务逻辑、数据处理、视图显示分离来组织代码。
  • SpringBoot只是简化了配置,减少配置文件(比如xml文件、Java显示配置,开箱即用)

解释一下SpringIOC、SpringAOP

Spring IOCinversion of control控制反转****)

是一种设计思想,其思想就是把原本在程序创建对象的控制权,统一交给SpringIOC容器去管理,控制:创建对象实例的权利,反转:控制权交给Spring框架、IOC容器去管理。

有了SpringIOC之后,我们只需要直接从容器中获取对象即可,而对象的创建是交给SpringIOC容器去创建管理的。

实现方式:

1、从配置元数据获取DI的业务POJO(配置元数据:xml、Configuration、注解等)

2、将业务POJO形成BeanDefinition注入到Spring Container中

3、使用方通过AppllicationContext从SpringContainer中获取即可

Spring AOP(Aspect Object Programming,面向切面编程

就是把公共逻辑抽出来,让开发者更加专注于业务逻辑开发。AOP是一种设计思想,是OOP的补充,OOP是面向类和对象的,但是AOP是面向不同切面的,一个切面可以横跨多个类和对象去操作,极大的提高了开发效率。

比如一个订单的创建,大致流程是:

1、权限校验

2、事务管理

3、创建订单

4、日志管理

使用AOP思想就可以把这四个步骤当作四个切面,让开发者专注于第三个切面,其他三个切面则使用基础的通用逻辑统一交给AOP封装管理。

SpringAOP是如何实现的?

AOP实现原理:

AOP实现有两种方式,一种是Java原生的动态代理,一种是基于cglib的动态代理。默认的一般是原生的JDK的动态代理,但是这种代理方式无法代理没有接口的类,此时就会使用cglib代理这个没有接口实现的类。

Sql注入攻击是什么?SQL注入是怎么产生的?

SQL注入攻击****:针对使用SQL进行数据查询和操作的应用程序,基本原理是通过在用户输入的数据中插入恶意的SQL代码,从而让应用程序执行未经授权的数据库操作或者或者泄露敏感信息。

比如SQL = select * from user where username = ‘#{username}’ and password = ‘#{password}’,攻击者在用户名框或者密码输入框中输入恶意的SQL代码:' OR 1 = 1 -- 就会变成select * from user where username = '' or 1 = 1 --'and password='' ,此时-- ' and password = '' 已经被注释掉了实际上就是select * from user where username = '' or 1 = 1; 此时就会将所有用户的数据信息全部返回给前端。

SQL注入的产生

1、参数未校验,用户不正确的输入

2、特殊字符未转义,例如:=、–这种类型的符号

什么时候需要创建索引?

  • 字段具有唯一性限制
  • 经常用于where子句查询的字段
  • 经常用于group by 和 order by查询的字段

为什么索引如果重复度比较高的时候会对数据库产生一定的压力?

  • 导致页分裂,占用物理空间大:每次数据更新的话,会导致索引进行重新排序,甚至造成页分裂的问题,导致索引查询效率下降,也会在一定程度上造成空间不必要的浪费。
  • 维护成本高:索引重复度比较高也会导致索引字段大小很大,维护空间和时间成本就会变大,占用一定的冗余物理空间
  • 查询效率低:索引重复度比较高可能会匹配到多个符合条件的索引项,进而增加查询的开销,导致查询效率下降。
  • 内存消耗大:如果是5.7的版本,由于MySQL的索引缓存存在的原因,索引重复度高,索引大小也会变大,需要更多的内存去存储这些数据,高内存可能会导致服务器崩溃。

创建联合索引失效的情况

当where子句查询或者order by或者group by查询的时候没有遵循最左匹配原则则会导致查询时联合索引部分失效。

比如:创建索引(a,b,c),此时select * from user where a = 1 and b = 1 and c = 1;此时均用到了联合索引。

若改成select * from user where a = 1 and b > 1 and c = 1;此时用到了索引的只有a,b,因为索引查询是先对a进行排序,在a相等的情况下,对b再进行排序,最后在b相同的情况下对c进行排序,此时因为b > 1无法直接定位到从哪个索引列开始顺序查询,也就是说对c再进行排序的话无法进一步提高查询速率,所以只有a,b用到了联合索引。

一条查询语句的顺序是from -> where -> group by -> Having -> select -> order by

如果有一个联合索引(a,b,c),如果where子句查询只有a = 1 and c = 1,能不能实现走(a,b,c)这个索引查询?

1、如果能够修改a,b,c联合索引的顺序的话,就可以实现,比如改成(a,c,b) 因为联合索引遵循最左匹配原则,即先对a排序,在a相同的情况下,对c排序,在c相同的情况下再对b进行排序,最终形成索引B+树。

2、如果不可以修改联合索引的顺序,那么将无法实现走a,b,c形成的联合索引查询,此时只有a = 1能走到联合索引。

目前有一个人员表,有姓名,年龄,性别字段,要求统计不同年龄下不同性别的人数?统计不同年龄下的人数?

1
2
select age , sex , count(*) from user group by age , sex;
select age , count(*) from user group by age;

有两个集合List如何快速找出相同的元素?

思路大致如下:

  1. 创建并初始化两个List类型的链表
  2. 将两个List类型的列表转换成HashSet类型
  3. 使用HashSet自带的取交集方法set1.retainAll(set2) ,此时set1中保存的就是原set1和set2的交集,即两个集合相同的元素。

代码实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import java.util.*;

public class FindCommonElements {
public static void main(String[] args) {
// 示例数据
List<Integer> list1 = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> list2 = Arrays.asList(3, 4, 5, 6, 7);

// 使用HashSet找出相同元素
Set<Integer> set1 = new HashSet<>(list1);
Set<Integer> set2 = new HashSet<>(list2);

set1.retainAll(set2); // 保留set1中与set2的交集

System.out.println(set1); // 输出:[3, 4, 5]
}
}

数据结构:哈希如何使用?

「哈希表 Hash Table」通过建立键 key 与值 value 之间的映射,实现高效的元素查询。具体而言,我们向哈希表输入一个 key ,则可以在O(1)时间内获取对应的 value

详情见下:

哈希表(Hello算法)

有一个集合Set怎么批量删除部分元素?

实现代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.util.*;

public class RemoveElementsFromSet {
public static void main(String[] args) {
// 原始Set
Set<Integer> originalSet = new HashSet<>();
originalSet.add(1);
originalSet.add(2);
originalSet.add(3);
originalSet.add(4);
originalSet.add(5);

// 需要删除的元素集合
Set<Integer> elementsToRemove = new HashSet<>();
elementsToRemove.add(3);
elementsToRemove.add(5);

// 批量删除部分元素
originalSet.removeAll(elementsToRemove);

System.out.println(originalSet); // 输出:[1, 2, 4]
}
}

Linux查询一个日志文件的关键字?查询某个关键字的前后500行?

查询日志文件的某个关键字可以使用grep命令实现,例如:grep ‘关键字’ filePath

查询某个关键字的前后500行:grep -AB 500或者 grep -C 500(-C == -AB)

怎么保证MySQL和Redis的一致性问题

读请求:先读缓存,如果缓存失效或不存在就让先获取到互斥锁的线程查数据库并回写缓存,让后续的请求直接都缓存即可

写请求:先更新数据库,再删缓存即可(此时可能会出现删缓存失败的场景,可以通过消息队列的方式,采取重试机制,如果删除缓存失败,则通过消息队列再进行一次删除缓存的操作,如果删除成功,则把消息队列里面的删除缓存操作删除即可,避免重复消费,造成不必要的资源浪费)

价格类型的数据Java用什么存储?

1、BigDecimal(使用String类型的进行转换,才不会导致精度丢失)

2、整数存储(比如:3.14存为314)

3、自定义存储方式,数据库一个字段存整数,一个字段存小数