在Spring Boot中动态加载URI

在Spring Boot中动态加载URI

通常,我们会在Spring Controller和处理方法中硬编码URI,但你是否考虑过从数据库中动态加载URI并在运行时更新它?我们可以从数据库中加载URI,并在任何Spring Controller中配置它。

为此,选择任何你想存储URI的数据库。

为了实现这一点,我们需要一个服务来从数据库加载所有URI并缓存它们,以便我们可以在处理方法中配置它们。

我创建了一个ApiCache服务来从数据库加载所有URI。

@Component
@Getter
@Setter
@DependsOn("dbInitialize")
public class ApiCache {
    @Autowired
    private DynamicUriRepository dynamicUriRepository;
    private Map<String, String> cacheMap = new HashMap<>();
    
    public String getApi(String apiName) {
        return cacheMap.get(apiName);
    }
    
    @PostConstruct
    public void init() {
        List<DynamicUri> dynamicUris = dynamicUriRepository.findAll();
        cacheMap.putAll(dynamicUris.stream()
            .collect(Collectors.toMap(DynamicUri::getUriName, DynamicUri::getUriPath)));
    }
}

**init() PostConstruct**将从数据库加载所有URI并缓存它们。

**getApi()**方法将通过传入的URI名称从映射中返回URI路径。

为了演示,我创建了另一个名为DbInitialize的服务来在数据库中输入uri_name和uri_path,这里不详细说明,你可以自己管理。

以下是域模型:

@AllArgsConstructor
@NoArgsConstructor
@Setter
@Getter
@Entity
public class DynamicUri {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String uriName;
    private String uriPath;
}

以下是我们的URI将被加载的控制器:

@RestController
public class DemoController {
    @GetMapping("#{apiCache.getApi('DEMO-API')}")
    public String demo() {
        return "Hello from Spring Boot!";
    }
}

“#{apiCache.getApi(‘DEMO-API’)}” 是一种spEL表达式,它将调用getApi()方法,并传入参数“DEMO-API”。有关更多spEL信息,请参考这里

现在进入下一部分:我们如何在运行时更新URI?

为此,我在UriController中创建了一个端点来处理更新请求。

@RestController
public class UriController {
    @Autowired
    private RequestMappingHandlerMapping requestMappingHandlerMapping;
    
    @PutMapping(value = "/uri/update")
    public Object updateUri(@RequestBody UriUpdateRequest uriUpdateRequest) {
        Map<RequestMappingInfo, HandlerMethod> handlerMethods =
            requestMappingHandlerMapping.getHandlerMethods();
        
        for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : handlerMethods.entrySet()) {
            RequestMappingInfo requestMappingInfo = entry.getKey();
            HandlerMethod handlerMethod = entry.getValue();
            
            for (String patternValue : requestMappingInfo.getPatternValues()) {
                if (patternValue.equals(uriUpdateRequest.getOldUri())) {
                    RequestMethod requestMethod =
                        requestMappingInfo.getMethodsCondition().getMethods().stream().findFirst().get();
                    
                    if (requestMethod.name().equals(uriUpdateRequest.getHttpMethod())) {
                        RequestMappingInfo requestMappingInfoToRegister =
                            RequestMappingInfo.paths(uriUpdateRequest.getNewUri())
                                .methods(requestMethod).build();
                        
                        Object handler = handlerMethod.getBean();
                        requestMappingHandlerMapping.unregisterMapping(requestMappingInfo);
                        requestMappingHandlerMapping.registerMapping(
                            requestMappingInfoToRegister, handler, handlerMethod.getMethod());
                    }
                }
            }
        }
        return "URI updated successfully";
    }
}

为了演示,我在控制器中编写了所有逻辑。

RequestMappingHandlerMapping是一个处理应用程序中所有URI的类。

getHandlerMethods()方法返回一个映射,其中包含RequestMappingInfoHandlerMethod

RequestMappingInfo顾名思义,存储有关URI的所有信息。

HandlerMethod顾名思义,存储有关处理方法和bean的信息。

代码解释: 这里,我们使用RequestMappingHandlerMapping检索应用程序中的所有可用处理方法。然后,我们定位与oldUri关联的特定RequestMappingInfo并根据请求的HTTP方法进行过滤以更新相应的URI。

注意可能会有相同的URI与不同的HTTP方法关联。例如,POST /ordersGET /orders

当通过根据URI和HTTP方法进行过滤定位到所需的RequestMappingInfo时,将使用新的URI和HTTP方法创建一个新的RequestMappingInfo对象。然后将该方法的关联处理器bean存储在一个对象handler中。

Object handler = handlerMethod.getBean();
RequestMappingInfo requestMappingInfoToRegister =
    RequestMappingInfo.paths(uriUpdateRequest.getNewUri())
        .methods(requestMethod).build();

然后我们注销旧的RequestMappingInfo并注册新的:

requestMappingHandlerMapping.unregisterMapping(requestMappingInfo);
requestMappingHandlerMapping.registerMapping(requestMappingInfoToRegister, handler,
                                              handlerMethod.getMethod());
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值