Unity游戏逆向工程终极指南:用Il2CppDumper轻松破解IL2CPP保护
2026/7/27 17:55:50
这是一个基于Spring Boot的多数据源动态切换方案,通过解析请求的域名自动选择对应的数据源。
package com.park.context; import cn.hutool.core.convert.Convert; import com.alibaba.ttl.TransmittableThreadLocal; import com.park.constants.SecurityConstants; import org.apache.commons.lang3.StringUtils; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; public class SessionContext { private static final TransmittableThreadLocal<Map<String, Object>> THREAD_LOCAL = new TransmittableThreadLocal<>(); public static void set(String key, Object value) { Map<String, Object> map = getLocalMap(); map.put(key, value == null ? StringUtils.EMPTY : value); } public static String get(String key) { Map<String, Object> map = getLocalMap(); return Convert.toStr(map.getOrDefault(key, StringUtils.EMPTY)); } public static Map<String, Object> getLocalMap() { Map<String, Object> map = THREAD_LOCAL.get(); if (map == null) { map = new ConcurrentHashMap<>(); THREAD_LOCAL.set(map); } return map; } public static void setCompanyId(String companyId) { set(SecurityConstants.COMPANY_ID, companyId); } public static String getCompanyId() { return get(SecurityConstants.COMPANY_ID); } public static void setParkingLotId(Set<String> parkingLotIds) { set(SecurityConstants.PARKINGLOT_ID, parkingLotIds); } public static Set<String> getParkingLotId() { return get(SecurityConstants.PARKINGLOT_ID, Set.class); } public static <T> T get(String key, Class<T> clazz) { Map<String, Object> map = getLocalMap(); return cast(map.getOrDefault(key, null)); } public static <T> T cast(Object obj) { if (obj == null) { return null; } return (T) obj; } public static void remove() { THREAD_LOCAL.remove(); } }package com.park.source; import com.park.constants.SecurityConstants; import com.park.context.SessionContext; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; public class DynamicDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { System.out.println("当前数据源:" + SessionContext.get(SecurityConstants.DOMAIN)); return SessionContext.get(SecurityConstants.DOMAIN); } }package com.park.constants; public class SecurityConstants { public static final String AUTHORIZATION = "Authorization"; public static final String COMPANY_ID = "companyId"; public static final String PARKINGLOT_ID = "parkingLotIds"; public static final String DOMAIN = "domain"; } package com.park.interceptor; import com.park.constants.SecurityConstants; import com.park.context.SessionContext; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.stereotype.Component; import org.springframework.web.servlet.AsyncHandlerInterceptor; import java.net.URI; import java.net.URISyntaxException; @Component public class DomainInterceptor implements AsyncHandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 清除之前的会话数据 SessionContext.remove(); String origin = request.getHeader("Origin"); if (origin != null) { try { URI uri = new URI(origin); String domain = uri.getHost(); SessionContext.setDomain(domain); } catch (URISyntaxException e) { // 记录错误日志 } } return true; } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // 请求结束后清除线程本地变量 SessionContext.remove(); } } package com.park.config; import com.park.interceptor.DomainInterceptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebConfig implements WebMvcConfigurer { @Autowired private DomainInterceptor domainInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(domainInterceptor) .addPathPatterns("/**") .excludePathPatterns("/login", "/public/**"); } }spring: datasource: bj: jdbc-url: jdbc:postgresql://localhost:5432/bj_db username: your_username password: your_password driver-class-name: org.postgresql.Driver cd: jdbc-url: jdbc:postgresql://localhost:5432/cd_db username: your_username password: your_password driver-class-name: org.postgresql.Driver package com.park.config; import com.park.source.DynamicDataSource; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.jdbc.DataSourceBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import javax.sql.DataSource; import java.util.HashMap; import java.util.Map; @Configuration public class DataSourceConfig { @Bean @ConfigurationProperties(prefix = "spring.datasource.bj") public DataSource bjDataSource() { return DataSourceBuilder.create().build(); } @Bean @ConfigurationProperties(prefix = "spring.datasource.cd") public DataSource cdDataSource() { return DataSourceBuilder.create().build(); } @Bean @Primary public DataSource dynamicDataSource() { Map<Object, Object> targetDataSources = new HashMap<>(); targetDataSources.put("bj.park.com", bjDataSource()); targetDataSources.put("cd.park.com", cdDataSource()); DynamicDataSource dynamicDataSource = new DynamicDataSource(); dynamicDataSource.setTargetDataSources(targetDataSources); dynamicDataSource.setDefaultTargetDataSource(primaryDataSource()); return dynamicDataSource; } }