My multi-tenant application needs to periodically check a set of SFTP folders for an ingestion file. The SFTP folders and parameters are defined in my application.properties file, and the number is dynamic.
ingestion.carriers=carrier1,carrier2
ingestion.carrier1=sftp
ingestion.carrier1.sftp.host=localhost
ingestion.carrier1.sftp.username=sftp
ingestion.carrier1.sftp.password=sftp
ingestion.carrier1.sftp.remotedir=carrier1
ingestion.carrier1.sftp.localdir=sftp/carrier1
ingestion.carrier1.sftp.archivedir=sftp/carrier1/archive
ingestion.carrier1.sftp.errordir=sftp/carrier1/error
ingestion.carrier1.ping=7000
ingestion.carrier2=sftp
ingestion.carrier2.sftp.host=localhost
ingestion.carrier2.sftp.username=sftp
ingestion.carrier2.sftp.password=sftp
ingestion.carrier2.sftp.remotedir=carrier2
ingestion.carrier2.sftp.localdir=sftp/carrier2
ingestion.carrier2.sftp.archivedir=sftp/carrier2/archive
ingestion.carrier2.sftp.errordir=sftp/carrier2/error
ingestion.carrier2.pingFrequency=13000
I need to dinamically create all the necessary beans to enable spring integration flow. To do so, I've tried to set up a BeanFactoryPostProcessor, as I cannot declare the beans in a "static" way. This processor is thought to be configured, in future, with different methods to retrieve the file: because of this, the actual creation of beans is delegated to another class.
This is the post processor...
package mypkg.batch.config.integration;
import mypkg.batch.config.integration.factory.SFTPBeansFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import java.util.List;
#Component
public class IngestionBeanConfigurator implements BeanFactoryPostProcessor {
public static final Logger LOG = LoggerFactory.getLogger(IngestionBeanConfigurator.class);
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory fact) throws BeansException {
Environment env = fact.getBean(Environment.class);
String carriersList = env.getProperty("ingestion.carriers");
if (carriersList == null) {
LOG.info("No ingestion has been defined");
return;
}
List<String> carriers = List.of(carriersList.split(","));
for (String carrier : carriers) {
String carrierMethod = env.getProperty("ingestion.%s".formatted(carrier));
if (carrierMethod != null) {
if ("sftp".equals(carrierMethod)) {
new SFTPBeansFactory(carrier, env).loadBeans(fact);
} else {
LOG.warn("Invalid carrier method {} for carrier {}", carrierMethod, carrier);
}
}
}
}
}
... and this is the class creating SFTP beans
package com.eyemed.foodogs.batch.config.integration.factory;
import com.eyemed.foodogs.model.exception.MembersMessageHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.integration.dsl.IntegrationFlows;
import org.springframework.integration.dsl.MessageChannelSpec;
import org.springframework.integration.dsl.Pollers;
import org.springframework.integration.dsl.StandardIntegrationFlow;
import org.springframework.integration.dsl.context.IntegrationFlowContext;
import org.springframework.integration.file.filters.AcceptOnceFileListFilter;
import org.springframework.integration.sftp.filters.SftpSimplePatternFileListFilter;
import org.springframework.integration.sftp.inbound.SftpInboundFileSynchronizer;
import org.springframework.integration.sftp.inbound.SftpInboundFileSynchronizingMessageSource;
import org.springframework.integration.sftp.session.DefaultSftpSessionFactory;
import java.io.File;
import java.math.BigInteger;
import java.util.concurrent.TimeUnit;
public class SFTPBeansFactory implements BeanFactory {
public static final Logger LOG = LoggerFactory.getLogger(SFTPBeansFactory.class);
private final String carrierId;
private final String sftpHost;
private final String sftpUsername;
private final String sftpPassword;
private final String sftpRemoteDir;
private final String sftpLocalDir;
private final String sftpArchiveDir;
private final String sftpErrorDir;
private final BigInteger pingFrequency;
public SFTPBeansFactory(final String carrierId, final Environment props) {
String prefix = "ingestion.%s".formatted(carrierId);
this.carrierId = carrierId;
this.sftpHost = props.getProperty("%s.sftp.host".formatted(prefix));
this.sftpUsername = props.getProperty("%s.sftp.username".formatted(prefix));
this.sftpPassword = props.getProperty("%s.sftp.password".formatted(prefix));
this.sftpRemoteDir = props.getProperty("%s.sftp.remotedir".formatted(prefix));
this.sftpLocalDir = props.getProperty("%s.sftp.localdir".formatted(prefix));
this.sftpArchiveDir = props.getProperty("%s.sftp.archivedir".formatted(prefix));
this.sftpErrorDir = props.getProperty("%s.sftp.errordir".formatted(prefix));
String pingFrequencyString = props.getProperty("%s.ping".formatted(prefix));
if (pingFrequencyString != null) {
this.pingFrequency = new BigInteger(pingFrequencyString);
} else {
this.pingFrequency = BigInteger.valueOf(3600000);
}
}
public void loadBeans(ConfigurableBeanFactory fact) {
DefaultSftpSessionFactory sf = _buildSessionFactory();
SftpInboundFileSynchronizer sync = _buildInboundFileSynchronizer(sf);
fact.registerSingleton("sftp-sync-%s".formatted(carrierId), sync);
SftpInboundFileSynchronizingMessageSource src = _buildMessageSource(sync);
MembersMessageHandler handler = new MembersMessageHandler(carrierId, fact.getBean(JobLauncher.class), fact.getBean("readMembersJob", Job.class));
String beanName = "sftp-flow-%s".formatted(carrierId);
String channelName = "sftp-ingestion-channel-%s".formatted(carrierId);
LOG.info("Creating bean %s based on channel %s".formatted(beanName, channelName));
StandardIntegrationFlow flow = IntegrationFlows
.from(src, c -> c.poller(Pollers.fixedRate(pingFrequency.longValue(), TimeUnit.MILLISECONDS, 0)))
.channel(channelName)
.handle(handler)
.get();
IntegrationFlowContext ctx = fact.getBean(IntegrationFlowContext.class);
ctx.registration(flow).id(beanName).autoStartup(true).register();
flow.start();
}
private SftpInboundFileSynchronizingMessageSource _buildMessageSource(SftpInboundFileSynchronizer sync) {
var src = new SftpInboundFileSynchronizingMessageSource(sync);
src.setLocalDirectory(new File(sftpLocalDir));
src.setAutoCreateLocalDirectory(true);
src.setLocalFilter(new AcceptOnceFileListFilter<>());
return src;
}
private SftpInboundFileSynchronizer _buildInboundFileSynchronizer(DefaultSftpSessionFactory sf) {
var sync = new SftpInboundFileSynchronizer(sf);
sync.setDeleteRemoteFiles(true);
sync.setRemoteDirectory(sftpRemoteDir);
sync.setFilter(new SftpSimplePatternFileListFilter("*.csv"));
sync.setLocalFilenameGeneratorExpressionString(
"#this.substring(0, #this.length - 4) + '_%s_' + new com.eyemed.foodogs.application.util.TimestampProvider().currentTimestamp() + '.txt'".formatted(carrierId));
return sync;
}
private DefaultSftpSessionFactory _buildSessionFactory() {
var sf = new DefaultSftpSessionFactory();
sf.setHost(sftpHost);
sf.setUser(sftpUsername);
sf.setPassword(sftpPassword);
sf.setPort(22);
sf.setAllowUnknownKeys(true);
return sf;
}
}
Unfortunately, this doesn't seem to work: SFTP files are not read and remain sadly in the source folder. The local SFTP works, as the previous version with the "static" beans used to work correctly.
Also, I do not see errors in the log
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.5.5)
2022-10-18 11:42:15.396 INFO 8226 --- [ main] com.eyemed.foodogs.application.App : Starting App using Java 17 on A-M-L-MUTI.local with PID 8226 (/Users/lorenzomuti/Repositories/FooDogs/backend/foodogsbootapplication/target/classes started by lorenzomuti in /Users/lorenzomuti/Repositories/FooDogs/backend/foodogsbootapplication)
2022-10-18 11:42:15.399 INFO 8226 --- [ main] com.eyemed.foodogs.application.App : The following profiles are active: dev
2022-10-18 11:42:17.988 INFO 8226 --- [ main] c.e.f.b.c.i.factory.SFTPBeansFactory : Creating bean sftp-flow-carrier1 based on channel sftp-ingestion-channel-carrier1
2022-10-18 11:42:18.028 INFO 8226 --- [ main] c.e.f.b.c.i.factory.SFTPBeansFactory : Creating bean sftp-flow-carrier2 based on channel sftp-ingestion-channel-carrier2
2022-10-18 11:42:18.038 INFO 8226 --- [ main] faultConfiguringBeanFactoryPostProcessor : No bean named 'errorChannel' has been explicitly defined. Therefore, a default PublishSubscribeChannel will be created.
2022-10-18 11:42:18.049 INFO 8226 --- [ main] faultConfiguringBeanFactoryPostProcessor : No bean named 'integrationHeaderChannelRegistry' has been explicitly defined. Therefore, a default DefaultHeaderChannelRegistry will be created.
2022-10-18 11:42:18.311 INFO 8226 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.integration.config.IntegrationManagementConfiguration' of type [org.springframework.integration.config.IntegrationManagementConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2022-10-18 11:42:18.322 INFO 8226 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'integrationChannelResolver' of type [org.springframework.integration.support.channel.BeanFactoryChannelResolver] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2022-10-18 11:42:18.324 INFO 8226 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'integrationDisposableAutoCreatedBeans' of type [org.springframework.integration.config.annotation.Disposables] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2022-10-18 11:42:18.659 INFO 8226 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2022-10-18 11:42:18.675 INFO 8226 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2022-10-18 11:42:18.676 INFO 8226 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.53]
2022-10-18 11:42:18.816 INFO 8226 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2022-10-18 11:42:18.816 INFO 8226 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 3337 ms
2022-10-18 11:42:18.892 DEBUG 8226 --- [ main] o.s.w.f.CommonsRequestLoggingFilter : Filter 'logFilter' configured for use
2022-10-18 11:42:19.474 INFO 8226 --- [ main] c.e.f.application.config.UnionPayConfig : Activating UnionPay Service logger
2022-10-18 11:42:20.478 INFO 8226 --- [ main] o.s.b.c.r.s.JobRepositoryFactoryBean : No database type set, using meta data indicating: MYSQL
2022-10-18 11:42:20.501 INFO 8226 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : No TaskExecutor has been set, defaulting to synchronous executor.
2022-10-18 11:42:20.730 INFO 8226 --- [ main] o.s.s.web.DefaultSecurityFilterChain : Will secure any request with [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter#7a0f06ad, org.springframework.security.web.context.SecurityContextPersistenceFilter#3e9fb485, org.springframework.security.web.header.HeaderWriterFilter#580ffea, org.springframework.security.web.authentication.logout.LogoutFilter#7fe87c0e, org.springframework.security.web.authentication.www.BasicAuthenticationFilter#c82d925, org.springframework.security.web.savedrequest.RequestCacheAwareFilter#38dbeb39, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter#48106381, org.springframework.security.web.authentication.AnonymousAuthenticationFilter#1fa9692b, org.springframework.security.web.session.SessionManagementFilter#2ffb0d10, org.springframework.security.web.access.ExceptionTranslationFilter#f76872f, org.springframework.security.web.access.intercept.FilterSecurityInterceptor#6df2a206]
2022-10-18 11:42:20.849 INFO 8226 --- [ main] o.s.i.endpoint.EventDrivenConsumer : Adding {logging-channel-adapter:_org.springframework.integration.errorLogger} as a subscriber to the 'errorChannel' channel
2022-10-18 11:42:20.849 INFO 8226 --- [ main] o.s.i.channel.PublishSubscribeChannel : Channel 'application.errorChannel' has 1 subscriber(s).
2022-10-18 11:42:20.849 INFO 8226 --- [ main] o.s.i.endpoint.EventDrivenConsumer : started bean '_org.springframework.integration.errorLogger'
2022-10-18 11:42:20.867 INFO 8226 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2022-10-18 11:42:20.887 INFO 8226 --- [ main] com.eyemed.foodogs.application.App : Started App in 6.399 seconds (JVM running for 7.221)
Is my approach correct? Should I do something more? Please help me, as I do not know where to bump my head :)
Consider to move you logic into some #PostConstruct method instead.
I think getting access to bean factory and starting beans from the BeanFactoryPostProcessor is too early.
Also consider to use a SftpInboundChannelAdapterSpec instead of manual creation. And don't register those beans manually - rely on the IntegrationFlowContext.
I wanted to suggest you to look into this also: https://docs.spring.io/spring-integration/docs/current/reference/html/sftp.html#sftp-rotating-server-advice.
But looks like you use that carrierId in the message handler. Although it may come as a message header. Not sure also if you really need that .channel(channelName) in between.
Related
I am trying to add a prefix or suffix in the controller at the method level on top of GET, POST, PUT, DELETE mappings.
Controller class
#RestController
#RequestMapping("/something")
public class SomeController {
#PutMapping("/some/path/")
public ResponseEntity<ApiResponse<String>> someMethod() {
....
}
...
}
So, basically, the above request URL should be something like : http://localhost:8080/something/some/path/
Now, I just want to add some prefix or suffix whatever is feasible to the request URL which will be something like : http://localhost:8080/something/read/some/path/ or http://localhost:8080/something/some/path/read/ the extra "/read" which needs to be added to the request URL as a prefix or suffix. I can do this directly by adding this to the PutMapping value, but I want to decorate it somewhat using annotation like #Read
So, the updated Controller class will be like
#RestController
#RequestMapping("/something")
public class SomeController {
#Read
#PutMapping("/some/path/")
public ResponseEntity<ApiResponse<String>> someMethod() {
....
}
...
}
and the same way updated request URL will be like : http://localhost:8080/something/read/some/path/
I am unable to find a better way to do this. Till now I have only achieved adding a class-level prefix using custom annotation.
Can anyone please help with the above requirement.?
Thank you !!
I am also curious to know whether is achievable or not even?
Using such way of path extension make your code less understandable. (maybe you should read more about RESTful API) But spring can do almost everything you want.
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcRegistrations;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
import java.util.stream.Stream;
#SpringBootApplication
public class DemoApplication {
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface Read {
}
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface Write {
}
#Bean
public WebMvcRegistrations webMvcRegistrations() {
return new WebMvcRegistrations() {
#Override
public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
return new RequestMappingHandlerMapping() {
#Override
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
RequestMappingInfo defaultRequestMappingInfo = super.getMappingForMethod(method, handlerType);
if (defaultRequestMappingInfo == null) {
return null;
}
String pathSuffix;
if (method.isAnnotationPresent(Read.class)) {
pathSuffix = "read";
} else if (method.isAnnotationPresent(Write.class)) {
pathSuffix = "write";
} else {
return defaultRequestMappingInfo;
}
//extend path by mutating configured request mapping info
RequestMappingInfo.Builder mutateBuilder = defaultRequestMappingInfo.mutate();
mutateBuilder.paths(
defaultRequestMappingInfo.getPatternValues().stream()
.map(path -> path + "/" + pathSuffix)
.toArray(String[]::new)
);
return mutateBuilder.build();
}
};
}
};
}
#RestController
#RequestMapping("/books")
public static class BooksController {
#Read
#GetMapping("/{id}")
public String readBook(#PathVariable("id") String bookId) {
return bookId;
}
}
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
Extension point is here, you can change path like you want.
Example:
request: http://localhost:8080/books/asd
response: 404
output:
2022-06-27 10:49:48.671 DEBUG 8300 --- [nio-8080-exec-2] com.example.demo.DemoApplication$1$1 : Mapped to org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#errorHtml(HttpServletRequest, HttpServletResponse)
request: http://localhost:8080/books/asd/read
response: asd
output:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.7.0)
2022-06-27 10:48:53.622 INFO 8300 --- [ main] com.example.demo.DemoApplication : Starting DemoApplication using Java 1.8.0_312 on DESKTOP with PID 8300 ()
2022-06-27 10:48:53.624 DEBUG 8300 --- [ main] com.example.demo.DemoApplication : Running with Spring Boot v2.7.0, Spring v5.3.20
2022-06-27 10:48:53.625 INFO 8300 --- [ main] com.example.demo.DemoApplication : No active profile set, falling back to 1 default profile: "default"
2022-06-27 10:48:54.227 INFO 8300 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2022-06-27 10:48:54.233 INFO 8300 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2022-06-27 10:48:54.233 INFO 8300 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.63]
2022-06-27 10:48:54.298 INFO 8300 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2022-06-27 10:48:54.298 INFO 8300 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 643 ms
2022-06-27 10:48:54.473 DEBUG 8300 --- [ main] com.example.demo.DemoApplication$1$1 : 3 mappings in 'requestMappingHandlerMapping'
2022-06-27 10:48:54.536 INFO 8300 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2022-06-27 10:48:54.543 INFO 8300 --- [ main] com.example.demo.DemoApplication : Started DemoApplication in 1.199 seconds (JVM running for 1.827)
2022-06-27 10:49:01.196 INFO 8300 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2022-06-27 10:49:01.196 INFO 8300 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2022-06-27 10:49:01.197 INFO 8300 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 1 ms
2022-06-27 10:49:01.210 DEBUG 8300 --- [nio-8080-exec-1] com.example.demo.DemoApplication$1$1 : Mapped to com.example.demo.DemoApplication$BooksController#readBook(String)
dependencies
org.springframework.boot:spring-boot-starter-web
application.properties
logging.level.com.example.demo=debug
I am trying to make a small rest-api in springboot but i always get this errorerror 404
It is connected to a database but when I try to exceute a GET from Post I also have 404 error
This is my structure
project structure
My pom
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>Clientix</groupId>
<artifactId>Ruben_DeNicolas</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Clientix</name>
<description>TFG</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Repository
package repositories;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import models.ClientesModel;
#Repository
public interface ClientesRepository extends CrudRepository<ClientesModel, Integer>{
}
Service
package services;
import java.util.ArrayList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import models.ClientesModel;
import repositories.ClientesRepository;
#Service
public class ClientesService {
#Autowired
ClientesRepository clientesRepository;
public ArrayList<ClientesModel>getClientes()
{
return(ArrayList<ClientesModel>)clientesRepository.findAll();
}
public ClientesModel insert(ClientesModel c)
{
return clientesRepository.save(c);
}
}
Model
package models;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name = "clientes")
public class ClientesModel {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(unique = true, nullable = false)
private Integer idCliente;
private String NombreCliente;
private String CIFNIF;
private String DireccionFacturacion;
public ClientesModel(String NombreCliente) {
this.NombreCliente = NombreCliente;
}
public ClientesModel(int idCliente, String NombreCliente, String CIFNIF, String DireccionFacturacion) {
this.idCliente = idCliente;
this.NombreCliente = NombreCliente;
this.CIFNIF = CIFNIF;
this.DireccionFacturacion = DireccionFacturacion;
}
public Integer getIdCliente() {
return idCliente;
}
public void setIdCliente(Integer idCliente) {
this.idCliente = idCliente;
}
public String getNombreCliente() {
return NombreCliente;
}
public void setNombreCliente(String nombreCliente) {
NombreCliente = nombreCliente;
}
public String getCIFNIF() {
return CIFNIF;
}
public void setCIFNIF(String cIFNIF) {
CIFNIF = cIFNIF;
}
public String getDireccionFacturacion() {
return DireccionFacturacion;
}
public void setDireccionFacturacion(String direccionFacturacion) {
DireccionFacturacion = direccionFacturacion;
}
}
Controller
package controllers;
import java.util.ArrayList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import models.ClientesModel;
import services.ClientesService;
#RestController
#RequestMapping(value = "/clientes",produces="application/json")
public class ClientesController {
#Autowired
ClientesService clientesService;
//OBTENER TODOS LOS CLIENTES
//#RequestMapping(value = "/",method = RequestMethod.GET)
#GetMapping()
public ArrayList<ClientesModel> getClientes()
{
return clientesService.getClientes();
}
//INSTERTAR CLIENTE
#PostMapping
public ClientesModel insert(#RequestBody ClientesModel c)
{
return this.clientesService.insert(c);
}
}
```
Clientix application
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
#SpringBootApplication
#ComponentScan()
public class ClientixApplication {
public static void main(String[] args) {
SpringApplication.run(ClientixApplication.class, args);
}
}
This is the SpringBoot log
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.6.6)
2022-04-06 16:05:32.098 INFO 15728 --- [ main] C.Ruben_DeNicolas.ClientixApplication : Starting ClientixApplication using Java 17.0.2 on DESKTOP-0EJNGE1 with PID 15728 (C:\Users\Rubén\Desktop\TestSpringBoot\Ruben_DeNicolas (1)\Ruben_DeNicolas\target\classes started by Rubén in C:\Users\Rubén\Desktop\TestSpringBoot\Ruben_DeNicolas (1)\Ruben_DeNicolas)
2022-04-06 16:05:32.101 INFO 15728 --- [ main] C.Ruben_DeNicolas.ClientixApplication : No active profile set, falling back to 1 default profile: "default"
2022-04-06 16:05:32.373 INFO 15728 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
2022-04-06 16:05:32.381 INFO 15728 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 2 ms. Found 0 JPA repository interfaces.
2022-04-06 16:05:32.627 INFO 15728 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2022-04-06 16:05:32.632 INFO 15728 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2022-04-06 16:05:32.632 INFO 15728 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.60]
2022-04-06 16:05:32.692 INFO 15728 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2022-04-06 16:05:32.692 INFO 15728 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 569 ms
Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.
2022-04-06 16:05:32.784 INFO 15728 --- [ main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default]
2022-04-06 16:05:32.810 INFO 15728 --- [ main] org.hibernate.Version : HHH000412: Hibernate ORM core version 5.6.7.Final
2022-04-06 16:05:32.893 INFO 15728 --- [ main] o.hibernate.annotations.common.Version : HCANN000001: Hibernate Commons Annotations {5.1.2.Final}
2022-04-06 16:05:32.945 INFO 15728 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2022-04-06 16:05:32.948 WARN 15728 --- [ main] com.zaxxer.hikari.util.DriverDataSource : Registered driver with driverClassName=com.mysql.jdbc.Driver was not found, trying direct instantiation.
2022-04-06 16:05:33.018 INFO 15728 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
2022-04-06 16:05:33.034 INFO 15728 --- [ main] org.hibernate.dialect.Dialect : HHH000400: Using dialect: org.hibernate.dialect.MySQL55Dialect
2022-04-06 16:05:33.132 INFO 15728 --- [ main] o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
2022-04-06 16:05:33.138 INFO 15728 --- [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2022-04-06 16:05:33.156 WARN 15728 --- [ main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
2022-04-06 16:05:33.313 INFO 15728 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2022-04-06 16:05:33.319 INFO 15728 --- [ main] C.Ruben_DeNicolas.ClientixApplication : Started ClientixApplication in 1.398 seconds (JVM running for 1.705)
2022-04-06 16:05:36.286 INFO 15728 --- [nio-8080-exec-2] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2022-04-06 16:05:36.287 INFO 15728 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2022-04-06 16:05:36.287 INFO 15728 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : Completed initialization in 0 ms
what is the url your hitting on your browser, make sure not hitting with https...
Code looks okay, try hitting
http://localhost:8080/clientes
I am trying to use spring.gson.disable-html-escaping=false in my spring boot application.
but it is returning default value.
application.properties:
spring.mvc.converters.preferred-json-mapper=gson
spring.gson.disable-html-escaping=false
GsonHttpMessageConverterConfig.java
package com.example.demo;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.json.GsonHttpMessageConverter;
import java.util.*;
import java.util.stream.Collectors;
#Configuration
#Slf4j
public class GsonHttpMessageConverterConfig {
#Value("${grove.gson.http.converter.mediaTypes}")
private String configuredMediaTypes;
#Value("${spring.gson.disable-html-escaping}")
private String disabledHtmlEscaping;
#Bean
#Autowired
public GsonHttpMessageConverter gsonHttpMessageConverter(Gson gson) {
GsonHttpMessageConverter converter = new GsonHttpMessageConverter();
List<MediaType> configuredMediaTypes = httpConverterMediaTypes();
if (!configuredMediaTypes.isEmpty()){
converter.setSupportedMediaTypes(configuredMediaTypes);
}
converter.setGson(gson());
System.out.println("converter.getGson().htmlSafe() : "+converter.getGson().htmlSafe());
return converter;
}
#Bean
public Gson gson() {
//String disabledHtmlEscaping = System.getenv("spring.gson.disable-html-escaping");
final GsonBuilder builder = new GsonBuilder();
System.out.println("spring.gson.disable-html-escaping : "+disabledHtmlEscaping);
return builder.create();
}
private List<MediaType> httpConverterMediaTypes(){
//String configuredMediaTypes = System.getenv("grove.gson.http.converter.mediaTypes");
if (configuredMediaTypes != null && !configuredMediaTypes.trim().equals("")){
return Arrays.stream(configuredMediaTypes.split(","))
.map(mediaType -> mediaType.split("/"))
.map(mediaType -> new MediaType(mediaType[0],mediaType[1]))
.collect(Collectors.toList());
}
return Collections.emptyList();
}
}
can somebody help me why that property is not working.
I dont want to use builder.disableHtmlEscaping().create()
output is :
2022-03-28 11:20:06.930 INFO 11920 --- [ restartedMain] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.60]
2022-03-28 11:20:06.980 INFO 11920 --- [ restartedMain] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2022-03-28 11:20:06.980 INFO 11920 --- [ restartedMain] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1290 ms
spring.gson.disable-html-escaping : false
converter.getGson().htmlSafe() : true
2022-03-28 11:20:07.730 INFO 11920 --- [ restartedMain] o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 35729
2022-03-28 11:20:07.735 INFO 11920 --- [ restartedMain] o.s.b.a.e.web.EndpointLinksResolver : Exposing 13 endpoint(s) beneath base path '/actuator'
2022-03-28 11:20:07.774 INFO 11920 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2022-03-28 11:20:07.789 INFO 11920 --- [ restartedMain] com.example.demo.DemoApplication : Started DemoApplication in 2.566 seconds (JVM running for 2.965)
the expected output is :
converter.getGson().htmlSafe() is should return false if
I have a simple application to test Spring Boot.
Below is the configuration and the packages are set as per Spring documentation.
There is no error in application startup. Using Spring boot with eclipse.
Still the controller is not mapped to the server and when I do Post or Get it says :
{
"timestamp": 1547026379146,
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/postdata"
}
Repository:
package com.abc.nice.repo;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.abc.nice.entity.Messages;
#Repository
public interface MessagesRepository extends JpaRepository<Messages, Long> {
}
Entity:
package com.abc.nice.entity;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
#Entity
#Table(name = "Messages")
public class Messages{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Size(max = 100)
private String toNumber;
#Size(max = 250)
private String hsm;
#Size(max = 250)
private String template;
#Size(max = 250)
private String parameters;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTo() {
return toNumber;
}
public void setTo(String toNumber) {
this.toNumber = toNumber;
}
public String getHsm() {
return hsm;
}
public void setHsm(String hsm) {
this.hsm = hsm;
}
public String getTemplate() {
return template;
}
public void setTemplate(String template) {
this.template = template;
}
public String getParameters() {
return parameters;
}
public void setParameters(String parameters) {
this.parameters = parameters;
}
}
Controller :
package com.abc.nice.controller;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import com.abc.nice.entity.Messages;
import com.abc.nice.repo.MessagesRepository;
#RestController
public class ControllerRest {
#Autowired
private Messages msgDao;
private MessagesRepository msgRepo;
RestTemplate restTemplate;
#GetMapping({ "/StatusData" })
public List<Messages> index() {
return this.msgRepo.findAll();
}
#PostMapping(path = {"/postdata"})
public ResponseEntity<Messages> createBody(#RequestBody Map<String, String> body) {
this.msgDao = new Messages();
this.msgDao.setTemplate((String) body.get("template"));
this.msgDao.setParameters((String) body.get("parameters"));
this.msgDao.setHsm((String) body.get("hsm"));
this.msgDao.setTo((String) body.get("to"));
return new ResponseEntity<Messages>(this.msgRepo.save(this.msgDao), HttpStatus.OK);
}
}
MainClass :
package com.abc.nice;
import org.hibernate.HibernateException;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
#SpringBootApplication
//#EntityScan("com.abc.nice.entity")
#ComponentScan({"com.abc.nice.entity","com.abc.nice.controller"})
#EnableJpaRepositories({"com.abc.nice.repo"})
//#EnableAutoConfiguration
public class TestApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(TestApplication .class, args);
}
}
Startup Log :
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.5.9.RELEASE)
2019-01-09 17:33:27.724 INFO 19732 --- [ main] com.abc.nice.TestApplication : Starting TestApplication on abcD02 with PID 19732 (C:\Users\abcd\Desktop\test\target\classes started by abcD in C:\Users\abcd\Desktop\test)
2019-01-09 17:33:27.728 INFO 19732 --- [ main] com.abc.nice.TestApplication : No active profile set, falling back to default profiles: default
2019-01-09 17:33:27.827 INFO 19732 --- [ main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext#4206a205: startup date [Wed Jan 09 17:33:27 SGT 2019]; root of context hierarchy
2019-01-09 17:33:29.489 INFO 19732 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
2019-01-09 17:33:29.506 INFO 19732 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2019-01-09 17:33:29.507 INFO 19732 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.23
2019-01-09 17:33:29.746 INFO 19732 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2019-01-09 17:33:29.746 INFO 19732 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1922 ms
2019-01-09 17:33:30.005 INFO 19732 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/]
2019-01-09 17:33:30.009 INFO 19732 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*]
2019-01-09 17:33:30.009 INFO 19732 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2019-01-09 17:33:30.009 INFO 19732 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2019-01-09 17:33:30.009 INFO 19732 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*]
2019-01-09 17:33:30.598 INFO 19732 --- [ main] j.LocalContainerEntityManagerFactoryBean : Building JPA container EntityManagerFactory for persistence unit 'default'
2019-01-09 17:33:30.610 INFO 19732 --- [ main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [
name: default
...]
2019-01-09 17:33:30.680 INFO 19732 --- [ main] org.hibernate.Version : HHH000412: Hibernate Core {5.0.12.Final}
2019-01-09 17:33:30.682 INFO 19732 --- [ main] org.hibernate.cfg.Environment : HHH000206: hibernate.properties not found
2019-01-09 17:33:30.683 INFO 19732 --- [ main] org.hibernate.cfg.Environment : HHH000021: Bytecode provider name : javassist
2019-01-09 17:33:30.749 INFO 19732 --- [ main] o.hibernate.annotations.common.Version : HCANN000001: Hibernate Commons Annotations {5.0.1.Final}
2019-01-09 17:33:30.864 INFO 19732 --- [ main] org.hibernate.dialect.Dialect : HHH000400: Using dialect: org.hibernate.dialect.MySQL5Dialect
2019-01-09 17:33:31.033 INFO 19732 --- [ main] org.hibernate.tool.hbm2ddl.SchemaUpdate : HHH000228: Running hbm2ddl schema update
2019-01-09 17:33:31.058 INFO 19732 --- [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2019-01-09 17:33:31.388 INFO 19732 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for #ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext#4206a205: startup date [Wed Jan 09 17:33:27 SGT 2019]; root of context hierarchy
2019-01-09 17:33:31.454 INFO 19732 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2019-01-09 17:33:31.455 INFO 19732 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2019-01-09 17:33:31.489 INFO 19732 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2019-01-09 17:33:31.489 INFO 19732 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2019-01-09 17:33:31.527 INFO 19732 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2019-01-09 17:33:31.866 INFO 19732 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2019-01-09 17:33:31.937 INFO 19732 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2019-01-09 17:33:31.942 INFO 19732 --- [ main] com.abc.nice.WhatsapptestApplication : Started WhatsapptestApplication in 4.532 seconds (JVM running for 6.213)
2019-01-09 17:39:45.612 INFO 19732 --- [on(2)-127.0.0.1] inMXBeanRegistrar$SpringApplicationAdmin : Application shutdown requested.
2019-01-09 17:39:45.613 INFO 19732 --- [on(2)-127.0.0.1] ationConfigEmbeddedWebApplicationContext : Closing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext#4206a205: startup date [Wed Jan 09 17:33:27 SGT 2019]; root of context hierarchy
2019-01-09 17:39:45.616 INFO 19732 --- [on(2)-127.0.0.1] o.s.j.e.a.AnnotationMBeanExporter : Unregistering JMX-exposed beans on shutdown
2019-01-09 17:39:45.617 INFO 19732 --- [on(2)-127.0.0.1] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
Application.properties:
#spring.datasource.type=org.apache.commons.dbcp.BasicDataSource
spring.datasource.url=jdbc:mysql://localhost:3306/ptpreconn?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC&useSSL=false
spring.datasource.username=root
spring.datasource.password=admin
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.show-sql=true
spring.data.jpa.repositories.enabled=true
#spring.jpa.database-platform=org.hibernate.dialect.MYSQL5Dialect
spring.jpa.hibernate.ddl-auto=update
spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
server.port=${PORT:8080}
Please attach request from e.g. the developers' tools with HTTP verb that you are using and exact response from that request. I am concerned about #GetMapping - why it is in curly braces?
About post mapping, maybe you should describe consumes and produces part of mapping?
E.g.
#PostMapping(path = "/members", consumes = "application/json", produces = "application/json")
I have never used #PostMapping annotation without those parts.
UPDATE:
After removal of unnecessary component scan in Main class change controller as follow:
#RestController
public class ControllerRest {
#Autowired
private MessagesRepository msgRepo;
RestTemplate restTemplate;
#GetMapping({ "/StatusData" })
public List<Messages> index() {
return this.msgRepo.findAll();
}
#PostMapping(path = {"/postdata"})
public ResponseEntity<Messages> createBody(#RequestBody Map<String, String> body) {
Messages msgDao = new Messages();
msgDao.setTemplate((String) body.get("template"));
msgDao.setParameters((String) body.get("parameters"));
msgDao.setHsm((String) body.get("hsm"));
msgDao.setTo((String) body.get("to"));
return new ResponseEntity<Messages>(this.msgRepo.save(this.HttpStatus.OK);
}
}
Add a context path to your application.properties file or application.yml, whichever you are using.
server.servlet.contextPath=/springbootapi
Hit your endpoint: The endpoint for your POST method will be:
http://localhost:{PORT}/springbootapi/postdata
Why dont you statically supply your port. I think the port should be something like:
server.port=8080
I don't understand why you using #RequestBody with "Map<String,String>".
Try this code :
#Autowired
private MessagesRepository msgRepo;
#PostMapping("/postdata")
public ResponseEntity<Object> createBody(#RequestBody Message message) {
Message saveMessage= msgRepo.save(message);
URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}")
.buildAndExpand(saveMessage.getId()).toUri();
return ResponseEntity.created(location).build();
}
I want to save data to a table in postgresql. I am using spring boot + postgresql along with hibernate. My Application does not have any error but it is not creating table in database.
This is my controller class
package com.ge.health.poc.controlleer;
import java.io.IOException;
import org.springframework.beans.factory.annotation.Autowired;
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.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ge.health.poc.model.Bookmodel;
import com.ge.health.poc.service.BookServiceImplementation;
#RestController
public class HttpController {
#Autowired
BookServiceImplementation bookserviceimpl;
#RequestMapping(value = "/httpmethod", method = RequestMethod.POST)
#ResponseBody
public void helloService(#RequestBody String input) throws JsonParseException, JsonMappingException, IOException {
System.out.println(input);
ObjectMapper mapper = new ObjectMapper();
Bookmodel pojodata = mapper.readValue(input, Bookmodel.class);
System.out.println(pojodata);
}
}
AppConfig.java
package com.ge.health.poc.configuration;
import java.util.Properties;
import javax.annotation.Resource;
import javax.jms.ConnectionFactory;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
public class AppConfig {
#Resource
private SettingConfig settings;
#Bean
JmsTemplate jmsTemplate(ConnectionFactory connectionFactory) {
return new JmsTemplate(connectionFactory);
}
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(settings.getDriverClassName());
dataSource.setUrl(settings.getDatasource());
dataSource.setUsername(settings.getUsername());
dataSource.setPassword(settings.getPassword());
return dataSource;
}
/**
* Declare the JPA entity manager factory.
*/
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
// Hibernate properties
Properties additionalProperties = new Properties();
additionalProperties.put("hibernate.dialect", settings.getDialect());
additionalProperties.put("hibernate.show_sql", settings.getShowsql());
additionalProperties.put("hibernate.hbm2ddl.auto", settings.getDdlauto());
entityManagerFactory.setJpaProperties(additionalProperties);
return entityManagerFactory;
}
/**
* Declare the transaction manager.
*/
#Bean
public JpaTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
/**
* PersistenceExceptionTranslationPostProcessor is a bean post processor
* which adds an advisor to any bean annotated with Repository so that any
* platform-specific exceptions are caught and then rethrown as one Spring's
* unchecked data access exceptions (i.e. a subclass of
* DataAccessException).
*/
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
}
SettingConfig.java
package com.ge.health.poc.configuration;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
#Component
public class SettingConfig {
public String getDdlauto() {
return ddlauto;
}
public void setDdlauto(String ddlauto) {
this.ddlauto = ddlauto;
}
public String getShowsql() {
return showsql;
}
public void setShowsql(String showsql) {
this.showsql = showsql;
}
public String getDialect() {
return dialect;
}
public void setDialect(String dialect) {
this.dialect = dialect;
}
#Value("${spring.datasource.url}")
private String datasource;
#Value("${hibernate.hbm2ddl.auto}")
private String ddlauto;
#Value("${hibernate.show_sql}")
private String showsql;
#Value("{hibernate.dialect}")
private String dialect;
#Value("${spring.datasource.username}")
private String username;
#Value("${spring.datasource.password}")
private String password;
#Value("${spring.datasource.driver-class-name}")
private String driverClassName;
public String getDatasource() {
return datasource;
}
public void setDatasource(String datasource) {
this.datasource = datasource;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getDriverClassName() {
return driverClassName;
}
public void setDriverClassName(String driverClassName) {
this.driverClassName = driverClassName;
}
}
application.properties
# Database
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:5432/bookdetails
spring.datasource.username=postgres
spring.datasource.password=admin
# Hibernate
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.show_sql=true
hibernate.hbm2ddl.auto=create
POJO class
package com.ge.health.poc.model;
import javax.persistence.Column;
import javax.persistence.Table;
import org.springframework.data.annotation.Id;
import org.springframework.stereotype.Component;
#Component
#Table
public class Bookmodel {
#Id
private String id;
#Column
private String name;
#Column
private String isbn;
#Column
private String author;
#Column
private String pages;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPages() {
return pages;
}
public void setPages(String pages) {
this.pages = pages;
}
#Override
public String toString() {
return "Bookmodel [id=" + id + ", name=" + name + ", isbn=" + isbn + ", author=" + author + ", pages=" + pages
+ "]";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getIsbn() {
return isbn;
}
public void setIsbn(String isbn) {
this.isbn = isbn;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
}
I want to save data to a table in postgresql.I am using spring boot + postgresql along with hibernate. My Application donot have any error but it is not creating table in database.
The problem is that you are using wrong annotation i.e #component.
Remove this annotation and use #Entity.
This is your code.
After executing this code check the logs, you will see no sql create query is fired by hibernate.
package com.example.demo.hibernateDemoEntity;
import javax.persistence.*;
import org.springframework.stereotype.Component;
#Component
#Table
public class Bookmodel {
#Id
private int id;
#Column
private String name;
#Column
private String isbn;
#Column
private String author;
#Column
private String pages;
}
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.1.7.RELEASE)
2019-09-01 16:52:15.532 INFO 5436 --- [ main] c.example.demo.HibernateDemoApplication : Starting HibernateDemoApplication on BGINMAC004.local with PID 5436 (/Users/Dildeep.Singh/Documents/workspace-sts-3.9.9.RELEASE/HibernateDemo/target/classes started by Dildeep.Singh in /Users/Dildeep.Singh/Documents/workspace-sts-3.9.9.RELEASE/HibernateDemo)
2019-09-01 16:52:15.536 INFO 5436 --- [ main] c.example.demo.HibernateDemoApplication : No active profile set, falling back to default profiles: default
2019-09-01 16:52:16.331 INFO 5436 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data repositories in DEFAULT mode.
2019-09-01 16:52:16.350 INFO 5436 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 12ms. Found 0 repository interfaces.
2019-09-01 16:52:16.730 INFO 5436 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration' of type [org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration$$EnhancerBySpringCGLIB$$de6750d] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2019-09-01 16:52:17.026 INFO 5436 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2019-09-01 16:52:17.049 INFO 5436 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2019-09-01 16:52:17.050 INFO 5436 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.22]
2019-09-01 16:52:17.156 INFO 5436 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2019-09-01 16:52:17.156 INFO 5436 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1581 ms
2019-09-01 16:52:17.355 INFO 5436 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2019-09-01 16:52:17.805 INFO 5436 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
2019-09-01 16:52:17.844 INFO 5436 --- [ main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [
name: default
...]
2019-09-01 16:52:17.894 INFO 5436 --- [ main] org.hibernate.Version : HHH000412: Hibernate Core {5.3.10.Final}
2019-09-01 16:52:17.895 INFO 5436 --- [ main] org.hibernate.cfg.Environment : HHH000206: hibernate.properties not found
2019-09-01 16:52:18.056 INFO 5436 --- [ main] o.hibernate.annotations.common.Version : HCANN000001: Hibernate Commons Annotations {5.0.4.Final}
2019-09-01 16:52:18.147 INFO 5436 --- [ main] org.hibernate.dialect.Dialect : HHH000400: Using dialect: org.hibernate.dialect.MySQL5Dialect
2019-09-01 16:52:18.388 INFO 5436 --- [ main] o.h.t.schema.internal.SchemaCreatorImpl : HHH000476: Executing import script 'org.hibernate.tool.schema.internal.exec.ScriptSourceInputNonExistentImpl#43a09ce2'
2019-09-01 16:52:18.390 INFO 5436 --- [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2019-09-01 16:52:18.657 INFO 5436 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2019-09-01 16:52:18.690 WARN 5436 --- [ main] aWebConfiguration$JpaWebMvcConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
2019-09-01 16:52:18.883 INFO 5436 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2019-09-01 16:52:18.886 INFO 5436 --- [ main] c.example.demo.HibernateDemoApplication : Started HibernateDemoApplication in 18.83 seconds (JVM running for 24.343)
Now replace #Component with #Entity annotation and see the logs.
#Entity
#Table
public class Bookmodel {
#Id
private int id;
#Column
private String name;
#Column
private String isbn;
#Column
private String author;
#Column
private String pages;
}
Spring Logs
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.1.7.RELEASE)
2019-09-01 17:10:59.943 INFO 5461 --- [ main] c.example.demo.HibernateDemoApplication : Starting HibernateDemoApplication on BGINMAC004.local with PID 5461 (/Users/Dildeep.Singh/Documents/workspace-sts-3.9.9.RELEASE/HibernateDemo/target/classes started by Dildeep.Singh in /Users/Dildeep.Singh/Documents/workspace-sts-3.9.9.RELEASE/HibernateDemo)
2019-09-01 17:10:59.946 INFO 5461 --- [ main] c.example.demo.HibernateDemoApplication : No active profile set, falling back to default profiles: default
2019-09-01 17:11:00.629 INFO 5461 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data repositories in DEFAULT mode.
2019-09-01 17:11:00.649 INFO 5461 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 13ms. Found 0 repository interfaces.
2019-09-01 17:11:00.996 INFO 5461 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration' of type [org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration$$EnhancerBySpringCGLIB$$d77725a9] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2019-09-01 17:11:01.227 INFO 5461 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2019-09-01 17:11:01.249 INFO 5461 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2019-09-01 17:11:01.249 INFO 5461 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.22]
2019-09-01 17:11:01.357 INFO 5461 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2019-09-01 17:11:01.357 INFO 5461 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1374 ms
2019-09-01 17:11:01.519 INFO 5461 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2019-09-01 17:11:01.919 INFO 5461 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
2019-09-01 17:11:01.958 INFO 5461 --- [ main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [
name: default
...]
2019-09-01 17:11:02.006 INFO 5461 --- [ main] org.hibernate.Version : HHH000412: Hibernate Core {5.3.10.Final}
2019-09-01 17:11:02.010 INFO 5461 --- [ main] org.hibernate.cfg.Environment : HHH000206: hibernate.properties not found
2019-09-01 17:11:02.182 INFO 5461 --- [ main] o.hibernate.annotations.common.Version : HCANN000001: Hibernate Commons Annotations {5.0.4.Final}
2019-09-01 17:11:02.283 INFO 5461 --- [ main] org.hibernate.dialect.Dialect : HHH000400: Using dialect: org.hibernate.dialect.MySQL5Dialect
**Hibernate: drop table if exists bookmodel
Hibernate: create table bookmodel (id integer not null, author varchar(255), isbn varchar(255), name varchar(255), pages varchar(255), primary key (id)) engine=MyISAM**
2019-09-01 17:11:02.893 INFO 5461 --- [ main] o.h.t.schema.internal.SchemaCreatorImpl : HHH000476: Executing import script 'org.hibernate.tool.schema.internal.exec.ScriptSourceInputNonExistentImpl#134f8ef6'
2019-09-01 17:11:02.895 INFO 5461 --- [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2019-09-01 17:11:03.209 INFO 5461 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2019-09-01 17:11:03.239 WARN 5461 --- [ main] aWebConfiguration$JpaWebMvcConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
2019-09-01 17:11:03.442 INFO 5461 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2019-09-01 17:11:03.445 INFO 5461 --- [ main] c.example.demo.HibernateDemoApplication : Started HibernateDemoApplication in 18.81 seconds (JVM running for 24.307)
Now you can see sql create query is fired by hibernate.
You are "using" Spring Boot and the first thing you do is try very hard not to use Spring Boot.
Instead of doing all the configuration by yourself let Spring Boot do the heavy lifting for you.
In your application.properties set the proper dialect and use the correct properties (see this section of the Spring Boot Reference Guide for a full list of properties).
# Database
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:5432/bookdetails
spring.datasource.username=postgres
spring.datasource.password=admin
# Hibernate
spring.jpa.database=org.hibernate.dialect.PostgreSQL94Dialect
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=create
And remove your custom configuration (i.e. the AppConfig and SettingConfig) that breaks the auto configuration of Spring Boot.
I don't see any column definition in your POJO, how do you expect hibernate to know what type of column to create by simply give a Java type such as String? For my MySQL database I would define POJO like this
#Component
#Table(name = "Book")
public class Bookmodel {
#Size(max = 32)
#Id
#Column(columnDefinition = "varchar(128)", nullable = false, unique = true)
private String id;
#Column(columnDefinition = "varchar(128)", nullable = false)
private String name;
...
}