API中使用的堆栈是: Spring、Spring、Hibernate、Reactive1.1.3和Postgresql。
我想从名为desiredField的Mono中提取一个字符串值,并将其添加到hashmap中。我正在展示DB、模型、存储库和util模块,所有这些都发生在这里。
JWTUtil用于在API中生成用于登录目的的JWT令牌。JWTController正在正常工作,来响应令牌!唯一的问题是不能从Mono中提取de string值。
我试过两种方法。反应方式,使用订阅方法。以及使用块方法的阻塞方式。下面显示了这两种方法以及它们自己的控制台打印。
在第一种方法(反应方式)中,我无法从Mono中提取desiredField。令牌出现在响应中,但是令牌声明中没有desiredField。desiredField只在de流内活动(请参阅控制台日志打印),外部为空。
在第二种方法(阻塞方式)中,有一个无限的循环错误,而没有在响应中获得令牌。
你能帮我从Mono中提取这个值吗?
提前感谢!
Postgres:
############
# my_table #
############
id | desired_column
-------------------------------
1 | "I am the desired value"
型号:
@Data
@Entity(name = "MyModel")
@Table(name = "my_table")
public class MyModel{
@Id
@GeneratedValue
private long id;
@Column(name="desired_column")
private String desiredField;
}
储存库:
@Slf4j
@Repository
public class MyModelRepository {
public Mono<MyModel> getMyModelInstance() {
try{
EntityManagerFactory emf = Persistence.createEntityManagerFactory("my-persistance");
Mutiny.SessionFactory factory = emf.unwrap(Mutiny.SessionFactory.class);
CriteriaBuilder builder = factory.getCriteriaBuilder();
CriteriaQuery<MyModel> criteria = builder.createQuery(MyModel.class);
Root<MyModel> root = criteria.from(MyModel.class);
criteria.where(builder.equal(root.get("id"), "1"));
Uni<MyModel> myModelInstanceUni= factory.withSession(
session -> session
.createQuery(criteria)
.getSingleResult()
);
return myModelInstanceUni
.convert()
.with(UniReactorConverters.toMono());
} catch(Exception ex) {
log.error("There is an error: {}", ex.getMessage());
return null;
}
}
}
方法1:反应方式
功用:
@Slf4j
@Component
public class JWTUtil {
@Autowired
private MyModelRepository myModelRepository;
@Value("${springbootwebfluxjjwt.jjwt.secret}")
private String secret;
@Value("${springbootwebfluxjjwt.jjwt.expiration}")
private String expirationTime;
private Key key;
@PostConstruct
public void init(){
this.key = Keys.hmacShaKeyFor(secret.getBytes());
}
public Claims getAllClaimsFromToken(String token) {
// Here get token claims
}
public String getUsernameFromToken(String token) {
// Here get token username
}
public Date getExpirationDateFromToken(String token) {
// Here get expiration date from token;
}
private Boolean isTokenExpired(String token) {
// Here validates token
}
public String generateToken (User user) {
ArrayList<Long> usr_id = new ArrayList<Long>(Collections.singleton(user.getId()));
ArrayList<String> usr_name = new ArrayList<String>(Collections.singleton(user.getName()));
ArrayList<String> usr_lastname = new ArrayList<>(Collections.singleton(user.getLastName()));
Map<String, Object> claims = new HashMap<>();
claims.put("usr_id", usu_id);
claims.put("usr_name", usu_name);
claims.put("usr_lastname", usu_lastname);
String[] desiredValueFromInside= {null};
Disposable myInstance= myModelRepository.getMyModelInstance()
.log()
.subscribeOn(Schedulers.parallel())
.subscribe(
// On next
instance-> {
desiredValueFromInside[0] = instance.getDesiredField();
claims.put("desiredField", instance.getDesiredField());
log.info("SUBSCRIBING, instance.getDesiredField() IS: {}", impuesto.getImp_tasa());
log.info("SUBSCRIBING, THE VAR desiredValueFromInsideIS: {}", impuestoFromInside[0]);
},
// On error
error -> log.error("THERE S A PROBLEM: {}", error),
// On complete
() -> log.info("WE ARE DONE!")
);
log.info("DEBUGGING, FROM OUTSIDE desiredValueFromInside IS: {}", desiredValueFromInside[0]);
log.info("DEBUGGING, FROM OUTSIDE claims.get(\"desiredField\") IS: {}", claims.get("desiredField"));
return doGenerateToken(claims, user.getUsername());
}
private String doGenerateToken(Map<String, Object> claims, String username) {
// Here generate token
}
public Boolean validateToken(String token) {
// Here validates token
}
}
控制台:
.
.
.
2022-03-02 11:21:02.485 INFO 44752 --- [ntloop-thread-0] .r.p.i.DefaultSqlClientPoolConfiguration : HR000025: Connection pool size: 100
2022-03-02 11:21:02.500 INFO 44752 --- [ntloop-thread-0] c.a.o.configuration.security.JWTUtil : DEBUGGING, FROM OUTSIDE desiredValueFromInside IS: null
2022-03-02 11:21:02.500 INFO 44752 --- [ntloop-thread-0] c.a.o.configuration.security.JWTUtil : DEBUGGING, FROM OUTSIDE claims.get(\"desiredField\") IS: null
2022-03-02 11:21:02.500 INFO 44752 --- [ parallel-2] reactor.Mono.FromPublisher.1 : onSubscribe(MonoNext.NextSubscriber)
2022-03-02 11:21:02.507 INFO 44752 --- [ parallel-2] reactor.Mono.FromPublisher.1 : request(unbounded)
.
.
.
2022-03-02 11:21:03.834 INFO 44752 --- [ntloop-thread-1] reactor.Mono.FromPublisher.1 : onNext(MyModel(id=1, desired_field="I am the desired value")
2022-03-02 11:21:03.849 INFO 44752 --- [ntloop-thread-1] c.a.o.configuration.security.JWTUtil : SUBSCRIBING, instance.getDesiredField() IS: "I am the desired value"
2022-03-02 11:21:03.849 INFO 44752 --- [ntloop-thread-1] c.a.o.configuration.security.JWTUtil : SUBSCRIBING, THE VAR desiredValueFromInsideIS: "I am the desired value"
2022-03-02 11:21:03.849 INFO 44752 --- [ntloop-thread-1] c.a.o.configuration.security.JWTUtil : "WE ARE DONE!"
2022-03-02 11:21:03.849 INFO 44752 --- [ntloop-thread-1] reactor.Mono.FromPublisher.1 : onComplete()
方法2:阻塞方式
功用:
@Slf4j
@Component
public class JWTUtil {
@Autowired
private MyModelRepository myModelRepository;
@Value("${springbootwebfluxjjwt.jjwt.secret}")
private String secret;
@Value("${springbootwebfluxjjwt.jjwt.expiration}")
private String expirationTime;
private Key key;
@PostConstruct
public void init(){
this.key = Keys.hmacShaKeyFor(secret.getBytes());
}
public Claims getAllClaimsFromToken(String token) {
// Here get token claims
}
public String getUsernameFromToken(String token) {
// Here get token username
}
public Date getExpirationDateFromToken(String token) {
// Here get expiration date from token;
}
private Boolean isTokenExpired(String token) {
// Here validates token
}
public String generateToken (User user) {
ArrayList<Long> usr_id = new ArrayList<Long>(Collections.singleton(user.getId()));
ArrayList<String> usr_name = new ArrayList<String>(Collections.singleton(user.getName()));
ArrayList<String> usr_lastname = new ArrayList<>(Collections.singleton(user.getLastName()));
Map<String, Object> claims = new HashMap<>();
claims.put("usr_id", usu_id);
claims.put("usr_name", usu_name);
claims.put("usr_lastname", usu_lastname);
String[] desiredValueFromInside= {null};
String desiredField = myModelRepository.getMyModelInstance()
.map(MyModel::getDesiredField)
.share()
.block();
desiredValueFromInside[0] = instance.getDesiredField();
claims.put("desiredField", instance.getDesiredField());
log.info("DEBUGGING, FROM OUTSIDE desiredValueFromInside IS: {}", desiredValueFromInside[0]);
log.info("DEBUGGING, FROM OUTSIDE claims.get(\"desiredField\") IS: {}", claims.get("desiredField"));
return doGenerateToken(claims, user.getUsername());
}
private String doGenerateToken(Map<String, Object> claims, String username) {
// Here generate token
}
public Boolean validateToken(String token) {
// Here validates token
}
}
控制台:这个控制台日志有无限循环。
.
.
.
2022-03-02 11:40:58.640 WARN 38436 --- [-thread-checker] io.vertx.core.impl.BlockedThreadChecker : Thread Thread[vert.x-eventloop-thread-0,5,main] has been blocked for 9212 ms, time limit is 2000 ms
io.vertx.core.VertxException: Thread blocked
at java.base@11.0.12/java.lang.Thread.sleep(Native Method) ~[na:na]
at app//reactor.core.publisher.NextProcessor.block(NextProcessor.java:135) ~[reactor-core-3.4.14.jar:3.4.14]
at app//reactor.core.publisher.MonoProcessor.block(MonoProcessor.java:116) ~[reactor-core-3.4.14.jar:3.4.14]
.
.
.
发布于 2022-03-04 15:34:36
我认为这里的要点是您组织代码的方式,在我看来,您使用的是一个反应性的框架,但是思维和编码是一种势在必行的方式。
如果将generateToken
和doGenerateToken
更改为返回Mono,则可以执行以下操作:
private Mono<String> generateToken(User user) {
ArrayList<Long> usr_id = new ArrayList<Long>(Collections.singleton(user.getId()));
ArrayList<String> usr_name = new ArrayList<String>(Collections.singleton(user.getName()));
ArrayList<String> usr_lastname = new ArrayList<>(Collections.singleton(user.getLastName()));
return myModelRepository.getMyModelInstance()
.map(modelInstance -> {
Map<String, Object> claims = new HashMap<>();
//put all values you need in claims map...
//update doGenerateToken code to return a Mono<String>
return doGenerateToken(claims, user.getUsername());
});
}
https://stackoverflow.com/questions/71326490
复制相似问题