Base64与文件互转

Base64与文件互转

import java.io.*;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;




 public class Base64Utils {


     /**
      * @Description :  文件与base64的互相转换操作
      * @Author : mabo
      */
     // filePath 为文件所在全路径: D://file.txt
     public static String file2Str(String filePath) {

         //定义输出流对象
         InputStream in = null;
         byte[] data = null;
         // 读取文件字节数组
         try {
             in = new FileInputStream(filePath);
             data = new byte[in.available()];
             in.read(data);
             in.close();
         } catch (IOException e) {
             e.printStackTrace();
         } finally {
             try {
                 assert in != null;
                 in.close();
             } catch (IOException e) {
                 e.printStackTrace();
             }
         }
         // 对字节数组Base64编码
         BASE64Encoder encoder = new BASE64Encoder();
         // 返回 Base64 编码过的字节数组字符串
         assert data != null;
         return encoder.encode(data);
     }

     /**
      * @Description :  文件与base64的互相转换操作
      * @Author : mabo
      */
     // base64FileStr  base字符串
// filePath 同上
     public static boolean str2File(String base64FileStr, String filePath) {

         // 数据为空
         if (base64FileStr == null) {
             return false;
         }
         //判断文件夹是否存在
         File outputFile = new File(filePath);
         File fileP = outputFile.getParentFile();
         if (!fileP.exists() && !fileP.mkdirs() && !fileP.mkdir()) {
             throw new IllegalArgumentException("创建文件目录失败");
         }
         BASE64Decoder decoder = new BASE64Decoder();
         OutputStream out = null;
         try {
             // Base64解码,对字节数组字符串进行Base64解码并生成文件
             byte[] byt = decoder.decodeBuffer(base64FileStr);
             for (int i = 0, len = byt.length; i < len; ++i) {
                 // 调整异常数据
                 if (byt[i] < 0) {
                     byt[i] += 256;
                 }
             }
             InputStream input = new ByteArrayInputStream(byt);
             // 生成指定格式的文件
             out = new FileOutputStream(filePath);
             byte[] buff = new byte[1024];
             int len;
             while ((len = input.read(buff)) != -1) {
                 out.write(buff, 0, len);
             }
         } catch (IOException e) {
             e.printStackTrace();
         } finally {
             try {
                 assert out != null;
                 out.flush();
                 out.close();
             }catch (Exception e) {
                 e.printStackTrace();
             }
         }
         return true;
     }


 }

SpringCloud
SpringCloud组件及其作用
1)Gateway 网关在该系统中负责统一管理各个服务的对外接口,可以实现动态路由,鉴权,并且可以结合 Sentinel 实现全局流程控制,还可以实现系统的全局日志
2)Nacos 在该系统作为集成注册中心,统一管理 Sentinel,Gateway 等各组件的相关系统配置
3)Sentinel 在该系统实现流量控制、服务 熔断、降级,并且可以结合 Nacos 实现流控规则持久化
4)OpenFeign 实现负载均衡,Redis 实现系统缓存和验证码存储, SkyWalking 实现图形化分布式链路追踪

一个服务去调用另一个服务,会用到哪些组件?
Nacos配置中心获取服务
OpenFeign获取服务名进行负载均衡,获取服务实际地址

说一下MVC,它们各自的作用?
Model View Controller,M是指业务模型,V是指用户界面,C则是控制器
最典型的MVC就是JSP + servlet + javabean的模式
在这里插入图片描述
但是随着业务复杂度提高,并发量提高,系统渐渐倾向前后端分离部署。

前后端分离就是将一个单体应用拆分成两个独立的应用:前端应用和后端应用,以JSON格式进行数据交互
在这里插入图片描述

Controller类上可以使用哪些注解
@GetMapping
@PostMapping
@PutMapping
@RequestMapping

数据库连接池
程序初始化时创建一定数量的数据库连接对象并将其保存在一块内存区中,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个;释放空闲时间超过最大空闲时间的数据库连接以避免因为没有释放数据库连接而引起的数据库连接遗漏。

资源重用:

由于数据库连接得以重用,避免了频繁创建,释放连接引起的大量性能开销。在减少系统消耗的基础上,另一方面也增加了系统运行环境的平稳性。

更快的系统反应速度

数据库连接池在初始化过程中,往往已经创建了若干数据库连接置于连接池中备用。此时连接的初始化工作均已完成。对于业务请求处理而言,直接利用现有可用连接,避免了数据库连接初始化和释放过程的时间开销,从而减少了系统的响应时间。

新的资源分配手段

对于多应用共享同一数据库的系统而言,可在应用层通过数据库连接池的配置,实现某一应用最大可用数据库连接数的限制,避免某一应用独占所有的数据库资源。

统一的连接管理,避免数据库连接泄露

在较为完善的数据库连接池实现中,可根据预先的占用超时设定,强制回收被占用连接,从而避免了常规数据库连接操作中可能出现的资源泄露

druid和c3p0的区别
c3p0是一个开放源代码的JDBC连接池,它实现了数据源和JNDI绑定,包括了实现jdbc3和jdbc2扩展规范说明的Connection 和Statement 池的DataSources 对象。目前使用它的开源项目有Hibernate,Spring等
druid不仅仅是一个数据库连接池,它还包含一个ProxyDriver,一系列内置的JDBC组件库,一个 SQL Parser。支持所有JDBC兼容的数据库,包括Oracle、MySql、Derby、Postgresql、SQL Server、H2等等。Druid针对Oracle和MySql做了特别优化,比如Oracle的PS Cache内存占用优化,MySql的ping检测优化。Druid提供了MySql、Oracle、Postgresql、SQL-92的SQL的完整支持,这是一个手写的高性能SQL Parser,支持Visitor模式,使得分析SQL的抽象语法树很方便。简单SQL语句用时10微秒以内,复杂SQL用时30微秒。通过Druid提供的SQL Parser可以在JDBC层拦截SQL做相应处理,比如说分库分表、审计等。Druid防御SQL注入攻击的WallFilter就是通过Druid的SQL Parser分析语义实现的
dbcp 半自动化操作 不能自动连接
c3p0 自动化操作(自动的加载配置文件 并且设置到对象里面) 自动尝试连接

Druid 阿里巴巴的开源连接池

二、Druid的优点

替换DBCP和C3P0。Druid提供了一个高效、功能强大、可扩展性好的数据库连接池。
可以监控数据库访问性能,Druid内置提供了一个功能强大的StatFilter插件,能够详细统计SQL的执行性能,这对于线上分析数据库访问性能有帮助。
数据库密码加密。直接把数据库密码写在配置文件中,这是不好的行为,容易导致安全问题。DruidDruiver和DruidDataSource都支持PasswordCallback。
SQL执行日志,Druid提供了不同的LogFilter,能够支持Common-Logging、Log4j和JdkLog,你可以按需要选择相应的LogFilter,监控你应用的数据库访问情况。
扩展JDBC,如果你要对JDBC层有编程的需求,可以通过Druid提供的Filter机制,很方便编写JDBC层的扩展插件

在这里插入图片描述

数据库事务
. 事务的四大特性
事务具有4个基本特征,分别是:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Duration),简称ACID

① 原子性
事务的原子性是指事务必须是一个原子的操作序列单元。事务中包含的各项操作在一次执行过程中,只允许出现两种状态之一,要么都成功,要么都失败

任何一项操作都会导致整个事务的失败,同时其它已经被执行的操作都将被撤销并回滚,只有所有的操作全部成功,整个事务才算是成功完成

② 一致性(Consistency)
事务的一致性是指事务的执行不能破坏数据库数据的完整性和一致性,一个事务在执行之前和执行之后,数据库都必须处以一致性状态。

比如:如果从A账户转账到B账户,不可能因为A账户扣了钱,而B账户没有加钱

③ 隔离性
事务的隔离性是指在并发环境中,并发的事务是互相隔离的,一个事务的执行不能被其它事务干扰。也就是说,不同的事务并发操作相同的数据时,每个事务都有各自完整的数据空间。

一个事务内部的操作及使用的数据对其它并发事务是隔离的,并发执行的各个事务是不能互相干扰的

④ 持久性(Duration)
事务的持久性是指事务一旦提交后,数据库中的数据必须被永久的保存下来。即使服务器系统崩溃或服务器宕机等故障。只要数据库重新启动,那么一定能够将其恢复到事务成功结束后的状态

如何比较两个对象,说一下equals和HashCode 和==
两个对象相等,hashCode一定相等

两个对象不等,hashCode不一定不等

hashCode相等,两个对象不一定相等

hashCode不等,两个对象一定不等

== 比较的是两个对象在java虚拟机中的地址;
equals 默认比较的也是两个对象在java虚拟机中的地址,但是我们可以对一个对象的equals方法进行重写,而“==”我们无法重写;
hashcode 返回一个对象在java虚拟机中的地址;

微服务架构的优势、劣势
微服务架构的优势
使用微服务架构能够为我们带来如下好处:
1)服务的独立部署
每个服务都是一个独立的项目,可以独立部署,不依赖于其他服务,耦合性低。
2)服务的快速启动
拆分之后服务启动的速度必然要比拆分之前快很多,因为依赖的库少了,代码量也少了。
3)更加适合敏捷开发
敏捷开发以用户的需求进化为核心,采用迭代、循序渐进的方法进行。服务拆分可以快速发布新版本,修改哪个服务只需要发布对应的服务即可,不用整体重新发布。
4)职责专一,由专门的团队负责专门的服务
业务发展迅速时,研发人员也会越来越多,每个团队可以负责对应的业务线,服务的拆分有利于团队之间的分工。
5)服务可以动态按需扩容
当某个服务的访问量较大时,我们只需要将这个服务扩容即可。
6)代码的复用
每个服务都提供 REST API,所有的基础服务都必须抽出来,很多的底层实现都可以以接口方式提供。
微服务架构的劣势
微服务其实是一把双刃剑,既然有利必然也会有弊。下面我们来谈谈微服务有哪些弊端,以及能采取什么办法避免。
1)分布式部署,调用的复杂性高
单体应用的时候,所有模块之前的调用都是在本地进行的,在微服务中,每个模块都是独立部署的,通过 HTTP 来进行通信,这当中会产生很多问题,比如网络问题、容错问题、调用关系等。
2)独立的数据库,分布式事务的挑战
每个微服务都有自己的数据库,这就是所谓的去中心化的数据管理。这种模式的优点在于不同的服务,可以选择适合自身业务的数据,比如订单服务可以用 MySQL、评论服务可以用 Mongodb、商品搜索服务可以用 Elasticsearch。

缺点就是事务的问题了,目前最理想的解决方案就是柔性事务中的最终一致性,后面的章节会给大家做具体介绍。
3)测试的难度提升
服务和服务之间通过接口来交互,当接口有改变的时候,对所有的调用方都是有影响的,这时自动化测试就显得非常重要了,如果要靠人工一个个接口去测试,那工作量就太大了。这里要强调一点,就是 API 文档的管理尤为重要。
4)运维难度的提升
在采用传统的单体应用时,我们可能只需要关注一个 Tomcat 的集群、一个 MySQL 的集群就可以了,但这在微服务架构下是行不通的。当业务增加时,服务也将越来越多,服务的部署、监控将变得非常复杂,这个时候对于运维的要求就高了

项目中哪里用到了Redis?
作为缓存,存储信息
验证码
系统频繁访问的数据信息进行存储

Jedis的使用,可以实现锁的功能,但是会出现系统异常死锁,或者业务未结束锁释放。
需要使用Redisson,锁续命解决这个问题,

CAP原则
C:Consistency

即一致性,访问所有的节点得到的数据应该是一样的。注意,这里的一致性指的是强一致性,也就是数据更新完,访问任何节点看到的数据完全一致,要和弱一致性,最终一致性区分开来。

A:Availability

即可用性,所有的节点都保持高可用性。注意,这里的高可用还包括不能出现延迟,比如如果节点B由于等待数据同步而阻塞请求,那么节点B就不满足高可用性。

也就是说,任何没有发生故障的服务必须在有限的时间内返回合理的结果集。

P:Partiton tolerence

即分区容忍性,这里的分区是指网络意义上的分区。由于网络是不可靠的,所有节点之间很可能出现无法通讯的情况,在节点不能通信时,要保证系统可以继续正常服务。

设计模式,使用或了解过哪些
谈自己写的框架中使用了单例模式,工厂模式,命令模式

Spring中的每个bean默认也是单例,优点是方便Spring容器管理。

工厂模式:创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。 简单的使用就是SpringIOC容器中获取对象,就是工厂模式。

命令模式:Servlet ,请求类型反射到具体方法上

正向代理、反向代理
正向代理即是客户端代理, 代理客户端, 服务端不知道实际发起请求的客户端.

反向代理即是服务端代理, 代理服务端, 客户端不知道实际提供服务的服务端

动态代理
Jdk中的动态代理
JDK中的动态代理是通过反射类Proxy以及InvocationHandler回调接口实现的,但是JDK中所有要进行动态代理的类必须要实现一个接口,也就是说只能对该类所实现接口中定义的方法进行代理,这在实际编程中有一定的局限性,而且使用反射的效率也不高
Cglib实现
使用cglib是实现动态代理,不受代理类必须实现接口的限制,因为cglib底层是用ASM框架,使用字节码技术生成代理类,你使用Java反射的效率要高,cglib不能对声明final的方法进行代理,因为cglib原理是动态生成被代理类的子类

你可能感兴趣的