I need help with connecting my WebSocket to my DB in spring boot.
I know that the DB access happens in the controller but I don't know how.
#Controller
public class ChatController {
#MessageMapping("/chat.register")
#SendTo("/topic/public")
public ChatMessage register(#Payload ChatMessage chatMessage, SimpMessageHeaderAccessor headerAccessor) {
headerAccessor.getSessionAttributes().put("username", chatMessage.getSender());
return chatMessage;
}
#MessageMapping("/chat.send")
#SendTo("/topic/public")
public ChatMessage sendMessage(#Payload ChatMessage chatMessage) {
return chatMessage;
}
}
Where would I connect to the DB
Its not a good idea to add a repository to your controller. A better approach is to add a service layer between controller and database.
#Controller
public class ChatController {
#Autowired
private Chatservice chatservice;
#MessageMapping("/chat.register")
#SendTo("/topic/public")
public ChatMessage register(#Payload ChatMessage chatMessage, SimpMessageHeaderAccessor headerAccessor) {
headerAccessor.getSessionAttributes().put("username", chatMessage.getSender());
chatservice.saveChatMessage(chatMessage); // save this too?
return chatMessage;
}
#MessageMapping("/chat.send")
#SendTo("/topic/public")
public ChatMessage sendMessage(#Payload ChatMessage chatMessage) {
chatservice.saveChatMessage(chatMessage);
return chatMessage;
}
}
#Service
private class ChatService {
#Autowired
private ChatRepository repository;
public void saveChatMessage(ChatMessage chatMessage) {
// do more business stuff here e.g. Mapping to Entity ....
repository.save(chatMessage);
}
}
public interface ChatRepository extends CrudRepository<ChatMessage, Long> {
}
Related
I have a #Service layer class with several methods, which have #Transactional(isolation = Isolation.READ_UNCOMMITTED) annotated queries and #Transactional annotated write transactions.
Sometime deadlock appears on transactions and I can see in SQLServer Profiler deadlock analysis XML, the queries have READ_COMMITED isolation level. How can be isolationlevel setting changed over the transactions? Any help welcomed.
There are repositories like this:
#Repository
public interface mStorageRepository extends AdBaseClientOrgRepository<mStorage, Long> {
#Modifying
#Query("UPDATE mStorage s SET s.qtyonhand = s.qtyonhand + ?2, s.updated = current_timestamp WHERE s.id = ?1")
void updateqtyBymStorageid(long id, BigDecimal movementqty);
#Query("SELECT s FROM mStorage s WHERE s.locator.id = ?1 AND s.stockAlert = ?2 order by s.datelastinventory")
Iterable<mStorage> getByLocatorAndStockAlert(long mLocatorId, String stockAlert);
.
.
.
}
There are date service layers like this:
#Service
public class mStorageService extends AdBaseClientOrgService<mStorage, mStorageRepository> {
#Autowired
public mStorageService(Logger logger, TimeService timeService, MessageService messageService) {
super(logger, timeService, messageService);
}
#Override
#Autowired
public void setRepo(mStorageRepository repo) {
this.repo = repo;
}
#Transactional
public void updateqtyBymStorageid(long id, BigDecimal movementqty) {
logger.debug("start updateqtyBymStorageid : {} , {}",id,movementqty);
repo.updateqtyBymStorageid(id, movementqty);
logger.debug("end updateqtyBymStorageid : {} , {}",id,movementqty);
}
#Transactional(isolation = Isolation.READ_UNCOMMITTED)
public Iterable<mStorage> getByLocatorAndStockAlert(long locatorId, StockAlert stockAlert) {
Iterable<mStorage> ret = this.repo.getByLocatorAndStockAlert(locatorId, stockAlert.toString());
getLazyProperties(ret);
return ret;
}
.
.
.
}
There are several business logic service layer implementations also:
#Service
public class BaseProductionPartsUsageService {
#Autowired
public BaseProductionPartsUsageService(final Logger logger) {
this.logger = logger;
logger.info("BaseProductionPartsUsageService initialized");
}
protected Logger logger;
#Autowired
public void setStorageService(mStorageService storageService) {
this.storageService = storageService;
}
protected mStorageService storageService;
// calls several data service methods in method annotated with #Transactional
.
.
.
}
Sometimes we have deadlock and when we check the details in SQLServer profiler we can see that the query method, which was annotated by READ_UNCOMMITED is READ_COMMITED in profiler xml.
Using Spring boot 1.5.6.RELEASE.
I have the following mongo document base class:
#Document(collection="validation_commercial")
public abstract class Tier {
#Id
private String id;
#DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
private Date created;
#Field("tran")
private Tran tran;
public Tier() {
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
this.created = created;
}
public Tran getTran() {
return tran;
}
public void setTran(Tran tran) {
this.tran = tran;
}
}
which is then extended:
public class Tier1 extends Tier {
#Field("tier1")
private Tier1Programs tier1;
public Tier1() {
this.tier1 = new Tier1Programs();
}
public Tier1Programs getTier1() {
return tier1;
}
public void setTier1(Tier1Programs tier1) {
this.tier1 = tier1;
}
}
which in turn is extended:
public class Tier2 extends Tier1 {
#Field("tier2")
private Tier2Programs tier2;
public Tier2() {
this.tier2 = new Tier2Programs();
}
public Tier2Programs getTier2() {
return tier2;
}
public void setTier2(Tier2Programs tier2) {
this.tier2 = tier2;
}
}
There is a Tier1 Supervisor (Spring Boot Application) that uses the Tier1 class within the MongoRepository interface:
public interface Tier1Repository extends MongoRepository<Tier1,String>{}
for retrieving and saving - no issue.
I then have a Tier2 Supervisor (Spring Boot Application) that uses a Tier1 Repository (for retrieving the Tier1 document and a Tier2 Repository for saving the Tier2 document:
#Repository("tier1Repository")
public interface Tier1Repository extends MongoRepository<Tier1,String>{}
#Repository("tier2Repository")
public interface Tier2Repository extends MongoRepository<Tier2,String>{}
My service is:
#Service
public class TierService {
#Qualifier("tier1Repository")
#Autowired
private final Tier1Repository tier1Repository;
#Qualifier("tier2Repository")
#Autowired
private final Tier2Repository tier2Repository;
public TierService(#Qualifier("tier1Repository") Tier1Repository tier1Repository, #Qualifier("tier2Repository") Tier2Repository tier2Repository) {
this.tier1Repository = tier1Repository;
this.tier2Repository = tier2Repository;
}
public Tier1 findOne(String id) {
return tier1Repository.findOne(id);
}
public void SaveTier(Tier2 tier) {
tier2Repository.save(tier);
}
public Tier1Repository getTier1Repository() {
return tier1Repository;
}
public Tier2Repository getTier2Repository() {
return tier2Repository;
}
}
and finally the app:
#EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class, JdbcTemplateAutoConfiguration.class})
#Configuration
#ComponentScan(basePackages = {"com.k12commercial.tier2supervisor"})
#ImportResource("classpath:application-context.xml")
public class Application implements CommandLineRunner {
#Autowired
private IReceiver raBidNetPriceReceiver;
#Autowired
private UdyDataSourceFactory udyDSRegistry;
public static void main(String[] args) throws InterruptedException {
try {
SpringApplication.run(Application.class, args);
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void run(String... args) throws Exception {
raBidNetPriceReceiver.processTierMessages();
exit(0);
}
}
When I run the Tier2 Supervisor from the command line I get the following error:
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'tierService' defined in URL
[jar:file:/opt/java-commandline/tier2supervisor-1.0.jar!/BOOT-INF/classes!/com/k12commercial/tier2supervisor/service/TierService.class]: Unsatisfied dependency expressed through constructor parameter 1; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'tier2Repository': Invocation of init method failed; nested exception is org.springframework.data.mapping.model.MappingException: Ambiguous field mapping detected! Both private final java.lang.reflect.Type org.springframework.data.util.TypeDiscoverer.type and private final java.lang.Class org.springframework.data.util.ClassTypeInformation.type map to the same field name type! Disambiguate using #Field annotation!
I am not sure if the issue is Tier2 extending Tier1 (did try putting #Document tag above Tier1 and Tier2 with no change). I think I have marked the relevant fields so don't understand the need to disambiguate. I thought the issue was having 2 repositories (Spring Boot not knowing which one to DI) so removed the Tier1Repository - didn't work. Tried better qualifying the repositories but still got the same error. I made Tier1 and Tier2 #Transient and that got rid of the message but also removed the tier1 section in the mongo document - so wrong correction.
Thinking it is an annotation fix but not seeing it...
Please advise - thank you.
Sorry for the delay (I got pulled away to work on something else) and thank you to those who responded.
The issue was I had a MongoTemplate in my Tier level programs e.g.Tier2Programs (sub library) which Spring Boot was trying to autowire.
By moving the Mongo (CRUD) requirements to the supervisor level (I also replaced the Repositories with one MongoTemplate to simplify) I removed the ambiguity. (I also removed the Service class).
The code is contained with the RaBidNetReciever class
#Component
public class RaBidNetPriceReceiver extends BaseReceiver implements IReceiver, ApplicationEventPublisherAware {
private static final Logger LOGGER = LoggerFactory.getLogger(RaBidNetPriceReceiver.class);
private final RabbitTemplate raBidNetPriceRabbitTemplate;
public RaBidNetPriceReceiver(MongoTemplate mongoTemplate, RabbitTemplate raBidNetPriceRabbitTemplate) {
super(mongoTemplate);
this.raBidNetPriceRabbitTemplate = raBidNetPriceRabbitTemplate;
}
#Transactional
public void processTierMessages() {
try {
while (true) {
gson = getGsonBuilder().create();
byte[] body = (byte[]) raBidNetPriceRabbitTemplate.receiveAndConvert();
if (body == null) {
setFinished(true);
break;
}
tier1Message = gson.fromJson(new String(body), Tier1Message.class);
// document a 'Tier1' type so retrieve Tier1 first...
Tier1 tier1 = mongoTemplate.findById(tier1Message.getId(), Tier1.class);
Tier2Message tier2Message = new Tier2Message(tier1Message.getTran(), tier1Message.getId());
Tier2Process tierProcess = getTierProcess(tier2Message.getTran().getK12ArchitectureId());
Tier2 tier2 = new Tier2();
tier2.setId(tier1.getId());
tier2.setTier1Programs(tier1.getTier1Programs());
tier2.setCreated(tier1.getCreated());
tier2.setTran(tier1.getTran());
tierProcess.setTier(tier2);
tier2 = tier2.getTier2Programs().getRaBidNetPriceProgram().process(tierProcess);
mongoTemplate.save(tier2);
if (tier2.getTier2Programs().getRaBidNetPriceProgram().isFinished()) {
// publish event
publisher.publishEvent(new ProgramEvent(this, "FINISHED", tier2Message));
}
}
} catch (Exception e) {
LOGGER.error("id: " + tier1Message.getId() + " " + e.getMessage());
}
}
#Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.publisher = applicationEventPublisher;
}
}
Thank you,
I have referred to ->
Spring MVC how to display data from database into a table
My aim is to try and understand what is the syntax and process to create queries, and whether I'm correct.
The following code tries to display all Order entities.
#AutoWired
private OrderService orderService;
#RequestMapping("/")
//public String orderPage(Model model) {
// model.addAttribute("orderList", SomeApp.getStore().getOrderList());
// return "form/orderPage"};
// this is the code I am trying to translate below
#ResponseBody
public List<order> orderList(Map<String, Object> model) {
List<order> orderList = OrderService.findALl();
//orderRepository.findAll <- where does this come in? is it needed at all
return orderList;
}
If the Service layer is not being used, in my Repo do I only state
List<Order> findAll();
Additional Info:
Service layer is not used in this project and instead business logic will be in Controller (partly why I'm confused as to what code goes where)
You need to #Autowire the OrderRepository so that you can call orderRepository.findAll() in your Controller as shown below. For that, you also need to define the OrderRepository and Order Entity classes.
Controller:
#Controller
public class Controller {
#AutoWired
private OrderRepository orderRepository;
#RequestMapping("/")
#ResponseBody
public List<order> orderList(Map<String, Object> model) {
List<order> orderList = OrderService.findALl();
orderRepository.findAll();
return orderList;
}
}
Repository:
#Repository
public interface OrderRepository extends JpaRepository<Order, Integer> {
public Order findAll();
}
Entity:
#Entity
public class Order {
//add your entity fields with getters and setters
}
You can refer here for spring-data-jpa basic example.
I am trying to use Spring-AOP/AspectJ on the methods in a class annotated with #Transactional. So, I have two model DAO classes like this:
#Transactional
#Repository
public class ModelDAO {
public void save() {
}
}
#Transactional
#Repository
public class AnotherModelDAO {
public void save() {
}
}
And then an Aspect like:
#Aspect
public class ModelAspect {
#Around("publicMethod() && isModelClassSaveCalled()")
public Object doAspect(ProceedingJoinPoint joinPoint) throws Throwable {
joinPoint.proceed();
anotherModelDAO.save();
}
}
So, my question is: Is it possible to call model.save() and anotherModel.save() to be called in same transaction context through aspect as mentioned above?
Any help will be much appreciated.
I have a Jersey 2 application. A resource is using one of my service class using #Inject and all goes ok.
The binding configuration:
class MyApp extends ResourceConfig {
register(new AbstactBinder() {
#Override
protected void configure() {
bind(PrimaryService.class).to(PrimaryService.class);
}
});
}
The resource class:
#Path("/example");
class Resource {
#Inject
PrimaryService service;
#GET
public Response get() {
//Consume service class
}
}
Everything works as expected.
BUT what if I need another #Inject in the PrimaryService class?
I added the binding:
bind(PrimaryService.class).to(PrimaryService.class);
bind(SecondaryService.class).to(SecondaryService.class);
And, in the PrimaryService class, I have:
class PrimaryService {
#Inject
SecondaryService secondary;
public void someMethod() {
//Consume secondary
}
}
But, I have an exception telling me that dependency is usatisfied.
I'm using Jersey2 on Google AppEngine instance.