When I used spring aop(aspectJ proxy-target-class="true"), List can receive the parameters from json but it shows that "java.util.hashmap cannot be cast to MyEntity". And I am using SSH framework. The codes are shwon below:
package com.yoyo.aspect;
#Aspect
#Component
#Scope("prototype")
#ParentPackage("json-default")
#Results({#Result(name="result", type="json", params={"root","dataMap"})})
public class LoggerAspect extends SuperAction{
#Autowired
private LoggerService loggerService;
//signature
#Pointcut("execution(String com.yogo.action.admin..*.*(..))")
public void adminLogger(){}
#Pointcut("execution(String com.yogo.action.enterprise..*.*(..))")
public void enterpriseLogger(){}
#Pointcut("execution(String com.yogo.action.product..*.*(..))")
public void productLogger(){}
#Around(value="adminLogger()||enterpriseLogger()||productLogger()")
public Object loggerAround(ProceedingJoinPoint pjp) throws Throwable{
ServletRequestAttributes attr = (ServletRequestAttributes)RequestContextHolder.currentRequestAttributes();
HttpSession session=attr.getRequest().getSession(true);
String className = pjp.getSignature().getDeclaringTypeName();
Method method = ((MethodSignature)pjp.getSignature()).getMethod();
String methodName = method.getName();
Logger log = new Logger();
log.setClassName(className);
log.setMethodName(methodName);
try {
log.setResult("success");
return pjp.proceed();
} catch (Throwable throwable) {
log.setResult("failure");
return RESULT;
} finally {
if(session!=null&&session.getAttribute("AID")!=null){
log.setAid((int)session.getAttribute("AID"));
log.setDatetime(new Date());
loggerService.save(log);
}
}
}
}
package com.yoyo.action.product.property;
#Controller
#Scope("prototype")
#ParentPackage("json-default")
#Namespace("/product")
#Results({#Result(name="result", type="json", params={"root","dataMap"})})
#InterceptorRefs({#InterceptorRef(value="json"), #InterceptorRef(value="defaultStack")})
public class AddOrUpdateProductPropertyAction extends SuperAction /*implements ModelDriven<ProductProperty>*/{
#Autowired
private ProductPropertyService productPropertyService;
private ProductProperty productProperty = new ProductProperty();
private List<ProductProperty> list;
private Product product;
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
public List<ProductProperty> getList() {
return list;
}
public void setList(List<ProductProperty> list) {
this.list = list;
}
/*#Override
public ProductProperty getModel() {
return productProperty;
}*/
#Action(value="AddOrUpdateProductProperty")
public String addOrUpdateProductProperty() throws Throwable{
int pid = product.getPid();
try {
if(pid!=0&&!"".equals(pid)){
productProperty.setPid(pid);
for(int i=0; i<list.size(); i++){
productProperty.setPpid(list.get(i).getPpid());
productProperty.setPkey(list.get(i).getPkey());
productProperty.setPvalue(list.get(i).getPvalue());
productProperty.setStatus(list.get(i).getStatus());
productPropertyService.saveOrUpdate(productProperty);
}
}else{
setErrorResult(2, "No Product ID");
}
} catch (Exception e){
setErrorResult(1, e.getMessage());
throw new Exception(e);
}
return RESULT;
}
}
And I post the json in the right format to this AddOrUpdateProductProperty(url):
{
"product":{
"pid":"1"
},
"list":[
{
"pkey": "",
"pvalue":"45%",
"status":1
}]
}
the response saying(exception.getMessage):
{"msg":"java.util.HashMap cannot be cast to com.yogo.entity.ProductProperty","flag":1}
If I comment the AOP execution, everything runs well and all the data in "list" can be well received and written in mysql successfully.
//#Around(value="adminLogger()||enterpriseLogger()||productLogger()")
I also checked receiving the data in "list" using println. I found that it can receive it but cannot cast to MyEntity "ProductProperty":
System.out.println(list.get(i));
//this works
System.out.println(list.get(i).getPpid());
//this got error as above
I am not quite familiar with spring aop mechanism, anyone could help? Thank you so much!
Related
i've been struggeling with the following code. and am not sure how to deserialize it or even pass the correct type at run time.
the code is:
#Override
public <T, R> R sendAsync(T payload, String routingKey, String exchangeName) {
ListenableFuture<R> listenableFuture =
asyncRabbitTemplate.convertSendAndReceiveAsType(
exchangeName,
routingKey,
payload,
new ParameterizedTypeReference<>() {
}
);
try {
return listenableFuture.get();
} catch (InterruptedException | ExecutionException e) {
LOGGER.error(" [x] Cannot get response.", e);
return null;
}
}
let us say that am just calling the method like the following
SaveImageResponse response = backendClient.sendAsync( new SaveImageRequest(createQRRequest.getOwner(), qr), RabbitConstants.CREATE_QR_IMAGE_KEY, RabbitConstants.CDN_EXCHANGE);
while the pojo is the following:
public class SaveImageResponse {
private String id;
private String message;
public SaveImageResponse() {
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
#Override
public String toString() {
return "SaveImageResponse{" +
"id='" + id + '\'' +
", message='" + message + '\'' +
'}';
}
}
the current code is throwing the following error:
Caused by: java.lang.ClassCastException: class java.util.LinkedHashMap cannot be cast to class dev.yafatek.qr.api.responses.SaveImageResponse (java.util.LinkedHashMap is in module java.base of loader 'bootstrap'; dev.yafatek.qr.api.responses.SaveImageResponse is in unnamed module of loader 'app')
thanks in advance
SOLUTION:
so I ended up using the following:
#Override
public <T, R> R sendAsync(T payload, String routingKey, String exchangeName, Class<R> clazz) {
ListenableFuture<R> listenableFuture =
asyncRabbitTemplate.convertSendAndReceiveAsType(
exchangeName,
routingKey,
payload,
new ParameterizedTypeReference<>() {
}
);
try {
return objectMapper.convertValue(listenableFuture.get(), clazz);
} catch (InterruptedException | ExecutionException e) {
LOGGER.error(" [x] Cannot get response.", e);
return null;
}
}
by using the object mapper and pass the actual type when call the method using
Class<POJO> clazz
to use the above code :
WebsiteInfoResponse websiteInfoResponse = backendClient.sendAsync(new GetWebsiteInfoReq(createBusinessDetailsRequest.getWebsiteUrlId()), RabbitConstants.GET_WEBSITE_INFO_KEY, RabbitConstants.QR_EXCHANGE, WebsiteInfoResponse.class);
You can't.
The whole reason for ParameterizedTypeReference<Foo> is to tell the converter you want a Foo; this has to be resolved at compile time for the method; you can't call sendAsync() to receive different types.
Providing no generic type means it will convert to Object (usually a map).
Even new ParameterizedTypeReference<R>() { } won't work because R is not resolved at compile time for the generic type (of the sendAsync() method).
You have to do the conversion yourself.
#SpringBootApplication
public class So69299112Application {
public static void main(String[] args) {
SpringApplication.run(So69299112Application.class, args);
}
#Bean
MessageConverter converter() {
return new Jackson2JsonMessageConverter();
}
ObjectMapper mapper = new ObjectMapper();
#Bean
AsyncRabbitTemplate template(RabbitTemplate template) {
template.setMessageConverter(new SimpleMessageConverter());
return new AsyncRabbitTemplate(template);
}
#Bean
ApplicationRunner runner(Service service) {
return args -> {
byte[] response = service.sendAsync("bar", "foo", "");
Foo foo = this.mapper.readerFor(Foo.class).readValue(response);
System.out.println(foo);
};
}
#RabbitListener(queues = "foo")
public Foo listen(String in) {
return new Foo(in);
}
public static class Foo {
String foo;
public Foo() {
}
public Foo(String foo) {
this.foo = foo;
}
public String getFoo() {
return this.foo;
}
public void setFoo(String foo) {
this.foo = foo;
}
#Override
public String toString() {
return "Foo [foo=" + this.foo + "]";
}
}
}
#Component
class Service {
private static final Logger LOGGER = LoggerFactory.getLogger(Service.class);
AsyncRabbitTemplate asyncRabbitTemplate;
public Service(AsyncRabbitTemplate asyncRabbitTemplate) {
this.asyncRabbitTemplate = asyncRabbitTemplate;
}
public byte[] sendAsync(Object payload, String routingKey, String exchangeName) {
ListenableFuture<byte[]> listenableFuture = asyncRabbitTemplate.convertSendAndReceive(
exchangeName,
routingKey,
payload);
try {
return listenableFuture.get();
}
catch (InterruptedException | ExecutionException e) {
LOGGER.error(" [x] Cannot get response.", e);
return null;
}
}
}
I have a Service class, which makes 2 different calls to another API which returns 2 different response objects. For Simplicity let that be shown as below
public class Service {
public AddResponseWrapper add(Request request) {
final AddResponseWrapper addResponseWrapper = new AddResponseWrapper();
try {
final AddResponse addResponse = addApi.add(request);
addResponseWrapper.setAddResponse(addResponse);
} catch (final Exception e) {
addResponseWrapper.setErrorDetails(convert(e));
}
return addResponseWrapper;
}
public DeleteResponseWrapper delete(Request request) {
final DeleteResponseWrapper deleteResponseWrapper = new DeleteResponseWrapper();
try {
final DeleteResponse deleteResponse = deleteApi.delete(request);
deleteResponseWrapper.setDeleteResponse(deleteResponse);
} catch (final Exception e) {
deleteResponseWrapper.setErrorDetails(convert(e));
}
return deleteResponseWrapper;
}
}
Similarly, I have these 2 below POJOs created
public class AddResponseWrapper {
private AddResponse addResponse;
private ErrorDetails errorDetails;
public AddResponse getAddResponse() {
return addResponse;
}
public void setAddResponse(final AddResponse addResponse) {
this.addResponse = addResponse;
}
public ErrorDetails getErrorDetails() {
return errorDetails;
}
public void setErrorDetails(final ErrorDetails errorDetails) {
this.errorDetails = errorDetails;
}
}
public class DeleteResponseWrapper {
private DeleteResponse deleteResponse;
private ErrorDetails errorDetails;
public DeleteResponse getDeleteResponse() {
return deleteResponse;
}
public void setDeleteResponse(final DeleteResponse deleteResponse) {
this.deleteResponse = deleteResponse;
}
public ErrorDetails getErrorDetails() {
return errorDetails;
}
public void setErrorDetails(final ErrorDetails errorDetails) {
this.errorDetails = errorDetails;
}
}
The AddResponseWrapper & DeleteResponseWrapper are classes that I have created, while the AddResponse and DeleteResponse classes are classes that I inherit from the API that I call.
Now if I make 2 more APi calls, for say Subtract & Multiply operations, I would have to create 2 more POJO classes SubtractResponseWrapper and MultiplyResponseWrapper.
I do not find this solution clean, what I would really like to have is a Generic class, that should be returned from each of these calls and I can avoid the use of multiple Pojo classes.
Try this - however without some sort of heirarchy in your response objects it's possibly going to be not much better than ResponseWrapper<Object>.
public class ResponseWrapper<T> {
private T response;
private ErrorDetails errorDetails;
public T getResponse() {
return response;
}
public void setResponse(final T response) {
this.response = response;
}
public ErrorDetails getErrorDetails() {
return errorDetails;
}
public void setErrorDetails(final ErrorDetails errorDetails) {
this.errorDetails = errorDetails;
}
}
Then your service becomes -
public class Service {
public ResponseWrapper<AddResponse> add(Request request) {
final ResponseWrapper<AddResponse> addResponseWrapper = new ResponseWrapper<AddResponse>();
try {
final AddResponse addResponse = addApi.add(request);
addResponseWrapper.setResponse(addResponse);
} catch (final Exception e) {
addResponseWrapper.setErrorDetails(convert(e));
}
return addResponseWrapper;
}
public ResponseWrapper<Delete> delete(Request request) {
final ResponseWrapper<Delete> deleteResponseWrapper = new ResponseWrapper<Delete>();
try {
final DeleteResponse deleteResponse = deleteApi.delete(request);
deleteResponseWrapper.setResponse(deleteResponse);
} catch (final Exception e) {
deleteResponseWrapper.setErrorDetails(convert(e));
}
return deleteResponseWrapper;
}
}
Without changing the API class you can't go much further on simplification.
I am storing Device objects in a Room database and I'm having a problem with retrieving one of the attributes (temp_values) that is a list of floats. I've followed other advice found on here that says you need a type converter so I've shown that here. When I try to compile I get this error:
"warning: The query returns some columns [temp_values] which are not
used by java.lang.Float. You can use #ColumnInfo annotation on the
fields to specify the mapping. You can suppress this warning by
annotating the method with
#SuppressWarnings(RoomWarnings.CURSOR_MISMATCH). Columns returned by
the query: temp_values. Fields in java.lang.Float: ."
The issue is with the getTempValues query in the DAO, if I comment this out then everything compiles fine. I've included below the Device object, the TemperatureListConverter, and my DAO.
#Entity(tableName = "devices")
#TypeConverters(TemperatureListConverter.class)
public class Device implements Serializable {
#PrimaryKey
#NonNull
#ColumnInfo(name = "serial_num")
private String serialNum;
#ColumnInfo(name = "temp_values")
#TypeConverters(TemperatureListConverter.class)
private List<Float> tempValues;
public Device(String serialNum) {
this.serialNum = serialNum;
this.tempValues = new ArrayList<>();
}
public String getSerialNum() {
return serialNum;
}
public List<Float> getTempValues() {
return tempValues;
}
public void setTempValues(List<Float> tempValues) {
this.tempValues = tempValues;
}
}
public class TemperatureListConverter {
private static final Gson gson = new Gson();
#TypeConverter
public static List<Float> toTempList(String tempValuesString) {
if (tempValuesString == null) {
return Collections.emptyList();
}
Type type = new TypeToken<List<Float>>() {}.getType();
return gson.fromJson(tempValuesString, type);
}
#TypeConverter
public static String fromTempList(List<Float> tempValues) {
return gson.toJson(tempValues);
}
}
#Dao
#TypeConverters(TemperatureListConverter.class)
public interface DeviceDao {
#Query("SELECT * FROM devices")
List<Device> getAllDevices();
#Query("SELECT * FROM devices WHERE serial_num = :serialNum")
Device getDevice(String serialNum);
#Query("SELECT temp_values FROM devices WHERE serial_num = :serialNum")
List<Float> getTempValues(String serialNum);
#Query("UPDATE devices SET temp_values = :tempValues WHERE serial_num = :serialNum")
int setTempValues(String serialNum, List<Float> tempValues);
#Insert
void insert(Device... device);
#Query("DELETE FROM devices WHERE serial_num = :serialNum")
void deleteBySerial(String serialNum);
}
EDIT: I've added my database class here.
#Database(entities = {Device.class}, version = 37, exportSchema = false)
#TypeConverters(TemperatureListConverter.class)
public abstract class DeviceDatabase extends RoomDatabase {
private static final String DB_NAME = "devices_db";
private static DeviceDatabase deviceDb;
// simple singleton
public static DeviceDatabase getDeviceDb(Context context) {
if (deviceDb == null) {
deviceDb = Room.databaseBuilder(context, DeviceDatabase.class, DB_NAME)
.fallbackToDestructiveMigration()
.build();
}
return deviceDb;
}
public abstract DeviceDao getDeviceDao();
public void addDevice(final Device device) {
new Thread(new Runnable() {
#Override
public void run() {
try {
getDeviceDao().insert(device);
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
public void removeDevice(final String serialNum) {
new Thread(new Runnable() {
#Override
public void run() {
try {
getDeviceDao().deleteBySerial(serialNum);
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
public Device getDevice(final String serialNum) {
final Device[] finalDevice = new Device[1];
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try {
finalDevice[0] = getDeviceDao().getDevice(serialNum);
} catch (Exception e) {
e.printStackTrace();
}
}
});
thread.start();
try {
thread.join();
} catch (Exception e) {
e.printStackTrace();
}
return finalDevice[0];
}
public List<Float> getTempValues(final String serialNum) {
final List<Float> finalTempValues = new ArrayList<>();
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try {
finalTempValues.addAll(getDeviceDao().getTempValues(serialNum));
} catch (Exception e) {
e.printStackTrace();
}
}
});
thread.start();
try {
thread.join();
} catch (Exception e) {
e.printStackTrace();
}
return finalTempValues;
}
public void setTempValues(final String serialNum, final List<Float>
tempValues) {
new Thread(new Runnable() {
#Override
public void run() {
try {
getDeviceDao().setTempValues(serialNum, tempValues);
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
}
When Room processes a query that returns a collection type (List<Float> in this case), it tries to generate an implementation for a query that returns multiple rows of the table. That is the typical use, as in your query to get all devices:
#Query("SELECT * FROM devices")
List<Device> getAllDevices();
When a TypeConverter that returns a collection is used in a query intended to yield a single row, you need to give Room a hint of what you want. One way to do that is to wrap the collection value in a class:
public class ListWrapper {
#ColumnInfo(name = "temp_values")
List<Float> tempValues;
}
And change the query to return the wrapper class:
#Query("SELECT temp_values FROM devices WHERE serial_num = :serialNum LIMIT 1")
ListWrapper getTempValues(String serialNum);
I tried this with the code you posted. It eliminates the build error and appears to produce the desired implementation code.
It seems there is some issue while converting a generic type base. Try the following
#TypeConverter
public static List<Float> toTempList(String tempValuesString) {
if (tempValuesString == null) {
return Collections.emptyList();
}
Type type = new TypeToken<List<Float>>() {}.getType();
return gson.fromJson(tempValuesString, type);
}
#TypeConverter
public static String fromTempList(List<Float> tempValues) {
Type type = new TypeToken<List<Float>>() {}.getType();
return gson.toJson(tempValues, type);
}
Can I somehow use doAnswer() when an exception is thrown?
I'm using this in my integration test to get method invocations and the test in configured the #RabbitListenerTest...
#RunWith(SpringRunner.class)
#SpringBootTest
public class MyIT {
#Autowired
private RabbitTemplate rabbitTemplate;
#Autowired
private MyRabbitListener myRabbitListener;
#Autowired
private RabbitListenerTestHarness harness;
#Test
public void testListener() throws InterruptedException {
MyRabbitListener myRabbitListener = this.harness.getSpy("event");
assertNotNull(myRabbitListener);
final String message = "Test Message";
LatchCountDownAndCallRealMethodAnswer answer = new LatchCountDownAndCallRealMethodAnswer(1);
doAnswer(answer).when(myRabbitListener).event(message);
rabbitTemplate.convertAndSend("exchange", "key", message);
assertTrue(answer.getLatch().await(20, TimeUnit.SECONDS));
verify(myRabbitListener).messageReceiver(message);
}
#Configuration
#RabbitListenerTest
public static class Config {
#Bean
public MyRabbitListener myRabbitListener(){
return new MyRabbitListener();
}
}
}
It works ok but when I introduce an Exception being thrown, It doesn't i.e
This works
#RabbitListener(id = "event", queues = "queue-name")
public void event(String message) {
log.info("received message > " + message);
}
This doesn't
#RabbitListener(id = "event", queues = "queue-name")
public void event(String message) {
log.info("received message > " + message);
throw new ImmediateAcknowledgeAmqpException("Invalid message, " + message);
}
Any help appreciated
The LatchCountDownAndCallRealMethodAnswer is very basic
#Override
public Void answer(InvocationOnMock invocation) throws Throwable {
invocation.callRealMethod();
this.latch.countDown();
return null;
}
You can copy it to a new class and change it to something like
private volatile Exception exeption;
#Override
public Void answer(InvocationOnMock invocation) throws Throwable {
try {
invocation.callRealMethod();
}
catch (RuntimeException e) {
this.exception = e;
throw e;
}
finally {
this.latch.countDown();
}
return null;
}
public Exception getException() {
return this.exception;
}
then
assertTrue(answer.getLatch().await(20, TimeUnit.SECONDS));
assertThat(answer.getException(), isInstanceOf(ImmediateAcknowledgeAmqpException.class));
Please open a github issue; the framework should support this out-of-the-box.
My project uses spring framework
WebSocketConfig.java
#Configuration
#EnableWebMvc
#EnableWebSocket
public class WebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer {
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(systemWebSocketHandler(),"/webSocketServer").addInterceptors(new WebSocketHandshakeInterceptor());
registry.addHandler(systemWebSocketHandler(), "/sockjs/webSocketServer").addInterceptors(new WebSocketHandshakeInterceptor())
.withSockJS();
}
#Bean
public WebSocketHandler systemWebSocketHandler(){
return new SystemWebSocketHandler();
}
}
SystemWebSocketHandler.java
public class SystemWebSocketHandler implements WebSocketHandler {
private static final Logger logger;
private static final ArrayList<WebSocketSession> users;
static {
users = new ArrayList<>();
logger = LoggerFactory.getLogger(SystemWebSocketHandler.class);
}
#Autowired
private WebSocketService webSocketService;
#Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
logger.debug("connect to the websocket success......");
users.add(session);
String userName = (String) session.getAttributes().get(Constants.WEBSOCKET_USERNAME);
//查询未读消息
int count = webSocketService.getUnReadNews((String)session.getAttributes().get(Constants.WEBSOCKET_USERNAME));
session.sendMessage(new TextMessage(count+""));
}
#Override
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
}
#Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
logger.debug("websocket connection closed......");
users.remove(session);
}
#Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
logger.debug("websocket connection closed......");
users.remove(session);
}
#Override
public boolean supportsPartialMessages() {
return false;
}
/**
* 给所有在线用户发送消息
*
* #param message
*/
public void sendMessageToUsers(TextMessage message) {
for (WebSocketSession user : users) {
try {
if (user.isOpen()) {
user.sendMessage(message);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 给某个用户发送消息
*
* #param userName
* #param message
*/
public void sendMessageToUser(String userName, TextMessage message) {
for (WebSocketSession user : users) {
if (user.getAttributes().get(Constants.WEBSOCKET_USERNAME).equals(userName)) {
try {
if (user.isOpen()) {
user.sendMessage(message);
}
} catch (IOException e) {
e.printStackTrace();
}
break;
}
}
}
}
my jsp client
if ('WebSocket' in window) {
websocket = new WebSocket("ws://localhost:8080/Origami/webSocketServer");
} else if ('MozWebSocket' in window) {
websocket = new MozWebSocket("ws://localhost:8080/Origami/webSocketServer");
} else {
websocket = new SockJS("http://localhost:8080/Origami/sockjs/webSocketServer");
}
this is my websocket code and it works well
now I want to send messages to the client in a controller ,this is my controller
#Controller
public class AdminController {
static Logger logger = LoggerFactory.getLogger(AdminController.class);
#Autowired(required = false)
private AdminService adminService;
#Autowired(required = false)
private SystemWebSocketHandler systemWebSocketHandler;
#RequestMapping("/auditing")
#ResponseBody
public String auditing(HttpServletRequest request){
String result = "fail";
int id = Integer.parseInt(request.getParameter("id"));
String reason = request.getParameter("reason");
String title = request.getParameter("title");
String username = request.getParameter("username");
News news = new News();
DateTime dateTime = DateTime.now();
news.setNewsTime(dateTime.toDate());
news.setState(0);
news.setUsername(username);
if(reason.equals("")){
result = adminService.auditingById(id,"Y");
news.setNewsContent(String.format(Constants.AUDIT_MESSAGE, username, title, reason));
adminService.addNewsWithUnAudit(news);
}else{
news.setNewsContent(String.format(Constants.UN_AUDIT_MESSAGE,username,title,reason));
result = adminService.addNewsWithUnAudit(news);
result = adminService.auditingById(id, "D");
}
//SystemServerEndPoint serverEndPoint = new SystemServerEndPoint();
int unReadNewsCount = adminService.getUnReadNews(username);
systemWebSocketHandler.sendMessageToUser(username, new TextMessage(unReadNewsCount + ""));
return result;
}
}
I want to call
systemWebSocketHandler.sendMessageToUser(username, new TextMessage(unReadNewsCount + ""));
to send message to the client but systemWebSocketHandler is null
How to inject the systemWebSocketHandler to the controller
or some other ideas to complete the required? Such as the server connect to the websocketserver when it need to send message to the client and closed when it finished
My English is poor, but I'm trying to learn
I have resolved the problem
#Controller
public class AdminController {
#Bean
public SystemWebSocketHandler systemWebSocketHandler() {
return new SystemWebSocketHandler();
}