Axon Event Sourcing not generating table - spring

I am learning how to use the axon framework for event sourcing, seems to be going good but I have gotten stuck on the database configuration for event sourcing. From what I understood from docs / other articles, the database table should automatically generate.
I first tried with H2, the database table was generated by itself, everything working fine.
I added my own mysql db, and the database table is not being created.. I'm getting the error
'Table 'producttest.domain_event_entry' doesn't exist
I was under the impression that the table will generate itself, I must be doing something wrong here, but I'm unsure what. Could anyone help me please?
My code:
ProductAggregate class
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.axonframework.commandhandling.CommandHandler;
import org.axonframework.eventsourcing.EventSourcingHandler;
import org.axonframework.modelling.command.AggregateIdentifier;
import org.axonframework.spring.stereotype.Aggregate;
import java.util.UUID;
import static org.axonframework.modelling.command.AggregateLifecycle.apply;
#NoArgsConstructor
#Aggregate
#Slf4j
public class ProductAggregate {
#AggregateIdentifier
private String productId;
private String productName;
private String productDescription;
#CommandHandler
public ProductAggregate(ProductCreateCommand command){
log.info("handling {}", command);
apply(new ProductCreatedEvent(command.getProductId(),command.getProductName(),command.getProductDescription()));
}
#EventSourcingHandler
public void onProductCreateEvent(ProductCreatedEvent event){
log.info("applying {}", event);
this.productId = event.getProductId();
this.productName = event.getProductName();
this.productDescription = event.getProductDescription();
}
}
ProductCreateCommand
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.axonframework.modelling.command.TargetAggregateIdentifier;
#Data
#NoArgsConstructor
#AllArgsConstructor
public class ProductCreateCommand {
#TargetAggregateIdentifier
private String productId;
private String productName;
private String productDescription;
}
ProductCreatedEvent
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.axonframework.modelling.command.TargetAggregateIdentifier;
#Data
#NoArgsConstructor
#AllArgsConstructor
public class ProductCreatedEvent {
#TargetAggregateIdentifier
private String productId;
private String productName;
private String productDescription;
}
TestRunner
import lombok.extern.slf4j.Slf4j;
import org.axonframework.commandhandling.gateway.CommandGateway;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import java.util.UUID;
#Component
#Slf4j
public class TestRunner implements CommandLineRunner {
private final CommandGateway commandGateway;
#Autowired
public TestRunner(CommandGateway commandGateway) {
this.commandGateway = commandGateway;
}
#Override
public void run(String... args) throws Exception {
log.info("sending product create command");
commandGateway.sendAndWait(new ProductCreateCommand(UUID.randomUUID().toString(), "Oreo", "biscuit"));
log.info("sending product create command");
commandGateway.sendAndWait(new ProductCreateCommand(UUID.randomUUID().toString(), "Oreo", "biscuit"));
}
}
EDIT:
application.properties file
logging.level.root=info
server.port=8090
spring.datasource.url=jdbc:mysql://localhost:3306/producttest
spring.datasource.username=root
spring.datasource.password=password
spring.jpa.hibernate.use-new-id-generator-mappings= false
logs:
2021-01-06 21:44:51.229 INFO 21236 --- [ main] c.u.e.a.Client.TestRunner : sending product create command
2021-01-06 21:44:51.257 INFO 21236 --- [ main] c.u.e.a.Aggregate.ProductAggregate : handling ProductCreateCommand(productId=638643b7-1e4f-45b5-bfa9-1c2fd9360fa3, productName=Oreo, productDescription=biscuit)
2021-01-06 21:44:51.260 INFO 21236 --- [ main] c.u.e.a.Aggregate.ProductAggregate : applying ProductCreatedEvent(productId=638643b7-1e4f-45b5-bfa9-1c2fd9360fa3, productName=Oreo, productDescription=biscuit)
2021-01-06 21:44:51.321 WARN 21236 --- [ main] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 1146, SQLState: 42S02
2021-01-06 21:44:51.321 ERROR 21236 --- [ main] o.h.engine.jdbc.spi.SqlExceptionHelper : Table 'producttest.domain_event_entry' doesn't exist
2021-01-06 21:44:51.333 INFO 21236 --- [ main] ConditionEvaluationReportLoggingListener :
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2021-01-06 21:44:51.346 ERROR 21236 --- [ main] o.s.boot.SpringApplication : Application run failed

In this case, you should instruct your application how to create tables.
You have 2 options:
Tell JPA to do that, adding spring.jpa.hibernate.ddl-auto=create or spring.jpa.hibernate.ddl-auto=update
Use a more robust tool like flyway, liquibase, etc
All the other configs you showed looks fine.

Related

Spring boot different in hibernate vs eclipselink

I'm trying to change from Hibernate to Eclipselink as Jpa provider for spring boot. However, I'm seeing some difference in behaviour between the two.
Eclipselink Configuration
package com.test.test2;
import org.eclipse.persistence.config.PersistenceUnitProperties;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter;
import org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter;
import org.springframework.transaction.jta.JtaTransactionManager;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
#Configuration
public class EclipselinkJpaConfiguration extends JpaBaseConfiguration {
protected EclipselinkJpaConfiguration(DataSource dataSource, JpaProperties
properties, ObjectProvider<JtaTransactionManager> jtaTransactionManager) {
super(dataSource, properties, jtaTransactionManager);
}
#Override
protected AbstractJpaVendorAdapter createJpaVendorAdapter() {
return new EclipseLinkJpaVendorAdapter();
}
#Override
protected Map<String, Object> getVendorProperties() {
Map<String, Object> map = new HashMap<String, Object>();
map.put(PersistenceUnitProperties.WEAVING, "false");
return map;
}
}
Controller
package com.test.test2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
#RestController
public class PersonController {
#Autowired
PersonService personService;
#GetMapping("/test")
public ResponseEntity<String> test() {
return new ResponseEntity<String>(personService.helloWorld(), HttpStatus.OK);
}
#PostMapping("/createNewPerson")
public ResponseEntity<Person> createNewPerson() {
Person res = personService.createNewPerson();
return new ResponseEntity<Person>(res, HttpStatus.OK);
}
#PostMapping("/updatePerson/{id}")
public ResponseEntity<Person> updatePerson(#PathVariable("id") Long id) {
Person res = personService.updatePerson(id);
personService.transAnnotation();
return new ResponseEntity<Person>(res, HttpStatus.OK);
}
}
Service
package com.test.test2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
#Service
public class PersonService {
#Autowired
PersonRepository personRepository;
public String helloWorld() {
return "Hello World!";
}
public Person createNewPerson () {
Person newPerson = new Person();
newPerson.setFirstName("firstName");
newPerson.setLastName("lastName");
return personRepository.save(newPerson);
}
public Person updatePerson(Long id) {
Optional<Person> personOP = personRepository.findById(id);
if (personOP.isPresent()) {
Person person = personOP.get();
person.setFirstName("Update Name");
}
return null;
}
#Transactional(readOnly = true)
public void transAnnotation () {
}
}
Repository
package com.test.test2;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface PersonRepository extends JpaRepository<Person, Long>{
}
Eclipselink behavior
When calling /updatePerson/{id} api, person.firstName is updated to db without calling personRepoitory.save() if the next method is tagged with #Transactional.
As spring repository itself is transactional, even calling a personRepository.findAll() will commit and firstName is updated to db.
Logs
2021-11-24 12:01:06.264 INFO 2868 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8081 (http) with context path ''
2021-11-24 12:01:06.269 INFO 2868 --- [ main] com.test.test2.Test2Application : Started Test2Application in 1.966 seconds (JVM running for 2.227)
2021-11-24 12:01:12.689 INFO 2868 --- [nio-8081-exec-2] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2021-11-24 12:01:12.689 INFO 2868 --- [nio-8081-exec-2] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2021-11-24 12:01:12.689 INFO 2868 --- [nio-8081-exec-2] o.s.web.servlet.DispatcherServlet : Completed initialization in 0 ms
[EL Fine]: sql: 2021-11-24 12:01:12.741--ServerSession(2122837918)--Connection(555991754)--SELECT ID, first_name, last_name FROM TBL_PERSON WHERE (ID = ?)
bind => [1]
[EL Fine]: sql: 2021-11-24 12:01:12.771--ClientSession(1084235622)--Connection(819605412)--UPDATE TBL_PERSON SET first_name = ? WHERE (ID = ?)
bind => [Update Name, 1]
Whereas for Hibernate, the changes are not commited to db unless a save() is called.
I am aware that a if a function is tagged with #Transactional, we do not need to call save() as it will auto commit the changes. However, currently it is tagged only in the next method called.
Any possible causes for this? Could it be due to incorrect configuration?

Detecting the insertion of data into the table and calling the method

I have an issue with detecting adding a new row to the table. I want to trigger a method from some service (Spring boot) when somebody executes an insert query on the database (Postgres)
Somebody told me I can use #Scheduled annotation and check if something was added using a repository. I have to make some changes instantly (by using another method). The scheduled method should run every 5 seconds to do this instantly. Of course, this is a really bad idea because it will kill the database someday and it's not efficient.
How can I do this better?
You can write concrete implementer of org.hibernate.integrator.spi.Integrator. and give it to hibernate.integrator_provider
From ServiceRegistry we can get EventListenerRegistry and then append listener of type EventType.POST_INSERT. More events here.
Main Reference Hibernate Integrator Ref
As per the query, I have also added how to call the service method from the listener class.
Here is how I have done it:
package com.example.samplejdbctemplatecall;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.boot.Metadata;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.event.service.spi.EventListenerGroup;
import org.hibernate.event.service.spi.EventListenerRegistry;
import org.hibernate.event.spi.EventType;
import org.hibernate.event.spi.PostInsertEvent;
import org.hibernate.event.spi.PostInsertEventListener;
import org.hibernate.integrator.spi.Integrator;
import org.hibernate.jpa.boot.spi.IntegratorProvider;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.service.spi.SessionFactoryServiceRegistry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.orm.jpa.HibernatePropertiesCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.util.Collections;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
#RequestMapping(path = "/entity-listener")
#RestController
public class SampleLogController {
private final SampleLogRepository sampleLogRepository;
private final SampleLogEntries sampleLogEntiries;
#Autowired
public SampleLogController(SampleLogRepository sampleLogRepository, SampleLogEntries sampleLogEntiries) {
this.sampleLogRepository = sampleLogRepository;
this.sampleLogEntiries = sampleLogEntiries;
}
// This is usually post method but for test purpose creating new log with uuid random and inserting
#GetMapping(path = "insert")
public SampleLog insertNewEntry() {
final String uuid = UUID.randomUUID().toString();
final SampleLog sampleLog = new SampleLog();
sampleLog.setMessage(uuid);
return sampleLogRepository.save(sampleLog);
}
#GetMapping(path = "list-recent-inserts")
public Map<Long, String> entries() {
return sampleLogEntiries.data();
}
}
#Slf4j
#Component
class HibernateConfig implements HibernatePropertiesCustomizer {
private final JpaEventListenerIntegrator jpaEventListenerIntegrator;
#Autowired
HibernateConfig(JpaEventListenerIntegrator jpaEventListenerIntegrator) {
this.jpaEventListenerIntegrator = jpaEventListenerIntegrator;
}
#Override
public void customize(Map<String, Object> hibernateProperties) {
log.warn("Called hibernate configuration");
hibernateProperties.put("hibernate.integrator_provider",
(IntegratorProvider) () -> Collections.singletonList(jpaEventListenerIntegrator));
}
}
#Configuration
class SampleConfiguration {
#Bean
SampleLogEntries sampleEntries() {
return new SampleLogEntries();
}
}
class SampleLogEntries {
private final ConcurrentMap<Long, String> map = new ConcurrentHashMap<>();
public void add(SampleLog sampleLog) {
this.map.put(sampleLog.getId(), sampleLog.getMessage());
}
public Map<Long, String> data() {
return Collections.unmodifiableMap(this.map);
}
}
#Repository
interface SampleLogRepository extends CrudRepository<SampleLog, Long> {
}
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Entity
class SampleLog {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String message;
}
#Service
#Slf4j
class JpaEventListenerIntegrator implements Integrator, PostInsertEventListener {
private final SampleLogEntries sampleLogEntiries;
#Autowired
JpaEventListenerIntegrator(SampleLogEntries sampleLogEntiries) {
this.sampleLogEntiries = sampleLogEntiries;
}
#Override
public void integrate(Metadata metadata, SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) {
final EventListenerRegistry eventListenerRegistry = serviceRegistry.getService(EventListenerRegistry.class);
eventListenerRegistry
.appendListeners(EventType.POST_INSERT, this);
}
#Override
public void disintegrate(SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) {
final EventListenerRegistry eventListenerRegistry = serviceRegistry.getService(EventListenerRegistry.class);
EventListenerGroup<PostInsertEventListener> eventListenerGroup = eventListenerRegistry
.getEventListenerGroup(EventType.POST_INSERT);
log.info("listener attached were: " + eventListenerGroup.getClass().getSimpleName());
log.error("disintegrate : " + getClass().getCanonicalName());
eventListenerGroup.clearListeners();
}
#Override
public void onPostInsert(PostInsertEvent event) {
log.info("Inserted : " + event.getEntity());
final Object entity = event.getEntity();
if (entity instanceof SampleLog) {
sampleLogEntiries.add((SampleLog) entity);
}
}
#Override
public boolean requiresPostCommitHanding(EntityPersister persister) {
return false;
}
}
The answer from #silentsudo is the best one if you only ever use JPA to update the table in question, and if you only have one process updating it.
The issue is that since you are being notified via the JPA interceptor, you won't be notified of any updates that happen outside of your JAP repository.
If you need these other notifications, then you can use Postgres' LISTEN/NOTIFY without polling by using an alternate postgresql JDBC driver, pgjdbc-ng, which implements async notifications.
With this method, you create a trigger in the database to send the notification, so you will be notified of other's updates as well. See https://www.openmakesoftware.com/postgresql-listen-notify-events-example

Spring AOP - Determine whether method was invoked by #Scheduled

I have a runtime annotation #MyAnnotation, and I would like to write an Aspect that determines whether the test() method below was called by:
Spring's #Scheduled framework
normal method invocation
#SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
#Scheduled(cron = "*/1 * * * * *") // scheduled to invoke every second
#MyAnnotation
public void test() {
// business logic
}
}
aspect code (pointcut + advice)
#Around(value="#annotation(myAnnotation)")
public Object featureToggle(ProceedingJoinPoint joinPoint, MyAnnotation myAnnotation) throws Throwable {
Boolean isInvoked = // TODO - is invoked by #Scheduled or not
}
Inspecting stack traces is always ugly, but of course you can do it:
package de.scrum_master.spring.q65397019;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
#Retention(RetentionPolicy.RUNTIME)
public #interface MyAnnotation {}
package de.scrum_master.spring.q65397019;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
#Component
public class MyComponent {
#Scheduled(fixedRate = 1000)
// #Async
#MyAnnotation
public void doSomething() {}
}
package de.scrum_master.spring.q65397019;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
#SpringBootApplication
#Configuration
#EnableScheduling
#EnableAsync
public class DemoApplication {
public static void main(String[] args) throws InterruptedException {
try (ConfigurableApplicationContext appContext = SpringApplication.run(DemoApplication.class, args)) {
doStuff(appContext);
}
}
private static void doStuff(ConfigurableApplicationContext appContext) throws InterruptedException {
MyComponent myComponent = appContext.getBean(MyComponent.class);
myComponent.doSomething();
Thread.sleep(1000);
myComponent.doSomething();
}
}
package de.scrum_master.spring.q65397019;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import java.util.Arrays;
#Aspect
#Component
public class MyAspect {
#Around("#annotation(myAnnotation)")
public Object advice2(ProceedingJoinPoint joinPoint, MyAnnotation myAnnotation) throws Throwable {
if (
Arrays.stream(new Exception().getStackTrace())
.map(StackTraceElement::toString)
.anyMatch(string -> string.contains("scheduling.support.ScheduledMethodRunnable.run("))
)
System.out.println(joinPoint + " -> scheduled");
else
System.out.println(joinPoint + " -> normal");
return joinPoint.proceed();
}
}
This will print something like:
(...)
2020-12-22 10:00:59.372 INFO 1620 --- [ main] o.s.s.c.ThreadPoolTaskScheduler : Initializing ExecutorService 'taskScheduler'
execution(void de.scrum_master.spring.q65397019.MyComponent.doSomething()) -> scheduled
2020-12-22 10:00:59.456 INFO 1620 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2020-12-22 10:00:59.456 INFO 1620 --- [ main] d.s.spring.q65397019.DemoApplication : Started DemoApplication in 6.534 seconds (JVM running for 8.329)
execution(void de.scrum_master.spring.q65397019.MyComponent.doSomething()) -> normal
execution(void de.scrum_master.spring.q65397019.MyComponent.doSomething()) -> scheduled
execution(void de.scrum_master.spring.q65397019.MyComponent.doSomething()) -> normal
2020-12-22 10:01:00.475 INFO 1620 --- [ main] o.s.s.c.ThreadPoolTaskScheduler : Shutting down ExecutorService 'taskScheduler'
2020-12-22 10:01:00.477 INFO 1620 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
(...)
On Java 9+ you could use the stack walking API which would be more efficient than creating full stack traces from exception instances or querying them from the currently running thread.
Caveat: If you also annotate your scheduled method with #Async, then this will not work anymore because then the asynchronously running method does not have a stack trace in which you could identify that it was triggered by a ScheduledMethodRunnable or an application class.
Maybe you would like to achieve something like that:
#Slf4j
#Component
public class ScheduledTask {
#Scheduled(cron = "0/1 * * * * *")
#ScheduledTaskAnnotation(message = "ScheduledTaskMessage", number = 10)
public void doAction() {
log.debug("Task scheduled");
}
}
#Slf4j
#Aspect
#Component
public class ScheduledTaskAspect {
#Around("execution(public * *(..)) && #annotation(hu.gaszabo.sample.schedule.ScheduledTaskAnnotation)")
public void logScheduledTaskAction(final ProceedingJoinPoint p) {
log.debug("Aspect");
parameters(p).ifPresent(a -> {
log.debug("message: {}", a.message());
log.debug("number: {}", a.number());
});
try {
p.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
}
private Optional<ScheduledTaskAnnotation> parameters(final ProceedingJoinPoint p) {
final Method method = ((MethodSignature) p.getSignature()).getMethod();
return Optional.ofNullable(AnnotationUtils.findAnnotation(method, ScheduledTaskAnnotation.class));
}
}
#Retention(RetentionPolicy.RUNTIME)
#Target(value = { ElementType.METHOD })
public #interface ScheduledTaskAnnotation {
String message() default "Message";
long number() default 0L;
}

Thymeleaf templatespring boot jpa can't get data fom the dabase,404 error

: Resource not found
2019-07-29 05:04:25.834 DEBUG 18656 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed 404 NOT_FOUND
2019-07-29 05:04:25.834 DEBUG 18656 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : "ERROR" dispatch for GET "/error", parameters={}
2019-07-29 05:04:25.834 DEBUG 18656 --- [nio-8080-exec-1] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2019-07-29 05:04:25.834 DEBUG 18656 --- [nio-8080-exec-1] o.s.w.s.m.m.a.HttpEntityMethodProcessor : Using 'application/json', given [*/*] and supported [application/json, application/*+json, application/json, application/*+json]
2019-07-29 05:04:25.834 DEBUG 18656 --- [nio-8080-exec-1] o.s.w.s.m.m.a.HttpEntityMethodProcessor : Writing [{timestamp=Mon Jul 29 05:04:25 PDT 2019, status=404, error=Not Found, message=No message available, (truncated)...]
2019-07-29 05:04:25.835 DEBUG 18656 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Exiting from "ERROR" dispatch, status 404
2019-07-29 05:04:37.741 DEBUG 18656 --- [nio-8080-exec-3] o.s.web.servlet.DispatcherServlet : GET "/favicon.ico", parameters={}
2019-07-29 05:04:37.742 DEBUG 18656 --- [nio-8080-exec-3] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped to ResourceHttpRequestHandler [class path resource [META-INF/resources/], class path resource [resources/], class path resource [static/], class path resource [public/], ServletContext resource [/], class path resource []]
2019-07-29 05:04:37.754 DEBUG 18656 --- [nio-8080-exec-3] o.s.web.servlet.DispatcherServlet : Completed 200 OK
The problem is data already exist in the database but it's not being displayed in HTML table
EmployerController.java
package io.javabrains;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.hibernate.mapping.Index;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import io.javabrains.Entity.Employer;
#Controller
public class EmployerController {
#Autowired
private EmployerService service;
#RequestMapping("/")
public String newForm() {
return "form1";
}
public List<Employer>getAllEmployers()
{
return service.getAllEmployers();
}
#RequestMapping(value="/tables",method=RequestMethod.GET)
public String getAllEmployers(Model model)
{
List<Employer>employers = service.getAllEmployers();
model.addAttribute("Employer",employers);
return "tables";
}
#RequestMapping("/employer/{id}")
public Employer getEmployer(#PathVariable Integer id) {
return service.getEmployers(id);
}
#RequestMapping(method=RequestMethod.POST,value="/employer")
public void addEmployer(#RequestBody Employer employer) {
service.addEmployer(employer);
}
#RequestMapping(method=RequestMethod.PUT,value="/employer/{id}")
public void updateEmployer(#RequestBody Employer employer,#PathVariable int id) {
service.updateEmployer(id,employer);
}
#RequestMapping(method=RequestMethod.DELETE,value="/create/{id}")
public void deleteEmployer(#PathVariable int id)
{
service.deleteEmployer(id);
}
EmployerService.java
package io.javabrains;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import io.javabrains.Entity.Employer;
#Service
public class EmployerService {
#Autowired
private Repository repository;
public List<Employer>getAllEmployers(){
List<Employer>employers = new ArrayList<>();
repository.findAll()
.forEach(employers::add);
return employers;
}
public void addEmployer(Employer employer) {
repository.save(employer);
}
public void updateEmployer(int id, Employer employer) {
repository.save(employer);
}
public void deleteEmployer(int id) {
repository.deleteById(id);
;
}
public Employer getEmployers(int id)
{
return repository.getOne(id);
}
}
Employer.Java
package io.javabrains;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import io.javabrains.Entity.Employer;
#Service
public class EmployerService {
#Autowired
private Repository repository;
public List<Employer>getAllEmployers(){
List<Employer>employers = new ArrayList<>();
repository.findAll()
.forEach(employers::add);
return employers;
}
public void addEmployer(Employer employer) {
repository.save(employer);
}
public void updateEmployer(int id, Employer employer) {
repository.save(employer);
}
public void deleteEmployer(int id) {
repository.deleteById(id);
;
}
public Employer getEmployers(int id)
{
return repository.getOne(id);
}
}
table.html
<tbody>
<tr th:each="$(employers)">
<td th:text="${employers.name}"></td>
<td th:text="${employer.position}"></td>
<td th:text="${employer.office}"></td>
<td th:text="${employer.age}"></td>
<td th:text="${employer.salary}"></td>
</tr>
......
Assuming the method you are testing is this:
#RequestMapping(value="/tables",method=RequestMethod.GET)
public String getAllEmployers(Model model)
{
List<Employer>employers = service.getAllEmployers();
model.addAttribute("Employer",employers);
return "tables";
}
for the tables.html file you should have something like this
<tr th:each="${Employer}">
matching the name attribute with your html file.
Plus, at your service you can just do
repository.findAll()
This guide might help you https://www.baeldung.com/spring-mvc-and-the-modelattribute-annotation

getting below mention Exception while executing the query(Spring Boot+JPA+Hibernate)

This is the error received when try to execute the sample query. Please help me to get out of this.
org.hibernate.hql.internal.ast.QuerySyntaxException: Transaction is not mapped
below is the entity class with mapping
Transaction.java
package org.npst.mb.entity;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import org.springframework.stereotype.Component;
#Entity
#Table(name="transaction")
public class Transaction implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="transactionid")
private int transactionid;
#Column(name="appid")
private int appid;
public int getTransactionid() {
return transactionid;
}
public void setTransactionid(int transactionid) {
this.transactionid = transactionid;
}
public int getAppid() {
return appid;
}
public void setAppid(int appid) {
this.appid = appid;
}
}
Install .java(Spring Boot App Stater)
package org.npst.mb.install;
import org.npst.mb.controller.JobLauncherController;
import org.npst.mb.dao.TransactionDao;
import org.npst.mb.service.TransactionService;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ImportResource;
#SpringBootApplication
#EnableBatchProcessing
#ImportResource("classpath:batchjob.xml")
#ComponentScan(basePackages ={"org.npst.mb.entity.*"},basePackageClasses= {TransactionService.class,TransactionDao.class,JobLauncherController.class})
public class Install {
public static void main(String[] args) {
SpringApplication.run(Install.class, args);
}
}
DAOIMPL(Query to interact with DB)
package org.npst.mb.dao.impl;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.npst.mb.dao.TransactionDao;
import org.npst.mb.entity.Transaction;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
#Transactional
#Repository
public class TransactionDaoImpl implements TransactionDao {
#PersistenceContext
private EntityManager entityManager;
#Override
public boolean addTransaction(Transaction txndata) {
return true;
}
#Override
public long getMaxTid() {
try {
System.out.println("maxtxnid::");
String hql="from Transaction where transactionid > 0";
entityManager.createQuery(hql).getMaxResults();
return 0;
}
catch(Exception sql) {
System.out.println(sql.getMessage());
sql.printStackTrace();
return 0;
}
}
}
application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/test1
spring.datasource.username=root
spring.datasource.password=naveen123
spring.datasource.tomcat.max-wait=20000
spring.datasource.tomcat.max-active=50
spring.datasource.tomcat.max-idle=20
spring.datasource.tomcat.min-idle=15
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQLDialect
spring.jpa.properties.hibernate.id.new_generator_mappings = false
spring.jpa.properties.hibernate.format_sql = true
spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=create
spring.data.jpa.repositories.enabled=true
spring.jpa.open-in-view=true
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
As I understand, #ComponentScan scans and creates beans for the classes annotated #Component, #Service, #Controller,#Repository.
#EntityScan annotation is used to identify JPA entities(persistent classes).
Can you try by adding #EntityScan("org.npst.mb.entity")?

Resources