Anomaly northward, circulation southward (IF-ELSE
Removal plan)
After last
In the last article, the Pipeline of if-else cleanup, you guys watched me mess around, and as I summarized in the last article, I actually described the preconditions of if-else cleanup, being aware of the pipeline, Then we’ll move on to the cleanup plan, and in this article we’ll focus on how to short-circuit and flow pipes with Optional and Function
To the point
Abnormal to the north (up), flow to the south (down)! As mentioned in the previous article, pipe mode has Valve and Status. These two components mainly control the flow of code, which is the real implementation for cleaning if-else. However, we use a minimalist pipe in Crud-BOYS mode and do not include these components. So we actually do if-else in a couple of ways
- Valve piping (perform circuit breaker logic) and path piping (null-value logic transfer)
- The exception pipe throws an exception that causes execution to go north, essentially throwing an exception up top (to the external exception catching framework)
- Normal logic goes through other branch pipes, flows south, and continues down
source
Optional
Java8’s new features finally allow us to use functional programming, and it also provides some great tools, such as Optional, a tool for controlling decisions, as many articles have said… But if you take a closer look at its API, you’ll see that it’s not at all simple, so let’s take a look at some of the methods we’ll use today
// For filtering, it can effectively clean up 'if-else'
public Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if(! isPresent())return this;
else
return predicate.test(value) ? this : empty();
}
// For loading minimalist pipes, note that you can actually use andThen multilevel connections
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
if(! isPresent())return empty();
else {
// This returns Optional again
returnOptional.ofNullable(mapper.apply(value)); }}Copy the code
Function
// Stir-frying cold rice is the core method of minimalist plumbing
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
Copy the code
approach
In order to facilitate everybody understanding, we use a slightly more complex scenarios for example, at the same time in order to facilitate everybody can use in real business, reduce the cost of unity, better convenient and practical, this scenario is to use the permissions check JWT, Token in request header, and then check the validity of the Token, the user’s information, Then obtain the user’s permission, verify whether the current Url is in the user’s permission, we try to verify the Token validity
public static void main(String[] args) {
HttpServletRequest request = new HttpServletRequestWrapper(null);
// IF you do not concatenate the minimalist pipe, there will be a lot of 'if-else'
// The logic here is to check whether the Token is valid
String headerToken = request.getHeader(HttpHeaders.AUTHORIZATION);
// Flow logic all the way -> south
String userId = Optional.ofNullable(headerToken)
// Branch pipe, kill if-else
.filter(StringUtils::isNoneBlank)
// Simple pipe stitching
.map(parseUserIdFromToken().andThen(gainCacheFromRedis()))
// This comparison is actually to prevent Token leakage and other exceptions
.filter(cacheToken -> StringUtils.equals(headerToken, cacheToken))
// After the verification, obtain the UserId again
// We can encapsulate a layer directly in the previous Map. This is just for demonstration, not for complex extension
.map(parseUserIdFromToken())
// All logic goes from the exception -> to the north
.orElseThrow(() -> new RuntimeException("Token exception!"));
// Todo continues to obtain user permissions through UserId
}
/** * simulate JWT parsing **@returnResolve UserId */ from Token
private static Function<String, String> parseUserIdFromToken(a) {
return token -> "Analytical UserId JWT";
}
/** * Emulated Redis cache (distributed cache simple implementation) **@returnObtain the Token */ corresponding to UserId from Redis
private static Function<String, String> gainCacheFromRedis(a) {
return userId -> "Tokens obtained through Redis";
}
Copy the code
Sincerely summary
When I posted my last post to a mysterious technology group, someone pointed out that this is also an if-else, which is essentially a conditional judgment. After reviewing the code and logic, this is true, but I still want to point out the benefit of if-else, which is that the if-else logic between pipes is isolated. Check pipe section and the effectiveness of the Token through UserId access to user permissions pipeline between the conditions of judgment is isolated, rather than a heap together to form a routine, and then the IF – ELSE code block, of course, it’s just, is only a preliminary thinking after implementation, there will be misunderstandings, original intention is also expected to be of help, I also hope that some big guy can put forward a more beautiful solution to benefit my crud-boy. Finally, thank you for reading and wish the Dragon Boat Festival a healthy and happy family
Salted duck egg (a kind of egg)
Recently, I had the opportunity to use the Spring Cloud Gateway implemented by Spring Webflux, which is a Spring Reactor based responsive programming implementation. In the Spring Webflux scenario, None of the results can be read directly before subscribe, because subscribe blocks the current thread, which is not allowed in reactive programming, so the data flow in Reactor is stream, if-else can be controlled to very little. And all data must be wrapped by Mono and Flux, and Mono and Flux API is a big success of pipeline mode, can do a section to the end, never split, the following post a small example of Spring Webflux, we can try to learn from a
String hello = Mono
.just("HelloWorld")
// Can be directly judged
.switchIfEmpty(Mono.just("HelloReactor"))
// You can set the default value
.defaultIfEmpty("MyMan")
// Other values can be converted
.flatMap(word -> Mono.defer(() -> Mono.just("HelloPipeline")))
// Delay the operation
.doOnSuccess(System.out::println)
.doOnError(System.out::println)
.block();
System.out.println(hello);
Copy the code