中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

做古玩生意哪些網(wǎng)站好互聯(lián)網(wǎng)營銷師證書怎么考

做古玩生意哪些網(wǎng)站好,互聯(lián)網(wǎng)營銷師證書怎么考,金科網(wǎng)站建設(shè),國內(nèi)免費(fèi)無版權(quán)圖片素材網(wǎng)站背景 我們把數(shù)據(jù)存到數(shù)據(jù)庫的時候,有些敏感字段是需要加密的,從數(shù)據(jù)庫查出來再進(jìn)行解密。如果存在多張表或者多個地方需要對部分字段進(jìn)行加解密操作,每個地方都手寫一次加解密的動作,顯然不是最好的選擇。如果我們使用的是Mybati…

背景

我們把數(shù)據(jù)存到數(shù)據(jù)庫的時候,有些敏感字段是需要加密的,從數(shù)據(jù)庫查出來再進(jìn)行解密。如果存在多張表或者多個地方需要對部分字段進(jìn)行加解密操作,每個地方都手寫一次加解密的動作,顯然不是最好的選擇。如果我們使用的是Mybatis框架,那就跟著一起探索下如何使用框架的攔截器功能實(shí)現(xiàn)自動加解密吧。

定義一個自定義注解

我們需要一個注解,只要實(shí)體類的屬性加上這個注解,那么就對這個屬性進(jìn)行自動加解密。我們把這個注解定義靈活一點(diǎn),不僅可以放在屬性上,還可以放到類上,如果在類上使用這個注解,代表這個類的所有屬性都進(jìn)行自動加密。

/*** 加密字段*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.TYPE})
public @interface EncryptField {}

定義實(shí)體類

package com.wen3.demo.mybatisplus.po;import com.baomidou.mybatisplus.annotation.*;
import com.wen3.demo.mybatisplus.encrypt.annotation.EncryptField;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;@EncryptField
@Getter
@Setter
@Accessors(chain = true)
@KeySequence(value = "t_user_user_id_seq", dbType = DbType.POSTGRE_SQL)
@TableName("t_USER")
public class UserPo {/*** 用戶id*/@TableId(value = "USER_ID", type = IdType.INPUT)private Long userId;/*** 用戶姓名*/@TableField("USER_NAME")private String userName;/*** 用戶性別*/@TableField("USER_SEX")private String userSex;/*** 用戶郵箱*/@EncryptField@TableField("USER_EMAIL")private String userEmail;/*** 用戶賬號*/@TableField("USER_ACCOUNT")private String userAccount;/*** 用戶地址*/@TableField("USER_ADDRESS")private String userAddress;/*** 用戶密碼*/@TableField("USER_PASSWORD")private String userPassword;/*** 用戶城市*/@TableField("USER_CITY")private String userCity;/*** 用戶狀態(tài)*/@TableField("USER_STATUS")private String userStatus;/*** 用戶區(qū)縣*/@TableField("USER_SEAT")private String userSeat;
}

攔截器

Mybatis-Plus有個攔截器接口com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor,但發(fā)現(xiàn)這個接口有一些不足

  • 必須構(gòu)建一個MybatisPlusInterceptor這樣的Bean
  • 并調(diào)用這個BeanaddInnerInterceptor方法,把所有的InnerInterceptor加入進(jìn)去,才能生效
  • InnerInterceptor只有before攔截,缺省after攔截。加密可以在before里面完成,但解密需要在after里面完成,所以這個InnerInterceptor不能滿足我們的要求

所以繼續(xù)研究源碼,發(fā)現(xiàn)Mybatis有個org.apache.ibatis.plugin.Interceptor接口,這個接口能滿足我對自動加解密的所有訴求

  • 首先,實(shí)現(xiàn)Interceptor接口,只要注冊成為Spring容器的Bean,攔截器就能生效
  • 可以更加靈活的在beforeafter之間插入自己的邏輯

加密攔截器

創(chuàng)建名為EncryptInterceptor的加密攔截器,對update操作進(jìn)行攔截,對帶@EncryptField注解的字段進(jìn)行加密處理,無論是save方法還是saveBatch方法都會被成功攔截到。

package com.wen3.demo.mybatisplus.encrypt.interceptor;import com.wen3.demo.mybatisplus.encrypt.annotation.EncryptField;
import com.wen3.demo.mybatisplus.encrypt.util.FieldEncryptUtil;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.util.Objects;/*** 對update操作進(jìn)行攔截,對{@link EncryptField}字段進(jìn)行加密處理;* 無論是save方法還是saveBatch方法都會被成功攔截;*/
@Slf4j
@Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
})
@Component
public class EncryptInterceptor implements Interceptor {private static final String METHOD = "update";@Setter(onMethod_ = {@Autowired})private FieldEncryptUtil fieldEncryptUtil;@Overridepublic Object intercept(Invocation invocation) throws Throwable {if(!StringUtils.equals(METHOD, invocation.getMethod().getName())) {return invocation.proceed();}// 根據(jù)update攔截規(guī)則,第0個參數(shù)一定是MappedStatement,第1個參數(shù)是需要進(jìn)行判斷的參數(shù)Object param = invocation.getArgs()[1];if(Objects.isNull(param)) {return invocation.proceed();}// 加密處理fieldEncryptUtil.encrypt(param);return invocation.proceed();}
}

解密攔截器

創(chuàng)建名為DecryptInterceptor的加密攔截器,對query操作進(jìn)行攔截,對帶@EncryptField注解的字段進(jìn)行解密處理,無論是返回單個對象,還是對象的集合,都會被攔截到。

package com.wen3.demo.mybatisplus.encrypt.interceptor;import cn.hutool.core.util.ClassUtil;
import com.wen3.demo.mybatisplus.encrypt.annotation.EncryptField;
import com.wen3.demo.mybatisplus.encrypt.util.FieldEncryptUtil;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.sql.Statement;
import java.util.Collection;/*** 對query操作進(jìn)行攔截,對{@link EncryptField}字段進(jìn)行解密處理;*/
@Slf4j
@Intercepts({@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = Statement.class)
})
@Component
public class DecryptInterceptor implements Interceptor {private static final String METHOD = "query";@Setter(onMethod_ = {@Autowired})private FieldEncryptUtil fieldEncryptUtil;@SuppressWarnings("rawtypes")@Overridepublic Object intercept(Invocation invocation) throws Throwable {Object result = invocation.proceed();// 解密處理// 經(jīng)過測試發(fā)現(xiàn),無論是返回單個對象還是集合,result都是ArrayList類型if(ClassUtil.isAssignable(Collection.class, result.getClass())) {fieldEncryptUtil.decrypt((Collection) result);} else {fieldEncryptUtil.decrypt(result);}return result;}
}

加解密工具類

由于加密和解密絕大部分的邏輯是相似的,不同的地方在于

  • 加密需要通過反射處理的對象,是在SQL執(zhí)行前,是Invocation對象的參數(shù)列表中下標(biāo)為1的參數(shù);而解決需要通過反射處理的對象,是在SQL執(zhí)行后,對執(zhí)行結(jié)果對象進(jìn)行解密處理。
  • 一個是獲取到字段值進(jìn)行加密,一個是獲取到字段值進(jìn)行解密

于是把加解密邏輯抽象成一個工具類,把差異的部分做為參數(shù)傳入

package com.wen3.demo.mybatisplus.encrypt.util;import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ReflectUtil;
import com.wen3.demo.mybatisplus.encrypt.annotation.EncryptField;
import com.wen3.demo.mybatisplus.encrypt.service.FieldEncryptService;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;import java.lang.reflect.Field;
import java.util.Collection;
import java.util.List;
import java.util.Objects;/*** 加解密工具類*/
@Slf4j
@Component
public class FieldEncryptUtil {@Setter(onMethod_ = {@Autowired})private FieldEncryptService fieldEncryptService;/**對EncryptField注解進(jìn)行加密處理*/public void encrypt(Object obj) {if(ClassUtil.isPrimitiveWrapper(obj.getClass())) {return;}encryptOrDecrypt(obj, true);}/**對EncryptField注解進(jìn)行解密處理*/public void decrypt(Object obj) {encryptOrDecrypt(obj, false);}/**對EncryptField注解進(jìn)行解密處理*/public void decrypt(Collection list) {if(CollectionUtils.isEmpty(list)) {return;}list.forEach(this::decrypt);}/**對EncryptField注解進(jìn)行加解密處理*/private void encryptOrDecrypt(Object obj, boolean encrypt) {// 根據(jù)update攔截規(guī)則,第0個參數(shù)一定是MappedStatement,第1個參數(shù)是需要進(jìn)行判斷的參數(shù)if(Objects.isNull(obj)) {return;}// 獲取所有帶加密注解的字段List<Field> encryptFields = null;// 判斷類上面是否有加密注解EncryptField encryptField = AnnotationUtils.findAnnotation(obj.getClass(), EncryptField.class);if(Objects.nonNull(encryptField)) {// 如果類上有加密注解,則所有字段都需要加密encryptFields = FieldUtils.getAllFieldsList(obj.getClass());} else {encryptFields = FieldUtils.getFieldsListWithAnnotation(obj.getClass(), EncryptField.class);}// 沒有字段需要加密,則跳過if(CollectionUtils.isEmpty(encryptFields)) {return;}encryptFields.forEach(f->{// 只支持String類型的加密if(!ClassUtil.isAssignable(String.class, f.getType())) {return;}String oldValue = (String) ReflectUtil.getFieldValue(obj, f);if(StringUtils.isBlank(oldValue)) {return;}String logText = null, newValue = null;if(encrypt) {logText = "encrypt";newValue = fieldEncryptService.encrypt(oldValue);} else {logText = "decrypt";newValue = fieldEncryptService.decrypt(oldValue);}log.info("{} success[{}=>{}]. before:{}, after:{}", logText, f.getDeclaringClass().getName(), f.getName(), oldValue, newValue);ReflectUtil.setFieldValue(obj, f, newValue);});}
}

加解密算法

Mybatis-Plus自帶了一個AES加解密算法的工具,我們只需要提供一個加密key,然后就可以完成一個加解密的業(yè)務(wù)處理了。

  • 先定義一個加解密接口
package com.wen3.demo.mybatisplus.encrypt.service;/*** 數(shù)據(jù)加解密接口*/
public interface FieldEncryptService {/**對數(shù)據(jù)進(jìn)行加密*/String encrypt(String value);/**對數(shù)據(jù)進(jìn)行解密*/String decrypt(String value);/**判斷數(shù)據(jù)是否憶加密*/default boolean isEncrypt(String value) {return false;}
}
  • 然后實(shí)現(xiàn)一個默認(rèn)的加解密實(shí)現(xiàn)類
package com.wen3.demo.mybatisplus.encrypt.service.impl;import cn.hutool.core.util.ClassUtil;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.AES;
import com.wen3.demo.mybatisplus.encrypt.service.FieldEncryptService;
import org.springframework.stereotype.Component;import javax.crypto.IllegalBlockSizeException;/*** 使用Mybatis-Plus自帶的AES加解密*/
@Component
public class DefaultFieldEncryptService implements FieldEncryptService {private static final String ENCRYPT_KEY = "abcdefghijklmnop";@Overridepublic String encrypt(String value) {if(isEncrypt(value)) {return value;}return AES.encrypt(value, ENCRYPT_KEY);}@Overridepublic String decrypt(String value) {return AES.decrypt(value, ENCRYPT_KEY);}@Overridepublic boolean isEncrypt(String value) {// 判斷是否已加密try {// 解密成功,說明已加密decrypt(value);return true;} catch (MybatisPlusException e) {if(ClassUtil.isAssignable(IllegalBlockSizeException.class, e.getCause().getClass())) {return false;}throw e;}}
}

自動加解密單元測試

package com.wen3.demo.mybatisplus.service;import cn.hutool.core.util.RandomUtil;
import com.wen3.demo.mybatisplus.MybatisPlusSpringbootTestBase;
import com.wen3.demo.mybatisplus.encrypt.service.FieldEncryptService;
import com.wen3.demo.mybatisplus.po.UserPo;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.RandomStringUtils;
import org.junit.jupiter.api.Test;import java.util.Collections;
import java.util.List;
import java.util.Map;class UserServiceTest extends MybatisPlusSpringbootTestBase {@Resourceprivate UserService userService;@Resourceprivate FieldEncryptService fieldEncryptService;@Testvoid save() {UserPo userPo = new UserPo();String originalValue = RandomStringUtils.randomAlphabetic(16);String encryptValue = fieldEncryptService.encrypt(originalValue);userPo.setUserEmail(originalValue);userPo.setUserName(RandomStringUtils.randomAlphabetic(16));boolean testResult = userService.save(userPo);assertTrue(testResult);assertNotEquals(originalValue, userPo.getUserEmail());assertEquals(encryptValue, userPo.getUserEmail());// 測試解密: 返回單個對象UserPo userPoQuery = userService.getById(userPo.getUserId());assertEquals(originalValue, userPoQuery.getUserEmail());// 測試解密: 返回ListList<UserPo> userPoList = userService.listByEmail(encryptValue);assertEquals(originalValue, userPoList.get(0).getUserEmail());// 測試saveBatch方法也會被攔截加密userPo.setUserId(null);testResult = userService.save(Collections.singletonList(userPo));assertTrue(testResult);assertNotEquals(originalValue, userPo.getUserEmail());assertEquals(encryptValue, userPo.getUserEmail());}
}

單元測試運(yùn)行截圖

在這里插入圖片描述

http://www.risenshineclean.com/news/65220.html

相關(guān)文章:

  • 宜興建設(shè)局 審圖中心 網(wǎng)站seo快速排名軟件案例
  • 做企業(yè)網(wǎng)站要大陸營業(yè)執(zhí)照百度小說搜索風(fēng)云榜總榜
  • 專業(yè)做營銷網(wǎng)站百度推廣怎么推
  • 展示型網(wǎng)站設(shè)計(jì)方案百度域名收錄
  • 番禺人才網(wǎng)最新招聘信息網(wǎng)濰坊網(wǎng)站建設(shè)優(yōu)化
  • 國外免費(fèi)虛擬主機(jī)惠州seo整站優(yōu)化
  • 重慶市建設(shè)工程信息網(wǎng)質(zhì)量監(jiān)督網(wǎng)站seo策劃方案
  • 品牌建設(shè)完整版淄博seo
  • b2b門戶網(wǎng)站建設(shè)多少錢代寫
  • 1免費(fèi)做網(wǎng)站seo搜索引擎優(yōu)化人才
  • 珊瑚絨毯移動網(wǎng)站建設(shè)百度推廣頁面投放
  • 二級已備案域名免費(fèi)使用寧波搜索引擎優(yōu)化seo
  • 邯鄲做網(wǎng)站公司哪家好北京網(wǎng)站優(yōu)化多少錢
  • 專注高端網(wǎng)站設(shè)計(jì)百度百科官網(wǎng)
  • 怎樣看一個網(wǎng)站的瀏覽量太原seo網(wǎng)站排名
  • 旅游三級分銷網(wǎng)站google關(guān)鍵詞優(yōu)化排名
  • 廣州做網(wǎng)站建設(shè)的公司長沙網(wǎng)絡(luò)推廣
  • 青島旅游網(wǎng)站建設(shè)徐州seo排名公司
  • 網(wǎng)站seo計(jì)劃書代發(fā)百度關(guān)鍵詞排名
  • 網(wǎng)站建設(shè)報(bào)價(jià) 福州seo外包品牌
  • 網(wǎng)站輸入字符 顯示出來怎么做問答推廣
  • 做寫字樓用哪個網(wǎng)站更好比較靠譜的推廣平臺
  • 廣州網(wǎng)站二級等保企業(yè)網(wǎng)站營銷實(shí)現(xiàn)方式解讀
  • 英國人做愛無網(wǎng)站百度老舊版本大全
  • 外包兼職做圖的網(wǎng)站百度免費(fèi)推廣怎么操作
  • 廣州網(wǎng)站優(yōu)化哪家快洛陽市網(wǎng)站建設(shè)
  • 做綠色軟件的網(wǎng)站知乎百度關(guān)鍵詞推廣費(fèi)用
  • 網(wǎng)站獨(dú)立ip多代表什么競價(jià)推廣網(wǎng)絡(luò)推廣運(yùn)營
  • 做網(wǎng)站定金交多少合適合肥網(wǎng)站推廣優(yōu)化公司
  • 上行10m企業(yè)光纖做網(wǎng)站環(huán)球資源外貿(mào)平臺免費(fèi)