001-每特教育&蚂蚁课堂-第七期-精讲23种设计模式-纯手写Java动态代理模式
1. 什么是代理模式
代理模式是一种设计模式,简单说即是在不改变源码的情况下,实现对目标对象的功能扩展。
代理模式主要有两种:静态代理,动态代理。
代理模式的功能主要是起到增强方法和权限拦截的作用。
目标类和代理类实现的同一接口,约束规定。
2. 代理模式有那些应用场景
1,日志采集,2,权限控制,3,实现aop,4,mybatis mapper,5,spring的事务,6,全局捕获异常,7,Rpc远程调用;8,分布式事务原理代理数据源
3. 静态代理有那些实现方式
静态代理需要自己手写代理类代码
基于接口模式实现:
public class OrderServiceProxy implements OrderService{
private OrderService orderService;
public OrderServiceProxy(OrderService orderService) {
this.orderService = orderService;
}
public String addOrder(String userName, String userPwd) {
System.out.println("使用静态代理类打印日志开始:userName:" + userName + "," + userPwd);
String result = orderService.addOrder(userName, userPwd);
System.out.println("使用静态代理类打印日志结束:userName:" + userName + "," + userPwd);
return result;
}
}
public interface OrderService {
/**
* 需要被代理的方法
* @return
*/
String addOrder(String userName,String userPwd);
}
public class Test001 {
public static void main(String[] args) {
OrderService orderService = new OrderServiceProxy(new OrderServiceImpl());
orderService.addOrder("mayikt","123456");
}
}
package com.taotao.zuoye.daili.service;
/**
*@author tom
*Date 2020/7/10 0010 18:06
*
*/
public class OrderServiceImpl implements OrderService {
@Override
public String addOrder(String userName, String userPwd) {
System.out.println("目标代理类");
return userName+","+userPwd;
}
}
基于继承实现:
public class OrderServiceProxy extends OrderServiceImpl {
private OrderService orderService;
public OrderServiceProxy(OrderService orderService) {
this.orderService = orderService;
}
public String addOrder(String userName, String userPwd) {
System.out.println("使用静态代理类打印日志开始:userName:" + userName + "," + userPwd);
String result = super.addOrder(userName, userPwd);
System.out.println("使用静态代理类打印日志结束:userName:" + userName + "," + userPwd);
return result;
}
}
- 静态代理与动态代理区别
动态代理不需要写代理类对象,通过程序自动生成,而静态代理需要我们自己写代理类对象。 - Jdk动态代理实现的原理
jdk动态代理是实现阶段一般不需要关心代理类,而在运行阶段才指定哪一个对象,
动态代理类的源码是在运行阶段由jvm根据反射机制动态生成。
jdk动态代理的一般步骤如下:
1,被创建代理类的接口和类
2,实现InvocationHandler 接口,对目标接口中声明的所有方法进行统一处理;
3, 调用Proxy 的静态方法 ,创建代理类并生成相应的代理对象。
实现原理: 利用拦截器机制必须实现InvocationHandler 接口中的invoke 方法实现对我们的目标方法增强。
- 如何手写Jdk动态代理
- Proxy.newProxyInstance 三个参数的作用
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
loader: 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
interfaces: 一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
h: 一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
002-每特教育&蚂蚁课堂-第七期-精讲23种设计模式-CGLIB底层实现的原理
1. Cglib与Jdk动态代理的区别
1,jdk动态代理利用反射技术生成匿名的代理类走invokeHandler 回调方法实现增强,也是一种基于接口的方式实现。
2, Cglib 动态代理利用asm 字节码技术生成一个子类覆盖其中的方法实现增强,同时采用fastClass 机制对整个代理类建立索引比反射效率更高。
3.在Spring 中如果需要被代理的对象如果实现了接口采用jdk代理,没有实现接口则使用cglib 代理。
2. Cglib底层实现原理
Cglib 依赖于ASM 字节码技术,直接生成class文件,在采用类加载器读取的程序中,使用fastclass对被代理的类的方法建立索引文件不需要依赖于反射查找到目标方法,所以效率比jdk动态代理要高。
4. Spring中如何运用Cglib和Jdk动态代理
spring两种代理方式
1、若目标对象实现了若干接口,spring使用JDK的java.lang.reflect.Proxy类代理。
优点:因为有接口,所以使系统更加松耦合
缺点:为每一个目标类创建接口
2、若目标对象没有实现任何接口,spring使用CGLIB库生成目标对象的子类。
优点:因为代理类与目标类是继承关系,所以不需要有接口的存在。
缺点:因为没有使用接口,所以系统的耦合性没有使用JDK的动态代理好。
003-每特教育&蚂蚁课堂-第七期-精讲23种设计模式-站在SpringMVC源码角度分析
@async失效类的情况下
谜
1. 使用@Async为什么会失效?
@ASync 异步主要在 方法上加注解可以实现异步的效果
注意:
1, 必须将异步回调的方法单独使用有个类调用或者从容器中获取对象,如果在没有调用代理的情况下。@Async 会失效
2,如果Springmvc 控制类实现了接口,在该类中加了@Async会导致将该对象注入到SpringMVC容器中 AbstractHandlerMethodMapping
3, 方法名称必须是public
2. @Async底层实现原理
Spring容器启动初始化bean 时,判断类中是否使用了@Async注解,创建切入点和切入点处理器,根据切入点创建代理,在调用@Async注解标注的方法时,会调用代理,执行切入点处理器invoke 方法,将方法的执行提交给线程池,实现异步执行。
3. SpringMVC中使用@async会存在一个什么问题
注解失效的问题。
004-每特教育&蚂蚁课堂-第七期-精讲23种设计模式-基于装饰模式设计多级缓存框架
1. 什么是装饰模式
在实际开发项目,为了减少数据库的访问压力,我们都会将数据缓存到内存中,比如: Redis(分布式缓存),EHCHE(JVM 内置缓存)。
例如: 在早先,项目 比较小不会使用Redis作为缓存,使用JVm内置的缓存框架,项目比较大的时候开始采用redis 分布式缓存框架,这时候需要设计一级和二级缓存。
2. 装饰模式基本概念
装饰模式基本的概念: 不改变原有的代码基础上,新增附加功能。
装饰模式的定义:
1,抽象组件,定义一个抽象接口,来规范准备附加功能的类;
2,具体组件: 将要被附加功能的类,实现抽象构建角色接口‘
3, 抽象装饰者: 持有对具体构件角色的引用并定义与抽象构建角色一致的接口
4, 具体装饰: 实现抽象装饰者角色,负责对具体构件添加额外功能。
3. 如何基于装饰模式实现多级缓存框架(代码)
4. 装饰与代理模式区别
装饰模式是对我们装饰的对象实现增强,而代理模式是对我们的目标对象实现增强。
005-每特教育&蚂蚁课堂-第七期-精讲23种设计模式-基于观察者模式设计异步多渠道群发框架
1. 观察者基本概念
一个对象状态的改变通知给其他所有的对象。
2. 观察者应用场景有那些
Zookeeper的事件监听, 分布式配置中心刷新配置文件,业务中群发不同的渠道消息
3. 基于观察者模式异步发送多个渠道信息
006-每特教育&蚂蚁课堂-第七期-精讲23种设计模式-深入研究单例底层实现原理
- 什么是单例子
在当前jvm中 只会有一个该实例对象 - 单例的应用场景
1.在项目里定义的配置文件
2,Servlet对象默认就是单例
3,线程池,数据库连接池
4,Spring 中Bean 对象默认就是单例
5,实现网站计数器。
6,定义枚举常量 - 单例有那些种写法
10种写法:
懒汉式线程不安全。
package com.taotao.zuoye.single;
/**
*@author tom
*Date 2020/7/11 0011 22:36
*懒汉式: 当真正需要获取对象的时候,采取创建对象,改写法存在线程安全问题
* */
public class Singlleton01 {
private static Singlleton01 singlleton01=null;
//私有构造函数
private Singlleton01(){
}
/**
* 懒汉式,线程不安租全
*/
public static Singlleton01 getInstance(){
if (singlleton01 ==null){
singlleton01=new Singlleton01();
}
return singlleton01;
}
public static void main(String[] args) {
Singlleton01 singlleton01=Singlleton01.getInstance();
Singlleton01 singlleton011=Singlleton01.getInstance();
System.out.println(singlleton01==singlleton011);
}
}
懒汉式线程安全:
package com.taotao.zuoye.single;
/**
*@author tom
*Date 2020/7/11 0011 22:43
*
*/
public class Singleton02 {
private static Singleton02 Singleton02=null;
//私有构造函数
private Singleton02(){
}
/**
* 懒汉式,线程安全
* 已经创建的对象,获取该单例对象的时候还需要上锁效率比较低
*/
public static synchronized Singleton02 getInstance(){
if (Singleton02 ==null){
Singleton02=new Singleton02();
}
return Singleton02;
}
public static void main(String[] args) {
Singleton02 Singleton02= getInstance();
Singleton02 Singleton021= getInstance();
System.out.println(Singleton02==Singleton021);
}
}
3,懒汉式双重锁:
package com.taotao.zuoye.single;
/**
*@author tom
*Date 2020/7/11 0011 22:48
*能够保证线程安全,只会在创建该单例对象的时候上锁,获取单例对象时候不会上锁,效率比较高
*/
public class Singleton03 {
private static Singleton03 singleton03;
public static Singleton03 getInstance(){
//第一次查看
if(singleton03 ==null){
//第二次查看
synchronized (Singleton03.class){
if(singleton03==null){
singleton03=new Singleton03();
}
}
}
return singleton03;
}
public static void main(String[] args) {
Singleton03 singleton01=getInstance();
Singleton03 singleton03=getInstance();
System.out.println(singleton01==singleton03);
}
}
;
饿汉式私有:
package com.taotao.zuoye.single;
/**
*@author tom
*Date 2020/7/12 0012 8:16
*饿汉式私有
*/
public class Singleton04 {
private static final Singleton04 singleton04=new Singleton04();
private Singleton04(){
}
private static Singleton04 getInstance(){
return singleton04;
}
public static void main(String[] args) {
Singleton04 singleton04=Singleton04.getInstance();
Singleton04 singleton041=Singleton04.getInstance();
System.out.println(singleton04==singleton041);
}
}
饿汉式共有:
package com.taotao.zuoye.single;
/**
*@author tom
*Date 2020/7/12 0012 8:16
*饿汉式公有
*/
public class Singleton05 {
public static final Singleton05 singleton04=new Singleton05();
private Singleton05(){
}
private static Singleton05 getInstance(){
return singleton04;
}
public static void main(String[] args) {
Singleton05 singleton04= Singleton05.getInstance();
Singleton05 singleton041= Singleton05.getInstance();
System.out.println(singleton04==singleton041);
}
}
静态代码块:
package com.taotao.zuoye.single;
/**
*@author tom
*Date 2020/7/12 0012 9:14
*静态代码块
*/
public class Singleton06 {
private static Singleton06 singleton06;
static {
singleton06=new Singleton06();
}
public static Singleton06 getInstance(){
return singleton06;
}
public static void main(String[] args) {
Singleton06 singleton06=Singleton06.getInstance();
Singleton06 singleton061=Singleton06.getInstance();
System.out.println(singleton06==singleton061);
}
}
静态内部类:
package com.taotao.zuoye.single;
/**
*@author tom
*Date 2020/7/12 0012 9:18
*静态内部类
*/
public class Singleton07 {
private Singleton07(){
System.out.println(">>>>>>>>>Singleton07");
}
private static class SingletonHolder{
private static final Singleton07 singleton07=new Singleton07();
}
public static final Singleton07 getInstance(){
return SingletonHolder.singleton07;
}
public static void main(String[] args) {
Singleton07 singleton07=Singleton07.getInstance();
Singleton07 singleton017=Singleton07.getInstance();
System.out.println(singleton07==singleton017);
}
}
枚举实现单例:
public enum Singleton07 {
INSTANCE;
public void getInstance() {
System.out.println("<<<getInstance>>>");
}
}
枚举最安全
- 单例如何防止反射破解
1, 判断是否为空:
private Singleton01() throws Exception {
if (singleton01 != null) {
throw new Exception("该对象已经创建");
}
System.out.println("无参构造函数");
}
- 为什么序列化能够破解单例
- 如何防止序列化破解单例
2,重写该方法 指定返回的对象 防止序列化破解
007-每特教育&蚂蚁课堂-第七期-精讲23种设计模式-基于责任链模式实现风控系统
1. 什么是责任链
客户端发出一个请求,链上的对象都有机会爱处理这个请求,而客户端不需要知道
谁是具体的处理对象。这样就实现了请求者和接受者之间的解耦,并且在客户端可以实现动态的组合职责链,使编程更具有灵活性。
定义: 使多个对象都有机会处理请求,从而避免了请求的发送者和接受者直接的耦合关系,将这些对象连城一个链条,并沿着这条链条传递该请求,直到有对象处理他为止,其过程就是一个递归调用。
要点主要是:
1, 有多个对象共同对一个任务进行处理;
2,这些对象使用链式存储结构,可以增加一些操作后将对象传递给下一个任务,也可以在此对象上结束任务的处理,并结束任务。
3, 一个对象对任务进行处理,可以增加一些操作后将对象传递给下一个任务。也可以在此对象上结束任务的处理,并结束任务。
4,客户端负责组装链式结构,但是客户端不需要关心最终谁来处理了任务。
责任链模式优缺点
优点:
职责链模式的最主要功能就是:动态组合,请求者和接受者解耦。
请求者和接受者松散耦合:请求者不需要知道接受者,也不需要知道如何处理。每个职责对象只负责自己的职责范围,其他的交给后继者。各个组件间完全解耦。
动态组合职责:职责链模式会把功能分散到单独的职责对象中,然后在使用时动态的组合形成链,从而可以灵活的分配职责对象,也可以灵活的添加改变对象职责。
缺点:
产生很多细粒度的对象:因为功能处理都分散到了单独的职责对象中,每个对象功能单一,要把整个流程处理完,需要很多的职责对象,会产生大量的细粒度职责对象。
不一定能处理:每个职责对象都只负责自己的部分,这样就可以出现某个请求,即使把整个链走完,都没有职责对象处理它。这就需要提供默认处理,并且注意构造链的有效性。
2. 责任链模式应用场景
1,多条件的流程判断,权限控制
2,ERP系统,流程审批,总经理,人事, 项目经理
3,java 过滤器的底层实现Filter
4,风控系统;
3. 如何手写责任链链表关系
008-每特教育&蚂蚁课堂-第七期-精讲23种设计模式-策略模式
1. 什么是策略模式
策略模式是对算法的包装,是把使用算法的责任和算法本身分离开来,委派给不同的对象管理最终可以解决多重if 判断问题。
1, 环境(Context)角色: 持有一个Strategy 的引用;
2,抽象策略(Strategy)角色,这是一个抽象角色,通常由一个接口或者抽象类实现,此角色给出所有的具体策略类所需要的接口
3, 具体策略(ConcretStrategy)角色 : 包装了相关的算法或者行为;
定义策略接口---实现不同的策略类---利用多态或者其他方式调用策略;
2. 策略模式应用场景
1,异步发送短信 比如阿里云, 腾讯云,其他短信渠道
2,聚合支付,银联支付,支付宝,微信支付
3,联合登录
3. 如何实现策略模式
009-每特教育&蚂蚁课堂-第七期-互联网安全架构平台设计-如何防御XSS攻击与防止抓包篡改数据
1. 什么是XSS脚本攻击
···
XSS攻击通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。这些恶意网页程序通常是JavaScript,但实际上也可以包括Java、 VBScript、ActiveX、 Flash 或者甚至是普通的HTML。攻击成功后,攻击者可能得到包括但不限于更高的权限(如执行一些操作)、私密网页内容、会话和cookie等各种内容。
- 如何防御xss脚本攻击
参数过滤即可:
@Component
@WebFilter
public class XssFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
XssHttpServletRequestWrapper xssHttpServletRequestWrapper = new XssHttpServletRequestWrapper((HttpServletRequest) request);
chain.doFilter(xssHttpServletRequestWrapper, response);
}
@Override
public void destroy() {
}
}
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
private HttpServletRequest request;
public XssHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
this.request = request;
}
@Override
public String getParameter(String name) {
String oldValue = super.getParameter(name);
if(StringUtils.isEmpty(oldValue)){
return oldValue;
}
String newValue = StringEscapeUtils.escapeHtml4(oldValue);
return newValue;
}
}
- 如何防止抓包篡改http请求
可以使用第三方工具对请求前后代码实现代理,可以修改参数请求内容和参数响应内容。
使用MD5防止参数被篡改;
使用MD5可以直接验证签名参数, MD5属于单向加密,只能暴力破解。
String userName="123456";
System.out.println( DigestUtils.md5Hex(userName));
参数签名:
import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;
/**
* 参数验证签名
*/
public class SignUtil {
private static Logger logger = LoggerFactory.getLogger(SignUtil.class);
/** 加密密钥 */
private final static String APP_KEY = "mykey123456";
public final static String SECRET_KEY = "mysecret123456";
/** 字符编码 */
private final static String INPUT_CHARSET = "UTF-8";
/** 超时时间 */
private final static int TIME_OUT = 30 * 60 * 1000;
/**
* 请求参数Map转换验证Map
*
* @param requestParams
* 请求参数Map
* @param charset
* 是否要转utf8编码
* @return
* @throws UnsupportedEncodingException
*/
public static Map<String, String> toVerifyMap(Map<String, String[]> requestParams, boolean charset) {
Map<String, String> params = new HashMap<>();
for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
String name = (String) iter.next();
String[] values = requestParams.get(name);
String valueStr = "";
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
}
// 乱码解决,这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
if (charset)
valueStr = getContentString(valueStr, INPUT_CHARSET);
params.put(name, valueStr);
}
return params;
}
/**
* 除去数组中的空值和签名参数
*
* @param sArray
* 签名参数组
* @return 去掉空值与签名参数后的新签名参数组
*/
public static Map<String, String> paraFilter(Map<String, String> sArray) {
Map<String, String> result = new HashMap<>();
if (sArray == null || sArray.size() <= 0) {
return result;
}
for (String key : sArray.keySet()) {
String value = sArray.get(key);
if (value == null || value.equals("") || key.equalsIgnoreCase("sign")) {
continue;
}
result.put(key, value);
}
return result;
}
/**
* 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串
*
* @param params
* 需要排序并参与字符拼接的参数组
* @return 拼接后字符串
*/
public static String createLinkString(Map<String, String> params) {
return createLinkString(params, false);
}
/**
* 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串
*
* @param params
* 需要排序并参与字符拼接的参数组
* @param encode
* 是否需要UrlEncode
* @return 拼接后字符串
*/
public static String createLinkString(Map<String, String> params, boolean encode) {
List<String> keys = new ArrayList<>(params.keySet());
Collections.sort(keys);
String prestr = "";
for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
String value = params.get(key);
if (encode)
value = urlEncode(value, INPUT_CHARSET);
if (i == keys.size() - 1) {// 拼接时,不包括最后一个&字符
prestr = prestr + key + "=" + value;
} else {
prestr = prestr + key + "=" + value + "&";
}
}
return prestr;
}
/**
* 编码转换
*
* @param content
* @param charset
* @return
* @throws UnsupportedEncodingException
*/
private static byte[] getContentBytes(String content, String charset) {
if (charset == null || "".equals(charset)) {
return content.getBytes();
}
try {
return content.getBytes(charset);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + charset);
}
}
/**
* 编码转换
*
* @param content
* @param charset
* @return
*/
private static String getContentString(String content, String charset) {
if (charset == null || "".equals(charset)) {
return new String(content.getBytes());
}
try {
return new String(content.getBytes("ISO-8859-1"), charset);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("指定的编码集不对,您目前指定的编码集是:" + charset);
}
}
/**
* URL转码
*
* @param content
* @param charset
* @return
*/
private static String urlEncode(String content, String charset) {
try {
return URLEncoder.encode(content, charset);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("指定的编码集不对,您目前指定的编码集是:" + charset);
}
}
// TODO 签名
/**
* 生成要请求的签名参数数组
*
* @param sParaTemp
* 需要签名的参数Map
* @return 要请求的签名参数数组
*/
public static Map<String, String> signMap(Map<String, String[]> sParaTemp) {
// 请求参数Map转换验证Map,并生成要请求的签名参数数组
return sign(toVerifyMap(sParaTemp, false));
}
/**
* 生成要请求的签名参数数组
*
* @param sParaTemp
* 需要签名的参数
* @return 要请求的签名参数数组
*/
public static Map<String, String> sign(Map<String, String> sParaTemp) {
// 时间戳加入签名参数组中
sParaTemp.put("timestamp", String.valueOf(System.currentTimeMillis()));
// 除去数组中的空值和签名参数
Map<String, String> sPara = paraFilter(sParaTemp);
// 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
String prestr = createLinkString(sPara);
// 生成签名结果
String mysign = DigestUtils.md5Hex(getContentBytes(prestr + APP_KEY, INPUT_CHARSET));
// 签名结果加入请求提交参数组中
sPara.put("sign", mysign);
return sPara;
}
public static String getSignStr(Map<String, String> sParaTemp) {
return sign(sParaTemp).get("sign");
}
/**
* 生成要请求的签名参数字符串“参数=参数值”&链接
*
* @param sParaTemp
* 需要签名的参数Map
* @return 请求的签名参数字符串
*/
public static String signStringMap(Map<String, String[]> sParaTemp) {
// 生成要请求的签名参数数组
Map<String, String> sign = signMap(sParaTemp);
// 生成要请求的签名参数字符串“参数=参数值”&链接
return createLinkString(sign, true);
}
/**
* 生成要请求的签名参数字符串“参数=参数值”&链接
*
* @param sParaTemp
* 需要签名的参数
* @return
*/
public static String signString(Map<String, String> sParaTemp) {
// 生成要请求的签名参数数组
Map<String, String> sign = sign(sParaTemp);
// 生成要请求的签名参数字符串“参数=参数值”&链接
return createLinkString(sign, true);
}
// TODO 验证签名
/**
* 根据反馈回来的信息,生成签名结果
*
* @param paramsMap
* 通知返回来的请求参数Map
* @return 验证结果
*/
public static boolean verifyMap(Map<String, String[]> paramsMap) {
// 请求参数Map转换验证Map,并根据反馈回来的信息,生成签名结果
return verify(toVerifyMap(paramsMap, false));
}
/**
* 根据反馈回来的信息,生成签名结果
*
* @param params
* 通知返回来的参数数组
* @return 验证结果
*/
public static boolean verify(Map<String, String> params) {
String sign = "";
if (params.get("sign") != null) {
sign = params.get("sign");
} else {
logger.info("sign is null");
return false;
}
String timestamp = "";
if (params.get("timestamp") != null) {
timestamp = params.get("timestamp");
} else {
return false;
}
// 过滤空值、sign
Map<String, String> sParaNew = paraFilter(params);
// 获取待签名字符串
String preSignStr = createLinkString(sParaNew);
// 获得签名验证结果
String mysign = DigestUtils.md5Hex(getContentBytes(preSignStr + APP_KEY, INPUT_CHARSET));
if (mysign.equals(sign)) {
// 是否超时
long curr = System.currentTimeMillis();
if ((curr - Long.valueOf(timestamp)) > TIME_OUT) {
logger.info("api is time out");
return false;
}
return true;
} else {
return false;
}
}
}
生成MD5签名与验证
Map<String,String> signMap=new HashMap<>();
signMap.put("amount",1000+"");
Map<String, String> sign = SignUtil.sign(signMap);
System.out.println(sign.toString());
@RequestMapping("/toPay")
@ResponseBody
public String getMeiteUser(Long amount) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
Map<String, String[]> parameterMap = request.getParameterMap();
if (!SignUtil.verifyMap(parameterMap)) {
return "参数发生了变化,验证签名失败.";
}
return "用户支付金额:" + amount;
}
- 对称加密与非对称加密的区别
对称加密:
1,加密和解密都是同一个秘钥
2, 优势,算法公开,加密快,效率高
3,缺点,可以采用反编译破解客户端真实秘钥:
常用对称加密框架:
1,DES(Data Encryption Standard)
2, 3des
3,aes
加密和解密都是采用同一个秘钥,也就是客户端与服务器数据传输采用同一个秘钥实现加解密,所以如果黑客反编译了客户端源码就可以破解该密文。
010-每特教育&蚂蚁课堂-第七期-互联网安全架构平台设计-spring security实现动态权限控制
- security认证模式
- securityRBAC权限模型
011-每特教育&蚂蚁课堂-第七期-互联网安全架构平台设计-spring security+jwt+oatuh2.0
- 什么是jwt
- jwt与token之间的区别
- jwt实现的原理
- jwt存在那些优缺点
012-每特教育&蚂蚁课堂-第七期-互联网安全架构平台设计-spring security整合oatuh2.0
- 什么是oauh2.0协议
- oauh2.0协议实现的方式
- oauh2.0与单点登陆的区别
- oauh2.0四种实现方式
- oauht2.0实现应用场景
013-每特教育&蚂蚁课堂-第七期-从零开始学习多线程技术-多线程技术快速入门
- 什么是多线程
- 进程与线程的区别
- 多线程与单线程的区别
- 如何理解cpu切换概念
- 多线程创建四种方式
- 如何创建线程带返回结果
- 用户线程与守护线程的区别
- 多线程五种状态分析
014-每特教育&蚂蚁课堂-第七期-从零开始学习多线程技术-多线程线程安全问题
- 什么是线程安全问题
- 如何解决线程安全问题
- Synchronized与Lock锁的区别
- 多线程死锁线程产生的原因
- 多线程如何排查死锁的现象
015-每特教育&蚂蚁课堂-第七期-从零开始学习多线程技术-多线程之间如何实现通讯
- wait与notify区别
- wait与sleep区别
- join实现的原理
016-每特教育&蚂蚁课堂-第七期-深入理解并发编程-javavolatile原理分析
- 快速回顾多核多cpu的概念
- 线程不可见产生的原因
- java内存模型的Jmm定义
- volatile关键字实现原理
- mesi数据一致性协议原理
017-每特教育&蚂蚁课堂-第七期-深入理解并发编程-volatile重排序与内存屏障
- volatile不保证原子性
- 为什么会产生重排序
- 重排序会遵循什么原则
- 重排序在多线程的情况下有那些影响
- 为什么单例需要加上volatile
- synchronized与volatile区别
018-每特教育&蚂蚁课堂-第七期-深入理解并发编程-悲观锁&乐观锁&公平锁&非公平锁&自旋转锁原理
- 锁的分类有那些
- mysql中的事务如果是做begin,不回滚也提交会发生什么情况
- 如何处理mysql行锁的问题
- mysql中的行锁在什么时候释放
- 乐观锁与悲观锁的区别
- 公平锁与非公平锁的区别
- 什么是锁的可重入性
- 共享锁的特征
019-每特教育&蚂蚁课堂-第七期-深入理解并发编程-站在C++源码角度分析synchronized锁的原理
- 什么是CAS
- CAS保证原子性
- 什么是自旋锁
- 自旋锁有那些问题
- CAS有那些有缺点
- 原子类底层实现原理
- CAS如何解决ABA的问题
020-每特教育&蚂蚁课堂-第七期-深入理解并发编程-synchronized的monitor与对象布局原理分析
- synchronized实现原理
- synchronized monitor对象作用
- java对象 内存如何布局
- new 一个对象占多少字节
- 对象头存放了那些内容
021-每特教育&蚂蚁课堂-第七期-深入理解并发编程-synchronized锁竞争偏向锁轻量锁重量锁原理分析
- synchronized一定是为重量锁吗
- synchronized锁的进化过程
- synchronized 偏向锁、轻量锁 重量锁 区别
- 锁消除与粗化
- synchronized优化点
022-每特教育&蚂蚁课堂-第七期-深入理解并发编程-深入分析AQS实现原理、
023-每特教育&蚂蚁课堂-第七期-深入理解并发编程-AbstractQueuedSynchronizer源码解读
- Lock底层是如何实现?
- Lock默认是公平锁还是悲观锁
- 简单谈谈AQS框架
- AQS在那些地方有用到过
- AQS加锁、解锁原理
- AQS如何实现公平锁与非公平锁
- AQS底层是采用单向还是双链表存放正在等待的线程
网友评论