首页 > 技术文章 > 猴哥面经

wanjx 2019-05-12 23:00 原文

前台Contrller在用户发起请求时用前台发来的数据接参例如:
1,前台定义的返回值类型是EazyUItable类型,参数是总记录数和当前页的具体数据
2,后台通过接受这几个参数,和返回值类型去数据库查询
3,返回给页面
问题:在查询完商品详情信息后,商品类目显示列为乱码,在jsp页面查找了很多标签的类型都是utf-8,都没错
后来百度了一下在RequsetMapping里加了一个属性
produces: 指定返回值类型,不但可以设置返回值类型还可以设定返回值的字符编码
consumes:指定处理请求的提交内容类型(Content-Type),例如application/json, text/html;

1,在查询时返回值类型为具体的对象,和消息状态值

2,在删除和修改时返回值类型为一个封装的值对象,一个是msg,status,data对象


3,文件上传(MultipartFile uploadFile)(两个工具,getname,transforto上传)
1,获取图片信息
2,对其验证,分文件储存,加密
3,防止重名UUID
4,上传路径用nginux实现反向代理
5,上传
6,前台的url和参数是uploadFile

@PathVariable 是restful风格的注解

单点登录系统
实现redis 的缓存登录
1.用户进行登录操作时,输入用户名和密码.
2. JT-WEB接收用户请求时.将用户信息进行封装对用户密码进行加密,利用httpClient技术,发送给JT-SSO.单点登录系统.
3. JT-SSO单点登录系统,接收前台数据之后进行校验.如果用户名和密码不正确.直接提示返回.
4. 如果用户名和密码正确.首先生成加密的秘钥唯一key:token,之后将user转化为JSON数据.保存到Redis中.之后返回给JT-WEB token数据.
5. JT-WEB接收JT-SSO的返回值数据.把数据转化成对象,从这个对象中获取token数据,如果用户名密码不正确则友好提示给用户.
如果用户名和密码正确,将token数据保存到用户浏览器的Cookie中.
5.返回封装的对象
6.当登录过后,跳转到主页面时,通过Ajax,Jsonp异步请求回显用户登录信息,同过redis获取token,用回调函数返回给页面.

 


日志模块

查看日志,通过url,和参数username和当前页的数据来查询数据库并返回封装的值对象
删除日志根据url和ids

添加日志切面
1,添加一个日志的注解类
2,添加一个日志的切面@around通知
2.1 定义切入点和连接点
2.2 在执行目标方法后执行添加日志的操作
3,添加日志
3.1 用户登录后信息是存在subject中的,从subject中获取用户信息
3.2 用工具类获取用户RequestContextHolder.getRequestAttributes()).getRequest()获取request对象
3.3 根据连接点获取方法签名
3.4 获取类对象,获取目标方法名和参数
3.5 获取目标方法上的注解的属性值(做了什么操作)
3.6 获取执行时长
3.7 设置创建的时长
3.8 把参数封装成对象添加到数据库中

 


1.优化sql语句
1.1 尽可能根据主键查询
1.2 尽可能单表查询,将访问的压力交给tomcat服务器,可以通过集群的方式解决,极大减轻数据库的开销
①选择最有效率的表名顺序
数据库的解析器按照从右到左的顺序处理FROM子句中的表名,FROM子句中写在最后的表将被最先处理
②WHERE子句中的连接顺序
数据库采用自右而左的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其他WHERE条件之左,那些可以过滤掉最大数量记录的条件必须写在WHERE子句的之右。

1.3 如果进行关联查询时,应该提早确定数据,之后关联查询,减少笛卡尔积(关联的次数)

1.4 少用数据库函数 max/min 分组 hive
2.添加索引和视图(续表)
3.添加缓存(Redis/MemCache)
1.1非关系型数据库
1.2读写速度快,10万吞吐每秒
4.定期进行数据转储(将不用的数据,存储到历史表中(银行的流水))
5.可以使用高性能非关系型数据库储存.(redis/hbase),读写速度快
6.分库分表(贵/运维)
2数据库防止数据的丢失?
在archivelog mode(归档模式)只要其归档日志文件不丢失,就可以有效地防止数据丢失。


docker 管理镜像和容器,docker保证数据的一致性,能快速装多个容器

实现秒杀业务
1,在秒杀开始前 把要秒杀商品放入队列中.例如5个商品
2,在redis中设置一个key,设置它的消亡时间.
3,在用户访问时首先先拿到一个key,如果没有拿到就直接友好返回,拿到key的用户把用户id ,push进入到redis list集合中.
4,然后从list集合中pop出第一个用户,访问我们的队列,如果队列中有就取数据,队列中没有就友好返回
5,当用户取出数据,确认订单支付时,我们把确认的数据持久化到数据库中
6,依次执行,当队列中没有数据时,直接友好提示并返回下次再来.

solr实现 SolrClient
比模糊查询速度快
分词器就是IKAnalyzer中文分词器,它有细粒度切分和智能切分,即根据某种智能算法。
luncence实现了倒排索引技术\
普通域查询
复制域查询
动态域查询
分页查询
分组查询
高亮查询
过滤查询
区间查询
排序查询

 

 

 

 

AOP理解

定义切入点
定义通知
在需要添加切面的方法上添加切入点

在执行方法过后添加日志信息
1 获取用户信息
2 获取ip
3 获取方法签名
4 获取目标类
5 获取目标方法上的注解
6 读取注解的属性值
7 获取目标方法,和参数
8 完成日志对象封装
9 返回执行结果

缓存的Aop实现
ReadWriteLockLruCache<CacheKey,Object> cacheMap
=new ReadWriteLockLruCache<>(3);

1,定义一个唯一的key(类名加方法名加参数名)定义一个工具类CacheKey
2,获取到目标类,方法和参数
3,封装到这个工具类CacheKey
4,首先先从这个缓存中获取,如果有就直接返回
5,如果没有就执行目标方法,
6,并将结果放入缓存中

 

shiro理解
它是一个安全矿建,实现用户的认证,授权,加密,会话管理等,使用shiro快速完成认证,授权等开发,降低系统成本
1)Subject(主体):与软件交互的一个特定的实体(用户、第三方服务等)。
2)SecurityManager(安全管理器) :Shiro 的核心,用来协调管理组件工作。
3)Authenticator(认证管理器):负责执行认证操作
4)Authorizer(授权管理器):负责授权检测
5)SessionManager(会话管理):负责创建并管理用户 Session 生命周期,提供一个强有力的 Session 体验。
6)SessionDAO:代表 SessionManager 执行 Session 持久(CRUD)动作,它允许任何存储的数据挂接到 session 管理基础上。
7)CacheManager(缓存管理器):提供创建缓存实例和管理缓存生命周期的功能
8)Cryptography(加密管理器):提供了加密方式的设计及管理。
9)Realms(领域对象):是shiro和你的应用程序安全数据之间的桥梁。

 

cookie清除怎么办
策略1:实现URL重写技术.
例子:http://www.jt.com/cart/addCart?sessionId=XXXXXXX
步骤:
1.生成SessionId
2.将SessionId保存到域中.
3.发起请求时动态获取SessionId进行url拼接.
问题:
1.每次发请求都需要进行数据的拼接.
2.业务层,必须先获取SessionId,之后保存到域中.每个方法都需要添加该操作.
b,如何进行url重写。


encodeURL方法用在链接地址、表单提交地址。

response.encodeURL(String url);

encodeRedirectURL方法用于重定向地址。

response.encodeRedirectURL(String url);

 

 

创建线程的3中方式
1 继承tread

优点 : 编写简单,访问当前线程直接用this即可获得
缺点 : 继承thread 就不能继承其他类

2 实现runable接口

优点 : 可以继承其他类.多个线程可以共享同一个目标
缺点 : 没有返回值,而且不能抛出异常

3 实现callable接口 中的call方法有返回值

优点 : 有返回值,可以抛出异常
缺点 : 使用复杂

list
arrayList
linkedList

 


map
hash

 

 


springBoot常用注解
@SpringBootApplication注解的流程
@Target(ElementType.TYPE) // 注解的适用范围,其中TYPE用于描述类、接口(包括包注解类型)或enum声明
@Retention(RetentionPolicy.RUNTIME) // 注解的生命周期,保留到class文件中(三个生命周期)
@Documented // 表明这个注解应该被javadoc记录
@Inherited // 子类可以继承该注解

以下为重点
@SpringBootConfiguration // 继承了Configuration,表示当前是注解类
@EnableAutoConfiguration // 开启springboot的注解功能,springboot的四大神器之一,其借助@import的帮助
@ComponentScan(excludeFilters = { // 扫描路径设置(具体使用待确认)
@Configuration之后,本身其实也是一个IoC容器的配置类。
@ComponentScan的功能其实就是自动扫描并加载符合条件的组件
@EnableAutoConfiguration也是借助@Import的帮助,将所有符合自动配置条件的bean定义加载到IoC容器,仅此而已!

@SpringBootApplication
@Configuration //配置类
@PropertySource(value="classpath:/properties/redis.properties")
@Value
@Bean
@Component
@JsonIgnoreProperties

@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration

 

 

数据库的添加字段

alter 表 add 字段

 

 

redis理解
首先redis是可以做数据库,缓存和消息队列,key-value结构进行储存.
支持的结构有string,list,hash,set,zset
pexpire 设置key失效时间
redis的事务
Multi:都会开启事务
Exec:提交
Discard 回滚

redis在项目中用到
1,单点登录系统
2,商品类目


redis 拦截器,过滤器 数据库索引 jdk动态代理 微服务的优点和缺点为什么要用

拦截器的执行顺序:

1, 正常情况全部放行
2, 1pre 2pre 2post 1post 2after 1after

3, 非正常 第一个拦截放行,第二个拦截器拦截
1 pre 2 pre 1 after
拦截器1放行,拦截器2 preHandle才会执行。

拦截器2 preHandle不放行,拦截器2 postHandle和afterCompletion不会执行。

只要有一个拦截器不放行,postHandle不会执行。


3, 第一个拦截器拦截,第二个拦截器拦截
拦截器1 preHandle不放行,postHandle和afterCompletion不会执行。

拦截器1 preHandle不放行,拦截器2不执行。


过滤前-拦截前-Action处理-拦截后-过滤后

过滤器和拦截器的区别
过滤器



redis 缓存机制

? ?(1) 速度快,因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1)?
? ?(2) 支持丰富数据类型,支持string,list,set,sorted set,hash?
? ?(3) 支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行?
? ?(4) 丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除


索引
例子
1、如果每次都需要取到所有表记录,无论如何都必须进行全表扫描了,那么是否加索引也没有意义了。
2、对非唯一的字段,例如“性别”这种大量重复值的字段,增加索引也没有什么意义。
3、对于记录比较少的表,增加索引不会带来速度的优化反而浪费了存储空间,
因为索引是需要存储空间的,而且有个致命缺点是对于update/insert/delete的每次执行,
字段的索引都必须重新计算更新。所以并不是任何情况下都改建立索引的


优点

第一, 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。
第二, 可以大大加快数据的检索速度,这也是创建索引的最主要的原因。
第三, 可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。
第四, 在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间。
第五, 通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。

缺点

第一, 创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。
第二, 索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚簇索引,那么需要的空间就会更大。
第三, 当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度。

三、创建方向索引的准则


索引是建立在数据库表中的某些列的上面。因此,在创建索引的时候,应该仔细考虑在哪些列上可以创建索引,在哪些列上不能创建索引。
一般来说,应该在这些列上创建索引。

第一, 在经常需要搜索的列上,可以加快搜索的速度;
第二, 在作为主键的列上,强制该列的唯一性和组织表中数据的排列结构;
第三, 在经常用在连接的列上,这些列主要是一些外键,可以加快连接的速度;
第四, 在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,其指定的范围是连续的;
第五, 在经常需要排序的列上创建索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间;
第六, 在经常使用在WHERE子句中的列上面创建索引,加快条件的判断速度。

同样,对于有些列不应该创建索引。一般来说,不应该创建索引的的这些列具有下列特点:

第一, 对于那些在查询中很少使用或者参考的列不应该创建索引。
这是因为,既然这些列很少使用到,因此有索引或者无索引,并不能提高查询速度。
相反,由于增加了索引,反而降低了系统的维护速度和增大了空间需求。

第二, 对于那些只有很少数据值的列也不应该增加索引。
这是因为,由于这些列的取值很少,例如人事表的性别列,在查询的结果中,
结果集的数据行占了表中数据行的很大比例,即需要在表中搜索的数据行的比例很大。
增加索引,并不能明显加快检索速度。

第三, 对于那些定义为text, image和bit数据类型的列不应该增加索引。
这是因为,这些列的数据量要么相当大,要么取值很少。

第四,当修改性能远远大于检索性能时,不应该创建索引。这是因为,修改性能和检索性能是互相矛盾的。
当增加索引时,会提高检索性能,但是会降低修改性能。当减少 索引时,会提高修改性能,降低检索性能。
因此,当修改性能远远大于检索性能时,不应该创建索引。

 


sleep和wait

从使用角度看,sleep是Thread线程类的方法,而wait是Object顶级类的方法。

sleep可以在任何地方使用,而wait只能在同步方法或者同步块中使用。

CPU及资源锁释放

sleep,wait调用后都会暂停当前线程并让出cpu的执行时间,但不同的是sleep不会释放当前持有的对象的锁资源,
到时间后会继续执行,而wait会放弃所有锁并需要notify/notifyAll后重新获取到对象锁资源后才能继续执行。

异常捕获

sleep需要捕获或者抛出异常,而wait/notify/notifyAll不需要。

 

 


正向代理和反向代理

正向代理是代理的客户端,而服务端不知道是哪个客户端

反向代理是代理的服务端,而客户端不知道是哪个服务器


TimerTask 和 Quartz比较

精确度和功能

Quartz可以通过cron表达式精确到特定时间执行,而TimerTask不能。Quartz拥有TimerTask所有的功能

quartz每次都是新建任务,不影响其他任务 而timer一个任务失败就全部失败

 

TCP/IP:四层模型。

①网络接口层:对应物理层和数据链路层。

②网络层

③传输层

④应用层:包括会话层、表示层、应用层。

(1)OSI:七层模型。


①物理层:在物理信道上实现原始比特流的传输。(以太网,?IEEE 802.2 等)


②数据链路层:实现无差错地将数据帧从一个节点传送到下一个相邻节点。(Wi-Fi(IEEE 802.11) , WiMAX(IEEE 802.16), ?GPRS, HDLC, PPP 等协议)


③网络层:实现将数据分组从源站通过网络传送到目的站,即网络上一台主机与另一台主机之间的数据传输。(IP, ICMP, IGMP, ARP, RARP, OSPF 等协议)


④传输层:实现源端到目的端数据的传输,即某主机的某进程与另一台主机的某进程之间的数据传输。(TCP, UDP 等协议)


⑤会话层:实现在不同机器上用户建立、维护和终止会话关系。即会话层对会话提供控制管理服务、会话同步服务等。(ZIP, ASP, SSH 等协议)


⑥表示层:确保各种通信设备能够互相操作,不及考虑其数据的内部表示。即确保即使各种通信设备其数据的内部表示不同,但仍然能相互正确操作。(SSL等协议)


⑦应用层:使用户能够访问网络,为各类应用提供相应的服务、提供各种用户接口支持服务。应用层不是应用程序,应用层是一个为应用程序提供各类应用支持的服务层。(HTTP, FTP, SMTP, POP3, DHCP, DNS等协议)

htto请求到响应的过程

1. 域名解析
2. 发起TCP的3次握手
3. 建立TCP连接后发起http请求
4. 服务器端响应http请求,浏览器得到html代码
5. 浏览器解析html代码,并请求html代码中的资源
6. 浏览器对页面进行渲染呈现给用户

 

 


Eureka 如果不加安全控制,会存在下列问题:

Eureka 控制台可以看到各服务的状态和参数等信息,如果不加控制,只要知道注册中心的地址,就可以登录上去看到各服务信息;
只要知道注册中心地址,服务提供者就可以注册上来,对外提供服务;
只要知道注册中心地址,服务消费者就可以发现注册中心的服务,并调用服务;
为了安全起见,我们还是为 Eureka 增加安全控制,这里用 Spring Security 实现最基础的用户名、密码控制。

一个小知识点而已,几个配置就可以完成。

1. maven 包引用

在服务注册中心项目的 pom.xml 文件中引入 Spring Security 包。

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
2.增加应用配置

在应用配置文件中增加关于 security 的配置,一般是放在 application.yml ,但是本项目中分了 application.yml 和 bootstrap.yml 两个配置文件,所以我这里是放在了 application.yml 中。

spring:
application:
name: kite-eureka-center
security:
user:
name: test # 用户名
password: 123456 # 密码
此时,启动并访问 Eureka 管理控制台,会提示输入用户名和密码,输入上面的 name 和 password 即可。

3.服务提供者注册服务

在服务提供者的应用配置文件中做以下修改即可

eureka:
instance:
statusPageUrlPath: /actuator/info
healthCheckUrlPath: /actuator/health
prefer-ip-address: true
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://test:123456@localhost:3000/eureka/
上述配置与没有安全控制的时候唯一的差别就是在 defaultZone 指定的 eureka 地址。在地址中增加了用户名和密码。

推荐阅读