使用结构设计模式动态选择



我有一个服务,它从用户输入中获取URL,提取该URL的正文内容,应用CSS,最后以流的形式返回结果。

棘手的部分是,我有不同的实现取决于URL,如果URL不被识别,那么一个"default"使用实现。为此,我使用策略模式在运行时选择正确的实现。

@Component
public class HtmlToHtmlServiceFactory {
private final List<HtmlToHtmlService> services;
@Autowired
public HtmlToHtmlServiceFactory(List<HtmlToHtmlService> services) {
this.services = services
}
public HtmlToHtmlService getHtmlToHtmlImpl(String url) {
return services.stream()
.filter(service -> service.supportsUrl(url))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException(String.format("No service found that supports [%s]", url)));
}
}

然而,由于某些原因,我必须使用结构模式。我认为Decorator Pattern是最合适的。否则,我也在考虑一个自我注册模式。

另外,我认为@PostConstruct注释对于初始化bean可能很有用,但是我如何使用它来映射我的服务?

编辑:

我做这个编辑,因为我似乎没有解释好。我只有一个控制器,接收包含字符串(这是我要解析的网站的URL)的多部分文件

@PostMapping(value = "/website",
consumes = MediaType.MULTIPART_FORM_DATA_VALUE,
produces = MediaType.TEXT_HTML_VALUE)
public ResponseEntity<InputStreamResource> parseUrl(@RequestParam String url) throws IOException {
InputStream parsedFile = htmlToHtmlServiceFactory.getHtmlToHtmlImpl(url).htmlToHtml(url);
InputStreamResource inputStreamResource = new InputStreamResource(parsedFile);
return ResponseEntity.ok(inputStreamResource);
}

听起来你正在寻找的是MVC模式和Spring MVC。你也可以用WebFlux来实现异步。

如果你在谈论微服务,你应该看看Spring Cloud Gateway、服务注册和发现以及Circuit Breaker。

我会做如下的事情。

控制器:

@Controller
@RequestMapping("/path0")
public class HtmlToHtmlServiceFactory {
@Autowired
private final service1;
@Autowired
private final service2;
@GetMapping("/my/path1/{var1}/more_path")
public String getHtmlToHtmlImpl(@PathVariable("var1") VarType var1, Model model) {
model.addAttribute("attribute1", service1.doThings(var1))
return view/url/that/you/configured
}
@GetMapping("/my/path2/{var1}/more_path")
...
}

ControllerAdvice

@ControllerAdvice
public class ControllerExceptionHandler {
@Autowired
FallbackService fallbackService;
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<Fallback_Service_Output> validationErrorHandler(IllegalArgumentException e){
return ResponseEntity<>(FallbackService.fallback(), HttpStatus.BAD_REQUEST);
}
}

服务:

@Service
public class service1{
@Autowire
Component1 component1;
public SomeThing doThing(VarType var){
// do things with domain and data accesss layers and whatever else
}
}
@Service
public class service2{...}

视图/url/,/你/configured.html:

someHTML maybe using template engine like thymeleaf or JSP

编辑:

你说的是正则表达式吗?

像这样:


import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Service
public class ServiceX {
public static HtmlToHtmlService supportsUrl(String url) {
String pattern = "^http(s)?://[-a-zA-Z0-9+&@#/%?=~_!:,.]*[-a-zA-Z0-9+&@#/%=~]";
Pattern r = Pattern.compile(pattern);
Matcher matcher = r.matcher(url);
if (matcher.find()) {
return new HtmlToHtmlServiceImplX();
} else {
return null;
}
}
/*
...
*/

}

然后按照@tgdavies的建议:

public HtmlToHtmlService getHtmlToHtmlImpl(String url) {
return HtmlToHtmlService htmlToHtmlService = services.stream()
.filter(service -> service.supportsUrl(url))
.findFirst()
.orElse(new defaultHtmlToHtmlImpl());
}

最新更新