|
@@ -0,0 +1,252 @@
|
|
|
|
|
+package com.fs;
|
|
|
|
|
+
|
|
|
|
|
+import com.fs.common.utils.PhoneUtils;
|
|
|
|
|
+import com.fs.core.security.BaseSpringBootTest;
|
|
|
|
|
+import com.fs.store.domain.FsStoreOrder;
|
|
|
|
|
+import com.fs.store.domain.FsUser;
|
|
|
|
|
+import com.fs.store.domain.FsUserAddress;
|
|
|
|
|
+import com.fs.store.mapper.FsStoreOrderMapper;
|
|
|
|
|
+import com.fs.store.mapper.FsUserAddressMapper;
|
|
|
|
|
+import com.fs.store.mapper.FsUserMapper;
|
|
|
|
|
+import org.junit.Test;
|
|
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
|
|
+import org.springframework.jdbc.core.JdbcTemplate;
|
|
|
|
|
+
|
|
|
|
|
+import java.util.List;
|
|
|
|
|
+import java.util.concurrent.ExecutorService;
|
|
|
|
|
+import java.util.concurrent.Executors;
|
|
|
|
|
+import java.util.concurrent.atomic.AtomicInteger;
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * Encrypt phone/user_phone fields directly in fs_user, fs_user_address, fs_store_order
|
|
|
|
|
+ *
|
|
|
|
|
+ * @author fs
|
|
|
|
|
+ */
|
|
|
|
|
+public class DataMigrationTest extends BaseSpringBootTest {
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private FsUserMapper fsUserMapper;
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private FsUserAddressMapper fsUserAddressMapper;
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private FsStoreOrderMapper fsStoreOrderMapper;
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private JdbcTemplate jdbcTemplate;
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ public void migrateData() {
|
|
|
|
|
+ logger.info("=== 开始加密手机号字段 ===");
|
|
|
|
|
+
|
|
|
|
|
+ // 1. encrypt fs_user.phone
|
|
|
|
|
+// encryptUserPhone();
|
|
|
|
|
+
|
|
|
|
|
+ // 2. encrypt fs_user_address.phone
|
|
|
|
|
+ encryptUserAddressPhone();
|
|
|
|
|
+
|
|
|
|
|
+ // 3. encrypt fs_store_order.user_phone
|
|
|
|
|
+// encryptStoreOrderPhone();
|
|
|
|
|
+
|
|
|
|
|
+ logger.info("=== 手机号加密完成! ===");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ==================== fs_user ====================
|
|
|
|
|
+
|
|
|
|
|
+ private void encryptUserPhone() {
|
|
|
|
|
+ logger.info("encryptUserPhone start");
|
|
|
|
|
+ FsUser query = new FsUser();
|
|
|
|
|
+ List<FsUser> userList = fsUserMapper.selectFsUserList(query);
|
|
|
|
|
+ int total = userList.size();
|
|
|
|
|
+ logger.info("user count: {}", total);
|
|
|
|
|
+
|
|
|
|
|
+ int threadCount = 10;
|
|
|
|
|
+ ExecutorService executor = Executors.newFixedThreadPool(threadCount);
|
|
|
|
|
+ AtomicInteger successCount = new AtomicInteger(0);
|
|
|
|
|
+ AtomicInteger failCount = new AtomicInteger(0);
|
|
|
|
|
+ AtomicInteger skipCount = new AtomicInteger(0);
|
|
|
|
|
+
|
|
|
|
|
+ int batchSize = (total + threadCount - 1) / threadCount;
|
|
|
|
|
+ for (int i = 0; i < threadCount; i++) {
|
|
|
|
|
+ int fromIndex = i * batchSize;
|
|
|
|
|
+ int toIndex = Math.min(fromIndex + batchSize, total);
|
|
|
|
|
+ if (fromIndex >= total) {
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ List<FsUser> batch = userList.subList(fromIndex, toIndex);
|
|
|
|
|
+ executor.submit(() -> {
|
|
|
|
|
+ for (FsUser user : batch) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ String phone = user.getPhone();
|
|
|
|
|
+ if (phone == null || phone.isEmpty()) {
|
|
|
|
|
+ skipCount.incrementAndGet();
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ String encryptedPhone = PhoneUtils.encryptPhone(phone);
|
|
|
|
|
+ if (encryptedPhone != null && !encryptedPhone.isEmpty() && !encryptedPhone.equals(phone)) {
|
|
|
|
|
+ updateUserPhone(user.getUserId(), encryptedPhone);
|
|
|
|
|
+ int count = successCount.incrementAndGet();
|
|
|
|
|
+ if (count % 100 == 0) {
|
|
|
|
|
+ logger.info("encryptUserPhone progress: {}", count);
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ skipCount.incrementAndGet();
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ logger.error("encryptUserPhone error, userId: {}", user.getUserId(), e);
|
|
|
|
|
+ failCount.incrementAndGet();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ executor.shutdown();
|
|
|
|
|
+ try {
|
|
|
|
|
+ while (!executor.awaitTermination(60, java.util.concurrent.TimeUnit.SECONDS)) {
|
|
|
|
|
+ logger.info("waiting thread pool...");
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (InterruptedException e) {
|
|
|
|
|
+ logger.error("thread pool interrupted", e);
|
|
|
|
|
+ Thread.currentThread().interrupt();
|
|
|
|
|
+ }
|
|
|
|
|
+ logger.info("encryptUserPhone done, success: {}, skip: {}, fail: {}", successCount.get(), skipCount.get(), failCount.get());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void updateUserPhone(Long userId, String encryptedPhone) {
|
|
|
|
|
+ String sql = "UPDATE fs_user SET phone = ? WHERE user_id = ?";
|
|
|
|
|
+ jdbcTemplate.update(sql, encryptedPhone, userId);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ==================== fs_user_address ====================
|
|
|
|
|
+
|
|
|
|
|
+ private void encryptUserAddressPhone() {
|
|
|
|
|
+ logger.info("encryptUserAddressPhone start");
|
|
|
|
|
+ FsUserAddress query = new FsUserAddress();
|
|
|
|
|
+ List<FsUserAddress> addressList = fsUserAddressMapper.selectFsUserAddressList(query);
|
|
|
|
|
+ int total = addressList.size();
|
|
|
|
|
+ logger.info("address count: {}", total);
|
|
|
|
|
+
|
|
|
|
|
+ int threadCount = 10;
|
|
|
|
|
+ ExecutorService executor = Executors.newFixedThreadPool(threadCount);
|
|
|
|
|
+ AtomicInteger successCount = new AtomicInteger(0);
|
|
|
|
|
+ AtomicInteger failCount = new AtomicInteger(0);
|
|
|
|
|
+ AtomicInteger skipCount = new AtomicInteger(0);
|
|
|
|
|
+
|
|
|
|
|
+ int batchSize = (total + threadCount - 1) / threadCount;
|
|
|
|
|
+ for (int i = 0; i < threadCount; i++) {
|
|
|
|
|
+ int fromIndex = i * batchSize;
|
|
|
|
|
+ int toIndex = Math.min(fromIndex + batchSize, total);
|
|
|
|
|
+ if (fromIndex >= total) {
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ List<FsUserAddress> batch = addressList.subList(fromIndex, toIndex);
|
|
|
|
|
+ executor.submit(() -> {
|
|
|
|
|
+ for (FsUserAddress address : batch) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ String phone = address.getPhone();
|
|
|
|
|
+ if (phone == null || phone.isEmpty()) {
|
|
|
|
|
+ skipCount.incrementAndGet();
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ String encryptedPhone = PhoneUtils.encryptPhone(phone);
|
|
|
|
|
+ if (encryptedPhone != null && !encryptedPhone.isEmpty() && !encryptedPhone.equals(phone)) {
|
|
|
|
|
+ updateUserAddressPhone(address.getId(), encryptedPhone);
|
|
|
|
|
+ int count = successCount.incrementAndGet();
|
|
|
|
|
+ if (count % 100 == 0) {
|
|
|
|
|
+ logger.info("encryptUserAddressPhone progress: {}", count);
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ skipCount.incrementAndGet();
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ logger.error("encryptUserAddressPhone error, id: {}", address.getId(), e);
|
|
|
|
|
+ failCount.incrementAndGet();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ executor.shutdown();
|
|
|
|
|
+ try {
|
|
|
|
|
+ while (!executor.awaitTermination(60, java.util.concurrent.TimeUnit.SECONDS)) {
|
|
|
|
|
+ logger.info("waiting thread pool...");
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (InterruptedException e) {
|
|
|
|
|
+ logger.error("thread pool interrupted", e);
|
|
|
|
|
+ Thread.currentThread().interrupt();
|
|
|
|
|
+ }
|
|
|
|
|
+ logger.info("encryptUserAddressPhone done, success: {}, skip: {}, fail: {}", successCount.get(), skipCount.get(), failCount.get());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void updateUserAddressPhone(Long id, String encryptedPhone) {
|
|
|
|
|
+ String sql = "UPDATE fs_user_address SET phone = ? WHERE id = ?";
|
|
|
|
|
+ jdbcTemplate.update(sql, encryptedPhone, id);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ==================== fs_store_order ====================
|
|
|
|
|
+
|
|
|
|
|
+ private void encryptStoreOrderPhone() {
|
|
|
|
|
+ logger.info("encryptStoreOrderPhone start");
|
|
|
|
|
+ FsStoreOrder query = new FsStoreOrder();
|
|
|
|
|
+ List<FsStoreOrder> orderList = fsStoreOrderMapper.selectFsStoreOrderList(query);
|
|
|
|
|
+ int total = orderList.size();
|
|
|
|
|
+ logger.info("order count: {}", total);
|
|
|
|
|
+
|
|
|
|
|
+ int threadCount = 10;
|
|
|
|
|
+ ExecutorService executor = Executors.newFixedThreadPool(threadCount);
|
|
|
|
|
+ AtomicInteger successCount = new AtomicInteger(0);
|
|
|
|
|
+ AtomicInteger failCount = new AtomicInteger(0);
|
|
|
|
|
+ AtomicInteger skipCount = new AtomicInteger(0);
|
|
|
|
|
+
|
|
|
|
|
+ int batchSize = (total + threadCount - 1) / threadCount;
|
|
|
|
|
+ for (int i = 0; i < threadCount; i++) {
|
|
|
|
|
+ int fromIndex = i * batchSize;
|
|
|
|
|
+ int toIndex = Math.min(fromIndex + batchSize, total);
|
|
|
|
|
+ if (fromIndex >= total) {
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ List<FsStoreOrder> batch = orderList.subList(fromIndex, toIndex);
|
|
|
|
|
+ executor.submit(() -> {
|
|
|
|
|
+ for (FsStoreOrder order : batch) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ String userPhone = order.getUserPhone();
|
|
|
|
|
+ if (userPhone == null || userPhone.isEmpty()) {
|
|
|
|
|
+ skipCount.incrementAndGet();
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ String encryptedPhone = PhoneUtils.encryptPhone(userPhone);
|
|
|
|
|
+ if (encryptedPhone != null && !encryptedPhone.isEmpty() && !encryptedPhone.equals(userPhone)) {
|
|
|
|
|
+ updateStoreOrderPhone(order.getId(), encryptedPhone);
|
|
|
|
|
+ int count = successCount.incrementAndGet();
|
|
|
|
|
+ if (count % 100 == 0) {
|
|
|
|
|
+ logger.info("encryptStoreOrderPhone progress: {}", count);
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ skipCount.incrementAndGet();
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ logger.error("encryptStoreOrderPhone error, id: {}", order.getId(), e);
|
|
|
|
|
+ failCount.incrementAndGet();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ executor.shutdown();
|
|
|
|
|
+ try {
|
|
|
|
|
+ while (!executor.awaitTermination(60, java.util.concurrent.TimeUnit.SECONDS)) {
|
|
|
|
|
+ logger.info("waiting thread pool...");
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (InterruptedException e) {
|
|
|
|
|
+ logger.error("thread pool interrupted", e);
|
|
|
|
|
+ Thread.currentThread().interrupt();
|
|
|
|
|
+ }
|
|
|
|
|
+ logger.info("encryptStoreOrderPhone done, success: {}, skip: {}, fail: {}", successCount.get(), skipCount.get(), failCount.get());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void updateStoreOrderPhone(Long id, String encryptedPhone) {
|
|
|
|
|
+ String sql = "UPDATE fs_store_order SET user_phone = ? WHERE id = ?";
|
|
|
|
|
+ jdbcTemplate.update(sql, encryptedPhone, id);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|