Sending email via Spring Boot - java

I'm trying to create a contact form. I am using Spring Boot 3.0.0. and Thymeleaf. Everything runs on localhost. I get an unexpected error when I want to send a message:
javax.mail.Provider: com.sun.mail.imap.IMAPProvider not a subtype java.util.ServiceConfigurationError: javax.mail.Provider: com.sun.mail.imap.IMAPProvider not a subtype
pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.6.2</version>
</dependency>
Message class:
public class MessageInfoDto {
private String name;
private String email;
private String text;
public String getName() {
return name;
}
public String getEmail() {
return email;
}
public String getText() {
return text;
}
public void setName(String name) {
this.name = name;
}
public void setEmail(String email) {
this.email = email;
}
public void setText(String text) {
this.text = text;
}
Controller:
#Controller
public class MessageInfoController {
MessageInfoService messageInfoService;
public MessageInfoController(MessageInfoService messageInfoService) {
this.messageInfoService = messageInfoService;
}
#GetMapping("/contact")
public String emialForm(Model model) {
model.addAttribute("message", new MessageInfoDto());
return "contact";
}
#PostMapping("/send")
public String getMessage(MessageInfoDto message) {
messageInfoService.sendEmail(message);
return "redirect:/contact";
}
}
Service:
#Service
public class MessageInfoService {
private final JavaMailSender mailSender;
#Value("${spring.mail.username}")
private String owner;
public MessageInfoService(JavaMailSender mailSender) {
this.mailSender = mailSender;
}
public void sendEmail(MessageInfoDto message) {
SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
simpleMailMessage.setTo(owner);
simpleMailMessage.setFrom(message.getEmail());
simpleMailMessage.setText(message.getText());
simpleMailMessage.setSubject("New Message");
simpleMailMessage.setReplyTo(message.getEmail());
mailSender.send(simpleMailMessage);
}
}
HTML(contact.html):
<body>
<main class="main-content" layout:fragment="content">
<h2 class="list-heading">Send us a message</h2>
<form action="#" th:action="#{/send}" method="post" enctype="multipart/form-data" class="mc-form" th:object="${message}">
<label for="name">Your Name</label>
<input type="text" id="name" placeholder="Your Name" th:field="*{name}" required>
<label for="email">Your e-mail</label>
<input type="text" id="email" placeholder="e-mail" th:field="*{email}">
<label for="message">Your message</label>
<textarea id="message" rows="10" th:field="*{text}"></textarea>
<button type="submit">Send</button>
</form>
</main>
</body>
application.yml:
spring:
mail:
host: smtp.gmail.com
port: 587
username: 10*****#gmail.com
password: [genereted password]
properties:
smtp:
auth: true
starttles:
enable: true
required: true
Please help, I've been googling this since yesterday and couldn't find an answer.
I've also tried with javax.mail-api.

You don't need this, please remove it.
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.6.2</version>
</dependency>
Check MailSender import
USE import org.springframework.mail.MailSender;
NOT import org.springframework.mail.javamail.JavaMailSender;
spring-boot-starter-mail will create default MailSender , you don't create it (MailSender), just use #Autowired private MailSender mailSender;
Hello.java
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.SimpleMailMessage;
//import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.MailSender;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class Hello {
#Autowired
private MailSender mailSender;
#RequestMapping("/sendMail")
public String sendConfirmationEmail() {
SimpleMailMessage msg = new SimpleMailMessage();
msg.setTo("aaa#localhost");
msg.setSubject("Testing from Spring Boot");
msg.setText("Hello World from Spring Boot Email");
mailSender.send(msg);
return "OK";
}
}
I am test ok in my simple test project.
curl http://localhost:8080/sendMail
And I use FakeSmtp jar to my fake mail server.
my spring boot 3 pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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>3.0.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo-mail</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo-mail</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</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>
MY application.properties
spring.mail.host=localhost
spring.mail.port=2525
spring.mail.username=demo#localhost
spring.mail.password=demopassword
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.transport.protocol=smtp
spring.mail.properties.mail.smtps.quitwait=false
spring.mail.properties.mail.smtp.socketFactory.port=465
spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory
DemoMailApplication.java
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class DemoMailApplication {
public static void main(String[] args) {
SpringApplication.run(DemoMailApplication.class, args);
}
}
DemoMailApplication.java
Hello.java
application.properties
pom.xml
Spring Boot 2.7.x send Mail with attachments
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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.7.8</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</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>
DemoApplication.java
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
Hello.java
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.MailSender;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.File;
#RestController
public class Hello {
#Autowired
private JavaMailSenderImpl mailSender;
#RequestMapping("/sendMail")
public String sendConfirmationEmail() throws MessagingException {
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setTo("test#host.com");
helper.setText("Check out this image!");
FileSystemResource file = new FileSystemResource(new File("/YourAttachmentFile/Example.jpg"));
helper.addAttachment("CoolImage.jpg", file);
mailSender.send(message);
return "OK";
}
}
application.properties
spring.mail.host=localhost
spring.mail.port=2525
spring.mail.username=demo#localhost
spring.mail.password=demopassword
spring.mail.properties[mail.smtp.connectiontimeout]=5000
spring.mail.properties[mail.smtp.timeout]=3000
spring.mail.properties[mail.smtp.writetimeout]=5000
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.transport.protocol=smtp
spring.mail.properties.mail.smtps.quitwait=false
spring.mail.properties.mail.smtp.socketFactory.port=465
spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory
Package
mvn clean package
Run
cd target
java -jar demo-0.0.1-SNAPSHOT.jar
Test
curl http://localhost:8080/sendMail
You can use FakeSmtp as Dummy Mail Server
REFERENCE
Example Code is copy from spring-boot-reference-2.7.8.pdf ( 11.4. Sending Email -> TIP See the reference documentation ) -> https://docs.spring.io/spring-framework/docs/5.3.25/reference/html/integration.html#mail (6.2.1. Sending Attachments and Inline Resources)

import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSenderImpl;
public void sendEmail(){
JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
mailSender.setHost("smtp.gmail.com");
mailSender.setPort(587);
mailSender.setUsername("yourEmail#example.com");
mailSender.setPassword("yourPassword");
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom("sender#example.com");
message.setTo("receiver#example.com");
message.setSubject("Test Email");
message.setText("This is a test email sent using Spring Boot");
mailSender.send(message);
}

Related

Trying to implement telegrambots-spring-boot-starter and create Telegram bot, but it doesn't work

I use Spring boot and telegrambots-spring-boot-starter dependency. I did all things as it showed in this repository:
https://github.com/rubenlagus/TelegramBots/tree/master/telegrambots-spring-boot-starter.
But it didn't work.
My pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<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.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.telegram</groupId>
<artifactId>secretary.bot</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>secretary.bot</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambots-spring-boot-starter</artifactId>
<version>5.7.1</version>
</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>
<version>2.6.3</version>
</plugin>
</plugins>
</build>
</project>
My Bot class:
package com.telegram.secretary.bot;
import org.springframework.stereotype.Component;
import org.telegram.telegrambots.bots.TelegramLongPollingBot;
import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
import org.telegram.telegrambots.meta.api.objects.Update;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
import java.util.List;
#Component
public class MySecretaryBot extends TelegramLongPollingBot {
#Override
public String getBotUsername() {
return "Oyaqbot";
}
#Override
public String getBotToken() {
return "5240178378:AAHA6GVOT2fGp_pFMyXD75LEBlms6iEVtSs";
}
#Override
public void onRegister() {
}
#Override
public void onUpdateReceived(Update update) {
String command = update.getMessage().getText();
if(command.equals("/hello")){
String message = "Hello, dear friend!";
SendMessage response = new SendMessage();
response.setChatId(update.getMessage().getChatId().toString());
response.setText(message);
try {
execute(response);
}
catch (TelegramApiException e){
e.printStackTrace();
}
}
}
#Override
public void onUpdatesReceived(List<Update> updates) {
}
}
My Main Spring boot class:
package com.telegram.secretary.bot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Note: According to the repository telegram bot starter for Spring boot automatically registers your bot and no need registration code. And ApiContextInitializer.init(); method also doesn't exist anymore.
Try to register your bot manually.
Create bean for TelegramBotsAPI:
#Bean
public TelegramBotsApi telegramBotsApi() {
return new TelegramBotsApi(DefaultBotSession.class);
}
Register your bot in the constructor:
#Component
public class MySecretaryBot extends TelegramLongPollingBot {
#Autowired
public MySecretaryBot(TelegramBotsApi telegramBotsApi) {
telegramBotsApi.registerBot(this);
}
...
}
You should set scanning directive.
Try this:
#SpringBootApplication
#ComponentScan(basePackages = {
"com.telegram.secretary.bot",
"org.telegram.telegrambots"
})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

HandlerInterceptor is not working with Api Gateway Zuul

I am trying to implement Bucket4J rate limiter in Netflix Zuul Api Gateway. I have added Interceptor for Rate Limiting the requests using WebMvcConfigurer.
package com.rajkumar.apiigateway;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Lazy;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import com.rajkumar.apiigateway.ratelimit.interceptor.RateLimitInterceptor;
#SpringBootApplication
#EnableZuulProxy
public class ApiiGatewayApplication implements WebMvcConfigurer{
#Autowired
#Lazy
RateLimitInterceptor rateLimitInterceptor;
public static void main(String[] args) {
new SpringApplicationBuilder(ApiiGatewayApplication.class)
.run(args);
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(rateLimitInterceptor)
.addPathPatterns("/api/service_1/throttling/users");
}
}
And Interceptor for rate limiting looks like
package com.rajkumar.apiigateway.ratelimit.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import com.rajkumar.apiigateway.ratelimit.service.RateLimitService;
import io.github.bucket4j.Bucket;
import io.github.bucket4j.ConsumptionProbe;
#Component
public class RateLimitInterceptor implements HandlerInterceptor {
private static final String HEADER_API_KEY = "X-API-KEY";
private static final String HEADER_LIMIT_REMAINING = "X-RATE-LIMIT-REMAINING";
private static final String HEADER_RETRY_AFTER = "X-RATE-LIMIT-RETRY-AFTER-SECONDS";
#Autowired
RateLimitService rateLimitService;
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String apiKey = request.getHeader(HEADER_API_KEY);
if(apiKey == null || apiKey.isEmpty()) {
response.sendError(HttpStatus.OK.value(), HEADER_API_KEY+" request header is mandatory");
return false;
}
Bucket tokenBucket = rateLimitService.resolveBucket(request.getHeader(HEADER_API_KEY));
ConsumptionProbe probe = tokenBucket.tryConsumeAndReturnRemaining(1);
if(probe.isConsumed()) {
response.addHeader(HEADER_LIMIT_REMAINING, Long.toString(probe.getRemainingTokens()));
return true;
}
response.addHeader(HEADER_RETRY_AFTER, Long.toString(probe.getNanosToWaitForRefill()/1000000000));
response.sendError(HttpStatus.TOO_MANY_REQUESTS.value(),"You have exceeded your request limit");
return false;
}
}
and other dependent component
package com.rajkumar.apiigateway.ratelimit.service;
import java.util.concurrent.TimeUnit;
import org.springframework.stereotype.Component;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.rajkumar.apiigateway.ratelimit.RateLimit;
import io.github.bucket4j.Bucket;
import io.github.bucket4j.Bucket4j;
#Component
public class RateLimitService {
private LoadingCache<String, Bucket> cache = Caffeine.newBuilder()
.expireAfterWrite(1, TimeUnit.MINUTES)
.build(this::newBucket);
public Bucket resolveBucket(String apiKey) {
return cache.get(apiKey);
}
private Bucket newBucket(String apiKey) {
RateLimit plan = RateLimit.resolvePlanFromApiKey(apiKey);
Bucket bucket = Bucket4j.builder()
.addLimit(plan.getLimit())
.build();
return bucket;
}
}
package com.rajkumar.apiigateway.ratelimit;
import java.time.Duration;
import io.github.bucket4j.Bandwidth;
import io.github.bucket4j.Refill;
public enum RateLimit {
FREE(2L),
BASIC(4L),
PROFESSIONAL(10L);
private Long tokens;
private RateLimit(Long tokens) {
this.tokens = tokens;
}
public static RateLimit resolvePlanFromApiKey(String apiKey) {
if(apiKey==null || apiKey.isEmpty()) {
return FREE;
}
else if(apiKey.startsWith("BAS-")) {
return BASIC;
}
else if(apiKey.startsWith("PRO-")) {
return PROFESSIONAL;
}
return FREE;
}
public Bandwidth getLimit() {
return Bandwidth.classic(tokens, Refill.intervally(tokens, Duration.ofMinutes(1)));
}
}
and pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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.3.4.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.rajkumar</groupId>
<artifactId>apii-gateway</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>apii-gateway</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR8</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<!-- <version>2.5.5</version> -->
</dependency>
<dependency>
<groupId>com.github.vladimir-bukhtoyarov</groupId>
<artifactId>bucket4j-core</artifactId>
<version>4.10.0</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
and application.properties
server.port = 8080
spring.application.name = api-gateway
#routing for service 1
zuul.routes.service_1.path = /api/service_1/**
zuul.routes.service_1.url = http://localhost:8081/
#routing for service 2
zuul.routes.service_2.path = /api/service_2/**
zuul.routes.service_2.url = http://localhost:8082/
When I am trying to hit api gateway (http://localhost:8080/api/service_1/throttling/users): it is not passing through the interceptor. Any help is appreciated.
Thanks in advance.

Connect with MSSQL with Spring Reactive (R2DBC)

I am currently trying to establish a database connection with a Microsoft SQL Server.
Unfortunately I can not understand why it does not work. And the error message can unfortunately not give me precise information.
It looks like my code isn't even trying to connect to the database.
My Starterclaas:
#SpringBootApplication
public class R2Dbc3Application {
public static void main(String[] args) {
SpringApplication.run(R2Dbc3Application.class, args);
}
}
DatabaseConfiguration:
package com.example.config;
import io.r2dbc.mssql.MssqlConnectionConfiguration;
import io.r2dbc.mssql.MssqlConnectionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.r2dbc.config.AbstractR2dbcConfiguration;
import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories;
#Configuration
#EnableR2dbcRepositories("com.example.repository")
public class DatabaseConfiguration extends AbstractR2dbcConfiguration {
private final Logger log = LoggerFactory.getLogger(DatabaseConfiguration.class);
#Value("${spring.data.mssql.host}")
private String host;
#Value("${spring.data.mssql.database}")
private String database;
#Value("${spring.data.mssql.username}")
private String username;
#Value("${spring.data.mssql.password}")
private String password;
#Bean
#Override
public MssqlConnectionFactory connectionFactory() {
System.out.println("Connecting to database" + host);
return new MssqlConnectionFactory(MssqlConnectionConfiguration.builder()
.host(host)
.port(1453)
.database(database)
.username(username)
.password(password)
.build());
}
}
my DatabaseInitializer:
package com.example.config;
import com.example.domain.Person;
import com.example.repository.PersonRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
#Component
public class DatabaseInitializer {
private final Logger log = LoggerFactory.getLogger(DatabaseInitializer.class);
#Autowired
PersonRepository personRepository;
public DatabaseInitializer(PersonRepository personRepository) {
this.personRepository = personRepository;
}
#PostConstruct
public void init() {
log.info("Initializing database if necessary");
personRepository.findAll().count().subscribe(count -> {
if (count == 0) {
log.info("Database is empty, inserting sample data");
createPerson("Josh", "Long", "Pivotal");
createPerson("Julien", "Dubois", "Microsoft");
} else {
log.info("Database is already initialized");
}
});
}
private void createPerson(String firstName, String lastName, String company) {
Person person = new Person();
person.setFirstName(firstName);
person.setLastName(lastName);
person.setCompany(company);
personRepository.save(person).log().subscribe();
}
}
Person.Java:
package com.example.domain;
import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Table;
#Table("person")
public class Person {
#Id
private Long id;
private String firstName;
private String lastName;
private String company;
and getter/setter
My PersonRepository
package com.example.repository;
import com.example.domain.Person;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface PersonRepository extends ReactiveCrudRepository<Person, Long> {
}
And my Controller:
package com.example.web;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.domain.Person;
import com.example.repository.PersonRepository;
import reactor.core.publisher.Flux;
#RestController
#RequestMapping("/")
public class PersonController {
private final PersonRepository personRepository;
public PersonController(PersonRepository personRepository) {
this.personRepository = personRepository;
}
#GetMapping("/persons")
public Flux<Person> list() {
return personRepository.findAll();
}
}
My Pom:
<?xml version="1.0" encoding="UTF-8"?>
<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.2.6.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>R2DBC2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>R2DBC2</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<!-- see https://github.com/r2dbc/r2dbc-mssql/issues/77 -->
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
</dependency>
<dependency>
<groupId>io.r2dbc</groupId>
<artifactId>r2dbc-mssql</artifactId>
<version>1.0.0.M7</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-r2dbc</artifactId>
<version>1.0.0.gh-151-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-libs-snapshot</id>
<url>https://repo.spring.io/libs-snapshot</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</pluginRepository>
</pluginRepositories>
</project>
Error Message:
This application has no configured error view, so you are seeing this as a fallback.
Tue May 19 12:23:33 CEST 2020
[58026f55-7] There was an unexpected error (type=Not Found, status=404).
org.springframework.web.server.ResponseStatusException: 404 NOT_FOUND
at org.springframework.web.reactive.resource.ResourceWebHandler.lambda$handle$0(ResourceWebHandler.java:325)
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Error has been observed at the following site(s):
|_ checkpoint ⇢ HTTP GET "/persons" [ExceptionHandlingWebHandler]
Stack trace:
at org.springframework.web.reactive.resource.ResourceWebHandler.lambda$handle$0(ResourceWebHandler.java:325)
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:44)
at reactor.core.publisher.Mono.subscribe(Mono.java:4210)
at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onComplete(FluxSwitchIfEmpty.java:75)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onComplete(MonoFlatMap.java:174)
at reactor.core.publisher.MonoNext$NextSubscriber.onComplete(MonoNext.java:96)
at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.drain(FluxConcatMap.java:359)
at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.onSubscribe(FluxConcatMap.java:21
org.springframework.web.server.ResponseStatusException: 404 NOT_FOUND
It means the endpoint mapping through #GetMapping was not hit. Remember the paths are joined with defined mappings at the class level and then at the method level, the current endpoint would look like:
localhost:8080//persons
This is incorrect.
As long as the #RestController is a root with no further mapping, don't include the "/" character as long as it adds another "layer" or "subpath" in the path. The correct usage would be #RequestMapping("/endpoint-name"). In your case, you don't want an extra "subpath" so omit the annotation:
#RestController
public class PersonController { ... }
Unfortunatelly, I couldn't find any reference to support my statement.

Vaadin, SpringBoot and Jersey get request returns 404

it is my first post here, till now I finally always found the solution for my dev problem, but now I am really exchausted. Maybe you can help me.
I am trying to setup simple Rest get web app basing on vaadin + spring boot +
maven on tomcat. In some combinations in .pom i received the get response : "sth else" but in such case the vaadin ui wasnt loaded. In such configuration I paste below I cannot obtain the get response:
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.drzinks</groupId>
<artifactId>site</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>Site</name>
<description>CRUD Vaadin Spring App</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.2.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<vaadin.version>7.7.3</vaadin.version>
<vaadin.plugin.version>7.7.3</vaadin.plugin.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-spring-boot-starter</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<!-- in order to have hot deploy in tomcat -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-bom</artifactId>
<version>7.7.3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
web.xml:
<web-app version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<!-- Servlet declaration can be omitted in which case
it would be automatically added by Jersey -->
<servlet>
<servlet-name>javax.ws.rs.core.Application</servlet-name>
</servlet>
<servlet-mapping>
<servlet-name>javax.ws.rs.core.Application</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
WelcomeController.java:
package com.drzinks;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import org.springframework.stereotype.Component;
#Component
#Path("/sth")
public class WelcomeController {
#GET
#Produces("text/plain")
public String getSthElse(){
return "sth elese";
}
}
SiteApplication:
package com.drzinks;
import javax.ws.rs.ApplicationPath;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class SiteApplication {
public static void main(String[] args) {
SpringApplication.run(SiteApplication.class, args);
}
}
SiteUI.java:
package com.drzinks;
import org.springframework.beans.factory.annotation.Autowired;
import com.vaadin.annotations.Theme;
import com.vaadin.server.VaadinRequest;
import com.vaadin.spring.annotation.SpringUI;
import com.vaadin.ui.Label;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
#SpringUI
#Theme("valo")
public class SiteUI extends UI {
#Autowired
private RestClient restClient;
private VerticalLayout layout;
#Override
protected void init(VaadinRequest request) {
setupLayout();
addHeader();
}
private void setupLayout() {
layout = new VerticalLayout(); //alt shift l extr local var
setContent(layout);
}
private void addHeader() {
// Label label1 = new Label(welcomeController.returnSth());
// layout.addComponent(label1);
Label label2 = new Label(restClient.getSthFromServer());
// Label label2 = new Label("restClient.getSthFromServer()");
layout.addComponent(label2);
}
}
RestClient.java:
package com.drzinks;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import org.springframework.stereotype.Component;
import com.vaadin.spring.annotation.UIScope;
#UIScope
#Component
public class RestClient {
private Client client = ClientBuilder.newClient();
private WebTarget webtarget = client.target("http://localhost:8080");
public String getSthFromServer() {
String response;
response = webtarget.path("sth")
.request().get(String.class);
return response;
}
}
folder_structure
If anyone could help, I would be very appreciated as I spent on this more than 12 hrs, breaking all night..

Connect to PostgreSQL from SpringBootApplication

I am building a simple Spring application from the scratch using Maven and PostgreSQL.
I've been following thousand of tutorials but it isn't clear for me where to store the different configurations to connect and work with a PostgreSQL database.
My pom.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework</groupId>
<artifactId>gs-rest-service</artifactId>
<version>0.1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.2.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.4-1201-jdbc4</version>
</dependency>
</dependencies>
<properties>
<java.version>1.8</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-releases</id>
<url>https://repo.spring.io/libs-release</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-releases</id>
<url>https://repo.spring.io/libs-release</url>
</pluginRepository>
</pluginRepositories>
</project>
My src/main/java/quotes/Application.java file:
package quotes;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
My src/main/java/quotes/Quote.java file:
package quotes;
public class Quote {
private String content;
private String author;
public Quote(String content, String author) {
this.content = content;
this.author = author;
}
public String getContent() {
return this.content;
}
public Quote setContent(String content) {
this.content = content;
return this;
}
public String getAuthor() {
return this.author;
}
public Quote setAuthor(String author) {
this.author = author;
return this;
}
}
And my src/main/java/quotes/QuoteController.java file:
package quotes;
import java.util.concurrent.atomic.AtomicLong;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.CrossOrigin;
#Controller
public class QuoteController {
private static final String template = "Hello, %s!";
private final AtomicLong counter = new AtomicLong();
#CrossOrigin(origins = "*")
#RequestMapping("/random")
public #ResponseBody Quote randomQuote() {
return new Quote("¿A dónde vas? Patatas traigo", "Ortega y Pacheco");
}
}
I can build and run the application with Maven:
mvn clean package
java -jar target/*.jar
The idea now is to modify the code on QuoteController.java to connect to PostgreSQL and return a random stored quote.
Could you please give some advices / clues?
You should try this tutorial .
http://devcrumb.com/hibernate/spring-data-jpa-hibernate-maven
You need to add an application.properties file under src/main/resources
It should look like this for PostgreSQL:
spring.jpa.database=POSTGRESQL
spring.datasource.platform=postgres
spring.database.driverClassName=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:5432/your-db-name
spring.datasource.username=username
spring.datasource.password=password
Checkout this link for more info:
enter link description here

Categories

Resources