Merge branch 'master' of https://github.com/eugenp/tutorials into BAEL-1177

This commit is contained in:
Loredana Crusoveanu 2018-01-20 16:05:09 +02:00
commit f2a097bfc1
86 changed files with 1980 additions and 294 deletions

129
activejdbc/pom.xml Normal file
View File

@ -0,0 +1,129 @@
<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.baeldung</groupId>
<artifactId>activejdbc</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>activejdbc</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<activejdbc.version>1.4.13</activejdbc.version>
<environments>development.test,development</environments>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.javalite</groupId>
<artifactId>activejdbc-instrumentation</artifactId>
<version>${activejdbc.version}</version>
<executions>
<execution>
<phase>process-classes</phase>
<goals>
<goal>instrument</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.javalite</groupId>
<artifactId>db-migrator-maven-plugin</artifactId>
<version>${activejdbc.version}</version>
<configuration>
<configFile>${project.basedir}/src/main/resources/database.properties</configFile>
<environments>${environments}</environments>
</configuration>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.34</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
<configuration>
<reportFormat>brief</reportFormat>
<trimStackTrace>true</trimStackTrace>
<useFile>false</useFile>
<includes>
<include>**/*Spec*.java</include>
<include>**/*Test*.java</include>
</includes>
<excludes>
<exclude>**/helpers/*</exclude>
<exclude>**/*$*</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.javalite</groupId>
<artifactId>activejdbc</artifactId>
<version>${activejdbc.version}</version>
<exclusions>
<exclusion>
<groupId>opensymphony</groupId>
<artifactId>oscache</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.34</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.9</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>snapshots1</id>
<name>JavaLite Snapshots1</name>
<url>http://repo.javalite.io/</url>
<snapshots>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
<checksumPolicy>warn</checksumPolicy>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>snapshots2</id>
<name>JavaLite Snapshots2</name>
<url>http://repo.javalite.io/</url>
<snapshots>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
<checksumPolicy>warn</checksumPolicy>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>

View File

@ -0,0 +1,61 @@
package com.baeldung;
import com.baeldung.model.Employee;
import com.baeldung.model.Role;
import org.javalite.activejdbc.Base;
import org.javalite.activejdbc.LazyList;
import org.javalite.activejdbc.Model;
public class ActiveJDBCApp
{
public static void main( String[] args )
{
try {
Base.open();
ActiveJDBCApp app = new ActiveJDBCApp();
app.create();
app.update();
app.delete();
app.deleteCascade();
} catch (Exception e) {
e.printStackTrace();
} finally {
Base.close();
}
}
protected void create() {
Employee employee = new Employee("Hugo","C","M","BN");
employee.saveIt();
employee.add(new Role("Java Developer","BN"));
LazyList<Model> all = Employee.findAll();
System.out.println(all.size());
}
protected void update() {
Employee employee = Employee.findFirst("first_name = ?","Hugo");
employee.set("last_namea","Choi").saveIt();
employee = Employee.findFirst("last_name = ?","Choi");
System.out.println(employee.getString("first_name") + " " + employee.getString("last_name"));
}
protected void delete() {
Employee employee = Employee.findFirst("first_name = ?","Hugo");
employee.delete();
employee = Employee.findFirst("last_name = ?","Choi");
if(null == employee){
System.out.println("No such Employee found!");
}
}
protected void deleteCascade() {
create();
Employee employee = Employee.findFirst("first_name = ?","Hugo");
employee.deleteCascade();
employee = Employee.findFirst("last_name = ?","C");
if(null == employee){
System.out.println("No such Employee found!");
}
}
}

View File

@ -0,0 +1,19 @@
package com.baeldung.model;
import org.javalite.activejdbc.Model;
public class Employee extends Model {
public Employee(){
}
public Employee(String firstName, String lastName, String gender, String createdBy) {
set("first_name1",firstName);
set("last_name",lastName);
set("gender",gender);
set("created_by",createdBy);
}
}

View File

@ -0,0 +1,18 @@
package com.baeldung.model;
import org.javalite.activejdbc.Model;
import org.javalite.activejdbc.annotations.Table;
@Table("EMP_ROLES")
public class Role extends Model {
public Role(){
}
public Role(String role,String createdBy){
set("role_name",role);
set("created_by",createdBy);
}
}

View File

@ -0,0 +1,25 @@
# noinspection SqlNoDataSourceInspectionForFile
create table organisation.employees
(
id int not null auto_increment
primary key,
first_name varchar(100) not null,
last_name varchar(100) not null,
gender varchar(1) not null,
created_at datetime not null,
updated_at datetime null,
created_by varchar(100) not null,
updated_by varchar(100) null
)ENGINE = InnoDB DEFAULT CHARSET = utf8;
create table organisation.emp_roles
(
id int not null auto_increment primary key,
employee_id int not null,
role_name varchar(100) not null,
created_at datetime not null,
updated_at datetime null,
created_by varchar(100) not null,
updated_by varchar(100) null
)ENGINE = InnoDB DEFAULT CHARSET = utf8;

View File

@ -0,0 +1,10 @@
development.driver=com.mysql.jdbc.Driver
development.username=root
development.password=123456
development.url=jdbc:mysql://localhost/organisation
development.test.driver=com.mysql.jdbc.Driver
development.test.username=root
development.test.password=123456
development.test.url=jdbc:mysql://localhost/organisation_test

View File

@ -0,0 +1,51 @@
package com.baeldung;
import com.baeldung.model.Employee;
import com.baeldung.model.Role;
import org.javalite.activejdbc.test.DBSpec;
import org.junit.Test;
import java.util.List;
public class ActiveJDBCAppTest extends DBSpec
{
@Test
public void ifEmployeeCreated_thenIsValid() {
Employee employee = new Employee("B", "N", "M", "BN");
the(employee).shouldBe("valid");
}
@Test
public void ifEmployeeCreatedWithRoles_thenShouldPersist() {
Employee employee = new Employee("B", "N", "M", "BN");
employee.saveIt();
employee.add(new Role("Java Developer","BN"));
employee.add(new Role("Lead Java Developer","BN"));
a(Role.count()).shouldBeEqual(2);
List<Role> roles = employee.getAll(Role.class).orderBy("created_at");
the(roles.get(0).getRoleName()).shouldBeEqual("Java Developer");
the(roles.get(1).getRoleName()).shouldBeEqual("Lead Java Developer");
}
@Test
public void ifEmployeeCreatedWithRoles_whenNameUpdated_thenShouldShowNewName() {
Employee employee = new Employee("Binesh", "N", "M", "BN");
employee.saveIt();
employee.add(new Role("Java Developer","BN"));
employee.add(new Role("Lead Java Developer","BN"));
employee = Employee.findFirst("first_name = ?", "Binesh");
employee.set("last_name","Narayanan").saveIt();
Employee updated = Employee.findFirst("first_name = ?", "Binesh");
the(updated.getLastName()).shouldBeEqual("Narayanan");
}
@Test
public void ifEmployeeCreatedWithRoles_whenDeleted_thenShouldNotBeFound() {
Employee employee = new Employee("Binesh", "N", "M", "BN");
employee.saveIt();
employee.add(new Role("Java Developer","BN"));
employee.delete();
employee = Employee.findFirst("first_name = ?", "Binesh");
the(employee).shouldBeNull();
}
}

View File

@ -1,3 +1,4 @@
### Relevant Articles: ### Relevant Articles:
- [Microsoft Word Processing in Java with Apache POI](http://www.baeldung.com/java-microsoft-word-with-apache-poi) - [Microsoft Word Processing in Java with Apache POI](http://www.baeldung.com/java-microsoft-word-with-apache-poi)
- [Working with Microsoft Excel in Java](http://www.baeldung.com/java-microsoft-excel) - [Working with Microsoft Excel in Java](http://www.baeldung.com/java-microsoft-excel)
- [Creating a MS PowerPoint Presentation in Java](https://github.com/eugenp/tutorials/tree/master/apache-poi)

View File

@ -37,3 +37,6 @@
- [Iterable to Stream in Java](http://www.baeldung.com/java-iterable-to-stream) - [Iterable to Stream in Java](http://www.baeldung.com/java-iterable-to-stream)
- [Converting String to Stream of chars](http://www.baeldung.com/java-string-to-stream) - [Converting String to Stream of chars](http://www.baeldung.com/java-string-to-stream)
- [How to Iterate Over a Stream With Indices](http://www.baeldung.com/java-stream-indices) - [How to Iterate Over a Stream With Indices](http://www.baeldung.com/java-stream-indices)
- [Efficient Word Frequency Calculator in Java](http://www.baeldung.com/java-word-frequency)
- [Primitive Type Streams in Java 8](http://www.baeldung.com/java-8-primitive-streams)
- [Fail-Safe Iterator vs Fail-Fast Iterator](http://www.baeldung.com/java-fail-safe-vs-fail-fast-iterator)

View File

@ -33,3 +33,4 @@
- [Daemon Threads in Java](http://www.baeldung.com/java-daemon-thread) - [Daemon Threads in Java](http://www.baeldung.com/java-daemon-thread)
- [Implementing a Runnable vs Extending a Thread](http://www.baeldung.com/java-runnable-vs-extending-thread) - [Implementing a Runnable vs Extending a Thread](http://www.baeldung.com/java-runnable-vs-extending-thread)
- [How to Kill a Java Thread](http://www.baeldung.com/java-thread-stop) - [How to Kill a Java Thread](http://www.baeldung.com/java-thread-stop)
- [ExecutorService - Waiting for Threads to Finish](http://www.baeldung.com/java-executor-wait-for-threads)

View File

@ -118,3 +118,11 @@
- [Implementing a Binary Tree in Java](http://www.baeldung.com/java-binary-tree) - [Implementing a Binary Tree in Java](http://www.baeldung.com/java-binary-tree)
- [A Guide to ThreadLocalRandom in Java](http://www.baeldung.com/java-thread-local-random) - [A Guide to ThreadLocalRandom in Java](http://www.baeldung.com/java-thread-local-random)
- [RegEx for matching Date Pattern in Java](http://www.baeldung.com/java-date-regular-expressions) - [RegEx for matching Date Pattern in Java](http://www.baeldung.com/java-date-regular-expressions)
- [Introduction to the JDBC RowSet Interface in Java](http://www.baeldung.com/java-jdbc-rowset)
- [Nested Classes in Java](http://www.baeldung.com/java-nested-classes)
- [A Guide to Java Loops](http://www.baeldung.com/java-loops)
- [Varargs in Java](http://www.baeldung.com/java-varargs)
- [A Guide to HashSet in Java](http://www.baeldung.com/java-hashset)
- [A Guide to Inner Interfaces in Java](http://www.baeldung.com/java-inner-interfaces)
- [Polymorphism in Java](http://www.baeldung.com/java-polymorphism)
- [Recursion In Java](http://www.baeldung.com/java-recursion)

View File

@ -0,0 +1,76 @@
package com.baeldung.trie;
public class Trie {
private TrieNode root;
Trie() {
root = new TrieNode();
}
public void insert(String word) {
TrieNode current = root;
for (int i = 0; i < word.length(); i++) {
char ch = word.charAt(i);
TrieNode node = current.getChildren()
.get(ch);
if (node == null) {
node = new TrieNode();
current.getChildren()
.put(ch, node);
}
current = node;
}
current.setEndOfWord(true);
}
public boolean find(String word) {
TrieNode current = root;
for (int i = 0; i < word.length(); i++) {
char ch = word.charAt(i);
TrieNode node = current.getChildren()
.get(ch);
if (node == null) {
return false;
}
current = node;
}
return current.isEndOfWord();
}
public void delete(String word) {
delete(root, word, 0);
}
private boolean delete(TrieNode current, String word, int index) {
if (index == word.length()) {
if (!current.isEndOfWord()) {
return false;
}
current.setEndOfWord(false);
return current.getChildren()
.size() == 0;
}
char ch = word.charAt(index);
TrieNode node = current.getChildren()
.get(ch);
if (node == null) {
return false;
}
boolean shouldDeleteCurrentNode = delete(node, word, index + 1);
if (shouldDeleteCurrentNode) {
current.getChildren()
.remove(ch);
return current.getChildren().isEmpty();
}
return false;
}
public boolean containsNode(String word) {
return find(word);
}
public boolean isEmpty() {
return root == null;
}
}

View File

@ -0,0 +1,31 @@
package com.baeldung.trie;
import java.util.HashMap;
import java.util.Map;
class TrieNode {
private Map<Character, TrieNode> children;
private boolean endOfWord;
public TrieNode() {
children = new HashMap<>();
endOfWord = false;
}
public Map<Character, TrieNode> getChildren() {
return children;
}
public void setChildren(Map<Character, TrieNode> children) {
this.children = children;
}
public boolean isEndOfWord() {
return endOfWord;
}
public void setEndOfWord(boolean endOfWord) {
this.endOfWord = endOfWord;
}
}

View File

@ -0,0 +1,68 @@
package com.baeldung.trie;
import org.junit.Test;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class TrieTest {
@Test
public void whenEmptyTrie_thenNoElements() {
Trie trie = new Trie();
assertFalse(trie.isEmpty());
}
@Test
public void givenATrie_whenAddingElements_thenTrieNotEmpty() {
Trie trie = createExampleTrie();
assertFalse(trie.isEmpty());
}
@Test
public void givenATrie_whenAddingElements_thenTrieHasThoseElements() {
Trie trie = createExampleTrie();
assertFalse(trie.containsNode("3"));
assertFalse(trie.containsNode("vida"));
assertTrue(trie.containsNode("Programming"));
assertTrue(trie.containsNode("is"));
assertTrue(trie.containsNode("a"));
assertTrue(trie.containsNode("way"));
assertTrue(trie.containsNode("of"));
assertTrue(trie.containsNode("life"));
}
@Test
public void givenATrie_whenLookingForNonExistingElement_thenReturnsFalse() {
Trie trie = createExampleTrie();
assertFalse(trie.containsNode("99"));
}
@Test
public void givenATrie_whenDeletingElements_thenTreeDoesNotContainThoseElements() {
Trie trie = createExampleTrie();
assertTrue(trie.containsNode("Programming"));
trie.delete("Programming");
assertFalse(trie.containsNode("Programming"));
}
private Trie createExampleTrie() {
Trie trie = new Trie();
trie.insert("Programming");
trie.insert("is");
trie.insert("a");
trie.insert("way");
trie.insert("of");
trie.insert("life");
return trie;
}
}

View File

@ -16,5 +16,5 @@
- [Delegated Properties in Kotlin](http://www.baeldung.com/kotlin-delegated-properties) - [Delegated Properties in Kotlin](http://www.baeldung.com/kotlin-delegated-properties)
- [Sealed Classes in Kotlin](http://www.baeldung.com/kotlin-sealed-classes) - [Sealed Classes in Kotlin](http://www.baeldung.com/kotlin-sealed-classes)
- [JUnit 5 for Kotlin Developers](http://www.baeldung.com/junit-5-kotlin) - [JUnit 5 for Kotlin Developers](http://www.baeldung.com/junit-5-kotlin)
- [Extension Methods in Kotlin](http://www.baeldung.com/kotlin-extension-methods)

View File

@ -1,4 +1,4 @@
## Relevant articles: ## Relevant articles:
- [Intro to Dubbo](http://www.baeldung.com/dubbo-intro) - [Introduction to Dubbo](http://www.baeldung.com/dubbo)

View File

@ -1,2 +1,3 @@
### Relevant Articles: ### Relevant Articles:
- [Database Migrations with Flyway](http://www.baeldung.com/database-migrations-with-flyway) - [Database Migrations with Flyway](http://www.baeldung.com/database-migrations-with-flyway)
- [A Guide to Flyway Callbacks](http://www.baeldung.com/flyway-callbacks)

View File

@ -1,2 +1,4 @@
## Relevant articles: ## Relevant articles:
- [Introduction to Gradle](http://www.baeldung.com/gradle) - [Introduction to Gradle](http://www.baeldung.com/gradle)
- [Writing Custom Gradle Plugins](http://www.baeldung.com/gradle-create-plugin)
- [Creating a Fat Jar in Gradle](http://www.baeldung.com/gradle-fat-jar)

15
guest/deep-jsf/README.md Normal file
View File

@ -0,0 +1,15 @@
## Building
To build the module, use Maven's `package` goal:
```
mvn clean package
```
The `war` file will be available at `target/deep-jsf.war`
## Running
The `war` application is deployed to a Java EE 7 compliant application server, for example, to GlassFish 4 or later.
The example then will be accessible at http://localhost:8080/deep-jsf/index.xhtml

40
guest/deep-jsf/pom.xml Normal file
View File

@ -0,0 +1,40 @@
<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.stackify</groupId>
<artifactId>deep-jsf</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<failOnMissingWebXml>false</failOnMissingWebXml>
</properties>
<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>deep-jsf</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,14 @@
package com.stackify.deepjsf;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
@ManagedBean
@RequestScoped
public class GreetControllerBean {
public String greet() {
return "greet";
}
}

View File

@ -0,0 +1,47 @@
package com.stackify.deepjsf;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.component.UIComponent;
import javax.faces.component.UIViewRoot;
import javax.faces.component.visit.VisitContext;
import javax.faces.component.visit.VisitResult;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.servlet.http.HttpServletRequest;
@ManagedBean
@RequestScoped
public class PhaseListenerBean {
public void beforeListener(PhaseEvent event) {
if (!event.getPhaseId().equals(PhaseId.RENDER_RESPONSE)) {
return;
}
UIViewRoot root = event.getFacesContext().getViewRoot();
boolean showNewFeature = showNewFeatureForIp(event);
processComponentTree(root, event, showNewFeature);
}
private boolean showNewFeatureForIp(PhaseEvent event) {
HttpServletRequest request = (HttpServletRequest) event.getFacesContext()
.getExternalContext().getRequest();
String ip = request.getRemoteAddr();
return !ip.startsWith("127.0");
}
private void processComponentTree(UIComponent component, PhaseEvent event, boolean show) {
component.visitTree(VisitContext.createVisitContext(event.getFacesContext()),
(context, target) -> {
if (target.getId() != null
&& target.getId().startsWith("new-feature-")
&& !show) {
target.setRendered(false);
}
return VisitResult.ACCEPT;
});
}
}

View File

@ -0,0 +1,48 @@
package com.stackify.deepjsf;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.event.ValueChangeEvent;
@ManagedBean
@SessionScoped
public class UserBean {
private String name = "";
private String lastName = "";
private String proposedLogin = "";
public void nameChanged(ValueChangeEvent event) {
this.proposedLogin = event.getNewValue() + "-" + lastName;
}
public void lastNameChanged(ValueChangeEvent event) {
this.proposedLogin = name + "-" + event.getNewValue();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getProposedLogin() {
return proposedLogin;
}
public void setProposedLogin(String proposedLogin) {
this.proposedLogin = proposedLogin;
}
}

View File

@ -0,0 +1,14 @@
package com.stackify.deepjsf;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
@ManagedBean
@RequestScoped
public class UserControllerBean {
public String register() {
return "register-success";
}
}

View File

@ -0,0 +1,15 @@
<?xml version='1.0' encoding='UTF-8'?>
<faces-config version="2.2" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd">
<navigation-rule>
<from-view-id>/register.xhtml</from-view-id>
<navigation-case>
<from-outcome>register-success</from-outcome>
<to-view-id>/hello.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
</faces-config>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<f:view beforePhase="#{phaseListenerBean.beforeListener}">
<h:outputLabel value="Hello, #{userBean.name}"/>
<h:outputLabel id="new-feature-last-name" value=" #{userBean.lastName}"/>
</f:view>
</html>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<f:view>
<h:outputLabel value="Hello, #{userBean.name} #{userBean.lastName}! Your login is: #{userBean.proposedLogin}"/>
</f:view>
</html>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<f:view beforePhase="#{phaseListenerBean.beforeListener}">
<h:form>
<h:panelGrid columns="2">
<h:outputLabel value="First Name:"/>
<h:inputText id="name" value="#{userBean.name}"/>
<h:outputLabel id="new-feature-last-name-label" value="Last Name:"/>
<h:inputText id="new-feature-last-name" value="#{userBean.lastName}"/>
<h:commandButton value="Submit" action="#{greetControllerBean.greet}"/>
</h:panelGrid>
</h:form>
</f:view>
</html>

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
<h:outputScript library="javax.faces" name="jsf.js"/>
</h:head>
<f:view>
<h:form>
<h:panelGrid columns="2">
<h:outputLabel value="First Name:"/>
<h:inputText id="name" value="#{userBean.name}"
valueChangeListener="#{userBean.nameChanged}">
<f:ajax event="change" execute="@this" render="proposed-login"/>
</h:inputText>
<h:outputLabel id="lastname-label" value="Last Name:"/>
<h:inputText id="lastname" value="#{userBean.lastName}"
valueChangeListener="#{userBean.lastNameChanged}">
<f:ajax event="change" execute="@this" render="proposed-login"/>
</h:inputText>
<h:outputLabel id="login-label" value="Proposed Login:"/>
<h:inputText id="proposed-login" disabled="true" value="#{userBean.proposedLogin}"/>
<h:commandButton value="Submit" action="#{userControllerBean.register}"/>
</h:panelGrid>
</h:form>
</f:view>
</html>

View File

@ -5,3 +5,5 @@
- [Hibernate Mapping Date and Time](http://www.baeldung.com/hibernate-date-time) - [Hibernate Mapping Date and Time](http://www.baeldung.com/hibernate-date-time)
- [Hibernate Inheritance Mapping](http://www.baeldung.com/hibernate-inheritance) - [Hibernate Inheritance Mapping](http://www.baeldung.com/hibernate-inheritance)
- [A Guide to Multitenancy in Hibernate 5](http://www.baeldung.com/hibernate-5-multitenancy) - [A Guide to Multitenancy in Hibernate 5](http://www.baeldung.com/hibernate-5-multitenancy)
- [Introduction to Hibernate Spatial](http://www.baeldung.com/hibernate-spatial)
- [Hibernate Interceptors](http://www.baeldung.com/hibernate-interceptor)

View File

@ -2,6 +2,7 @@
### Relevant Article: ### Relevant Article:
- [Introduction to using InfluxDB with Java](http://www.baeldung.com/using-influxdb-with-java/) - [Introduction to using InfluxDB with Java](http://www.baeldung.com/using-influxdb-with-java/)
- [Using InfluxDB with Java](http://www.baeldung.com/java-influxdb)
### Overview ### Overview
This Maven project contains the Java code for the article linked above. This Maven project contains the Java code for the article linked above.

View File

@ -39,3 +39,8 @@ $ curl -X POST -H "Content-Type:application/json" -d '{ "firstName" : "Dassi", "
Now with default configurations it will be available at: [http://localhost:8080](http://localhost:8080) Now with default configurations it will be available at: [http://localhost:8080](http://localhost:8080)
Enjoy it :) Enjoy it :)
### Relevant Articles:
- [Intro to Performance Testing using JMeter](http://www.baeldung.com/jmeter)
- [Configure Jenkins to Run and Show JMeter Tests](http://www.baeldung.com/jenkins-and-jmeter)

View File

@ -2,3 +2,4 @@
- [Introduction to Reladomo](http://www.baeldung.com/reladomo) - [Introduction to Reladomo](http://www.baeldung.com/reladomo)
- [Introduction to ORMLite](http://www.baeldung.com/ormlite) - [Introduction to ORMLite](http://www.baeldung.com/ormlite)
- [Introduction To Kryo](http://www.baeldung.com/kryo) - [Introduction To Kryo](http://www.baeldung.com/kryo)
- [Introduction to KafkaStreams in Java](http://www.baeldung.com/java-kafka-streams)

View File

@ -58,6 +58,8 @@
- [Introduction to BouncyCastle with Java](http://www.baeldung.com/java-bouncy-castle) - [Introduction to BouncyCastle with Java](http://www.baeldung.com/java-bouncy-castle)
- [Intro to JDO Queries 2/2](http://www.baeldung.com/jdo-queries) - [Intro to JDO Queries 2/2](http://www.baeldung.com/jdo-queries)
- [Guide to google-http-client](http://www.baeldung.com/google-http-client) - [Guide to google-http-client](http://www.baeldung.com/google-http-client)
- [Interact with Google Sheets from Java](http://www.baeldung.com/google-sheets-java-client)
The libraries module contains examples related to small libraries that are relatively easy to use and does not require any separate module of its own. The libraries module contains examples related to small libraries that are relatively easy to use and does not require any separate module of its own.

View File

@ -1,3 +1,6 @@
## Logging Modules ## Logging Modules
### Relevant Articles:
- [Creating a Custom Logback Appender](http://www.baeldung.com/custom-logback-appender)

4
lucene/README.md Normal file
View File

@ -0,0 +1,4 @@
### Relevant Articles:
- [Introduction to Apache Lucene](http://www.baeldung.com/lucene)
- [A Simple File Search with Lucene](http://www.baeldung.com/lucene-file-search)

3
muleesb/README.md Normal file
View File

@ -0,0 +1,3 @@
### Relevant Articles:
- [Getting Started With Mule ESB](http://www.baeldung.com/mule-esb)

View File

@ -23,3 +23,6 @@ Before launching unit tests:
- Install OrientDB - Install OrientDB
- Create BaeldungDB, BaeldungDBTwo and BaeldungDBThree databases - Create BaeldungDB, BaeldungDBTwo and BaeldungDBThree databases
- Uncomment annotations on the test files - Uncomment annotations on the test files
### Relevant Articles:
- [Introduction to the OrientDB Java APIs](http://www.baeldung.com/java-orientdb)

View File

@ -1,3 +1,7 @@
## Persistence Modules ## Persistence Modules
### Relevant Articles:
- [Introduction to Hibernate Search](http://www.baeldung.com/hibernate-search)

View File

@ -113,7 +113,9 @@
<module>lombok</module> <module>lombok</module>
<!-- <module>kotlin</module>--> <!-- <module>kotlin</module>-->
<module>mapstruct</module> <module>mapstruct</module>
<!--
<module>metrics</module> <module>metrics</module>
-->
<module>mesos-marathon</module> <module>mesos-marathon</module>
<module>testing-modules/mockito</module> <module>testing-modules/mockito</module>
<module>testing-modules/mockito-2</module> <module>testing-modules/mockito-2</module>

View File

@ -60,6 +60,12 @@
<!-- <version>1.1.2</version> --> <!-- <version>1.1.2</version> -->
<!-- </dependency> --> <!-- </dependency> -->
<!-- Dependencies for Johnzon --> <!-- Dependencies for Johnzon -->
<!-- lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>compile</scope>
</dependency>
<dependency> <dependency>
<groupId>org.apache.geronimo.specs</groupId> <groupId>org.apache.geronimo.specs</groupId>

View File

@ -1,4 +1,4 @@
package com.baeldung; package com.baeldung.reactive.websocket;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;

View File

@ -0,0 +1,23 @@
package com.baeldung.reactive.websocket;
import java.net.URI;
import java.time.Duration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.reactive.socket.WebSocketMessage;
import org.springframework.web.reactive.socket.client.ReactorNettyWebSocketClient;
import org.springframework.web.reactive.socket.client.WebSocketClient;
import reactor.core.publisher.Mono;
@SpringBootApplication
public class ReactiveJavaClientWebSocket {
public static void main(String[] args) throws InterruptedException {
WebSocketClient client = new ReactorNettyWebSocketClient();
client.execute(URI.create("ws://localhost:8080/event-emitter"), session -> session.send(Mono.just(session.textMessage("event-me-from-spring-reactive-client")))
.thenMany(session.receive()
.map(WebSocketMessage::getPayloadAsText)
.log())
.then())
.block(Duration.ofSeconds(10L));
}
}

View File

@ -0,0 +1,11 @@
package com.baeldung.reactive.websocket;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ReactiveWebSocketApplication {
public static void main(String[] args) {
SpringApplication.run(ReactiveWebSocketApplication.class, args);
}
}

View File

@ -1,4 +1,4 @@
package com.baeldung; package com.baeldung.reactive.websocket;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;

View File

@ -1,4 +1,4 @@
package com.baeldung; package com.baeldung.reactive.websocket;
import org.springframework.web.reactive.socket.WebSocketSession; import org.springframework.web.reactive.socket.WebSocketSession;

View File

@ -30,6 +30,10 @@
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId> <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity4</artifactId>
</dependency>
<!-- oauth2 --> <!-- oauth2 -->
<dependency> <dependency>
@ -40,6 +44,21 @@
<groupId>org.springframework.security</groupId> <groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-jose</artifactId> <artifactId>spring-security-oauth2-jose</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>
<build> <build>

View File

@ -0,0 +1,54 @@
package com.baeldung.securityextrafields;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
public static final String SPRING_SECURITY_FORM_DOMAIN_KEY = "domain";
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
if (!request.getMethod()
.equals("POST")) {
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
}
UsernamePasswordAuthenticationToken authRequest = getAuthRequest(request);
setDetails(request, authRequest);
return this.getAuthenticationManager()
.authenticate(authRequest);
}
private UsernamePasswordAuthenticationToken getAuthRequest(HttpServletRequest request) {
String username = obtainUsername(request);
String password = obtainPassword(request);
String domain = obtainDomain(request);
if (username == null) {
username = "";
}
if (password == null) {
password = "";
}
if (domain == null) {
domain = "";
}
String usernameDomain = String.format("%s%s%s", username.trim(),
String.valueOf(Character.LINE_SEPARATOR), domain);
return new UsernamePasswordAuthenticationToken(usernameDomain, password);
}
private String obtainDomain(HttpServletRequest request) {
return request.getParameter(SPRING_SECURITY_FORM_DOMAIN_KEY);
}
}

View File

@ -0,0 +1,32 @@
package com.baeldung.securityextrafields;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
@Service("userDetailsService")
public class CustomUserDetailsService implements UserDetailsService {
private final UserRepository userRepository;
public CustomUserDetailsService(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
String[] usernameAndDomain = StringUtils.split(username, String.valueOf(Character.LINE_SEPARATOR));
if (usernameAndDomain == null || usernameAndDomain.length != 2) {
throw new UsernameNotFoundException("Username and domain must be provided");
}
User user = userRepository.findUser(usernameAndDomain[0], usernameAndDomain[1]);
if (user == null) {
throw new UsernameNotFoundException(
String.format("Username not found for domain, username=%s, domain=%s",
usernameAndDomain[0], usernameAndDomain[1]));
}
return user;
}
}

View File

@ -0,0 +1,26 @@
package com.baeldung.securityextrafields;
import java.util.ArrayList;
import java.util.Collection;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Repository;
@Repository("userRepository")
public class CustomUserRepository implements UserRepository {
@Override
public User findUser(String username, String domain) {
if (StringUtils.isAnyBlank(username, domain)) {
return null;
} else {
Collection<? extends GrantedAuthority> authorities = new ArrayList<>();
User user = new User(username, domain,
"$2a$10$U3GhSMpsMSOE8Kqsbn58/edxDBKlVuYMh7qk/7ErApYFjJzi2VG5K", true,
true, true, true, authorities);
return user;
}
}
}

View File

@ -0,0 +1,65 @@
package com.baeldung.securityextrafields;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.PropertySource;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@EnableWebSecurity
@PropertySource("classpath:/application-extrafields.properties")
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilterBefore(authenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.authorizeRequests()
.antMatchers("/css/**", "/index").permitAll()
.antMatchers("/user/**").authenticated()
.and()
.formLogin().loginPage("/login")
.and()
.logout()
.logoutUrl("/logout");
}
public CustomAuthenticationFilter authenticationFilter() throws Exception {
CustomAuthenticationFilter filter = new CustomAuthenticationFilter();
filter.setAuthenticationManager(authenticationManagerBean());
filter.setAuthenticationFailureHandler(failureHandler());
return filter;
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authProvider());
}
public AuthenticationProvider authProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService);
provider.setPasswordEncoder(passwordEncoder());
return provider;
}
public SimpleUrlAuthenticationFailureHandler failureHandler() {
return new SimpleUrlAuthenticationFailureHandler("/login?error=true");
}
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}

View File

@ -0,0 +1,13 @@
package com.baeldung.securityextrafields;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringExtraLoginFieldsApplication {
public static void main(String[] args) {
SpringApplication.run(SpringExtraLoginFieldsApplication.class, args);
}
}

View File

@ -0,0 +1,23 @@
package com.baeldung.securityextrafields;
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;
public class User extends org.springframework.security.core.userdetails.User {
private static final long serialVersionUID = 1L;
private final String domain;
public User(String username, String domain, String password, boolean enabled,
boolean accountNonExpired, boolean credentialsNonExpired,
boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {
super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
this.domain = domain;
}
public String getDomain() {
return domain;
}
}

View File

@ -0,0 +1,7 @@
package com.baeldung.securityextrafields;
public interface UserRepository {
public User findUser(String username, String domain);
}

View File

@ -0,0 +1,51 @@
package com.baeldung.securityextrafields;
import java.util.Optional;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class WebController {
@RequestMapping("/")
public String root() {
return "redirect:/index";
}
@RequestMapping("/index")
public String index(Model model) {
getDomain().ifPresent(d -> {
model.addAttribute("domain", d);
});
return "index";
}
@RequestMapping("/user/index")
public String userIndex(Model model) {
getDomain().ifPresent(d -> {
model.addAttribute("domain", d);
});
return "user/index";
}
@RequestMapping("/login")
public String login() {
return "login";
}
private Optional<String> getDomain() {
Authentication auth = SecurityContextHolder.getContext()
.getAuthentication();
String domain = null;
if (auth != null && !auth.getClass().equals(AnonymousAuthenticationToken.class)) {
User user = (User) auth.getPrincipal();
domain = user.getDomain();
}
return Optional.ofNullable(domain);
}
}

View File

@ -0,0 +1 @@
spring.thymeleaf.prefix = classpath:/templatesextrafields/

View File

@ -0,0 +1,18 @@
body {
font-family: sans;
font-size: 1em;
}
p.error {
font-weight: bold;
color: red;
}
div.logout {
float: right;
}
.formfield {
margin: 0.5em;
padding: 0.3em;
}

View File

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<head>
<title>Spring Security - Login With Extra Fields</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="/css/main.css" th:href="@{/css/main.css}" />
</head>
<body>
<div th:fragment="logout" class="logout" sec:authorize="isAuthenticated()">
Logged in user: <span sec:authentication="name"></span> |
domain: <span th:text="${domain}">Some Domain</span>
<div>
<form action="#" th:action="@{/logout}" method="post">
<input type="submit" value="Logout" />
</form>
</div>
</div>
<h1>Hello Spring Security</h1>
<p>This is an unsecured page, but you can access the secured pages after authenticating.</p>
<ul>
<li>Go to the <a href="/user/index" th:href="@{/user/index}">secured pages</a></li>
</ul>
</body>
</html>

View File

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<title>Login page</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="/css/main.css" th:href="@{/css/main.css}" />
</head>
<body>
<h1>Login page</h1>
<p>Example: user / domain / password</p>
<p th:if="${param.error}" class="error">Invalid user, password, or domain</p>
<form th:action="@{/login}" method="post">
<label for="username">Username</label>:
<input class="formfield" type="text" id="username" name="username" autofocus="autofocus" /> <br />
<label for="domain">Domain</label>:
<input class="formfield" type="text" id="domain" name="domain" /> <br />
<label for="password">Password</label>:
<input class="formfield" type="password" id="password" name="password" /> <br />
<input type="submit" value="Log in" />
</form>
<p><a href="/index" th:href="@{/index}">Back to home page</a></p>
</body>
</html>

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<title>Spring Security - Login With Extra Fields</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="/css/main.css" th:href="@{/css/main.css}" />
</head>
<body>
<div th:replace="index::logout"></div>
<h1>This is a secured page!</h1>
<p><a href="/index" th:href="@{/index}">Back to home page</a></p>
</body>
</html>

View File

@ -0,0 +1,103 @@
package com.baeldung.securityextrafields;
import static org.junit.Assert.assertEquals;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrlPattern;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.util.ArrayList;
import java.util.Collection;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.mock.web.MockHttpSession;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
@RunWith(SpringRunner.class)
@SpringJUnitWebConfig
@SpringBootTest(classes = SpringExtraLoginFieldsApplication.class)
public class SecurityExtraFieldsTest {
@Autowired
private FilterChainProxy springSecurityFilterChain;
@Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
@Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(wac)
.apply(springSecurity(springSecurityFilterChain)).build();
}
@Test
public void givenRootPathAccess_thenRedirectToIndex() throws Exception {
this.mockMvc.perform(get("/"))
.andExpect(status().is3xxRedirection())
.andExpect(redirectedUrlPattern("/index*"));
}
@Test
public void givenSecuredResource_whenAccessUnauthenticated_thenRequiresAuthentication() throws Exception {
this.mockMvc.perform(get("/user/index"))
.andExpect(status().is3xxRedirection())
.andExpect(redirectedUrlPattern("**/login"));
}
@Test
public void givenAccessSecuredResource_whenAuthenticated_thenAuthHasExtraFields() throws Exception {
MockHttpServletRequestBuilder securedResourceAccess = get("/user/index");
MvcResult unauthenticatedResult = mockMvc.perform(securedResourceAccess)
.andExpect(status().is3xxRedirection())
.andReturn();
MockHttpSession session = (MockHttpSession) unauthenticatedResult.getRequest()
.getSession();
String loginUrl = unauthenticatedResult.getResponse()
.getRedirectedUrl();
User user = getUser();
mockMvc.perform(post(loginUrl)
.param("username", user.getUsername())
.param("password", user.getPassword())
.param("domain", user.getDomain())
.session(session)
.with(csrf()))
.andExpect(status().is3xxRedirection())
.andExpect(redirectedUrlPattern("**/user/index"))
.andReturn();
mockMvc.perform(securedResourceAccess.session(session))
.andExpect(status().isOk());
SecurityContext securityContext
= (SecurityContext) session.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
Authentication auth = securityContext.getAuthentication();
assertEquals(((User)auth.getPrincipal()).getDomain(), user.getDomain());
}
private User getUser() {
Collection<? extends GrantedAuthority> authorities = new ArrayList<>();
return new User("myusername", "mydomain", "password", true, true, true, true, authorities);
}
}

View File

@ -0,0 +1,32 @@
package com.baeldung.kong;
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;
/**
* @author aiet
*/
@RestController
@RequestMapping("/stock")
public class QueryController {
private static int REQUEST_COUNTER = 0;
@GetMapping("/reqcount")
public int getReqCount(){
return REQUEST_COUNTER;
}
@GetMapping("/{code}")
public String getStockPrice(@PathVariable String code){
REQUEST_COUNTER++;
if("BTC".equalsIgnoreCase(code))
return "10000";
else return "N/A";
}
}

View File

@ -0,0 +1,13 @@
package com.baeldung.kong;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class StockApp {
public static void main(String[] args) {
SpringApplication.run(StockApp.class, args);
}
}

View File

@ -1,4 +1,4 @@
server.port=8080 server.port=9090
server.contextPath=/springbootapp server.contextPath=/springbootapp
management.port=8081 management.port=8081
management.address=127.0.0.1 management.address=127.0.0.1

View File

@ -0,0 +1,165 @@
package com.baeldung.kong;
import com.baeldung.kong.domain.APIObject;
import com.baeldung.kong.domain.ConsumerObject;
import com.baeldung.kong.domain.KeyAuthObject;
import com.baeldung.kong.domain.PluginObject;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.*;
import org.springframework.test.context.junit4.SpringRunner;
import java.net.URI;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.DEFINED_PORT;
/**
* @author aiet
*/
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = DEFINED_PORT, classes = StockApp.class)
public class KongAdminAPILiveTest {
private String getStockPrice(String code) {
try {
return restTemplate.getForObject(new URI("http://localhost:8080/stock/" + code), String.class);
} catch (Exception ignored) {
}
return null;
}
@Before
public void init() {
System.setProperty("sun.net.http.allowRestrictedHeaders", "true");
}
@Autowired TestRestTemplate restTemplate;
@Test
public void givenEndpoint_whenQueryStockPrice_thenPriceCorrect() {
String response = getStockPrice("btc");
assertEquals("10000", response);
response = getStockPrice("eth");
assertEquals("N/A", response);
}
@Test
public void givenKongAdminAPI_whenAddAPI_thenAPIAccessibleViaKong() throws Exception {
restTemplate.delete("http://localhost:8001/apis/stock-api");
APIObject stockAPI = new APIObject("stock-api", "stock.api", "http://localhost:8080", "/");
HttpEntity<APIObject> apiEntity = new HttpEntity<>(stockAPI);
ResponseEntity<String> addAPIResp = restTemplate.postForEntity("http://localhost:8001/apis", apiEntity, String.class);
assertEquals(HttpStatus.CREATED, addAPIResp.getStatusCode());
addAPIResp = restTemplate.postForEntity("http://localhost:8001/apis", apiEntity, String.class);
assertEquals(HttpStatus.CONFLICT, addAPIResp.getStatusCode());
String apiListResp = restTemplate.getForObject("http://localhost:8001/apis/", String.class);
assertTrue(apiListResp.contains("stock-api"));
HttpHeaders headers = new HttpHeaders();
headers.set("Host", "stock.api");
RequestEntity<String> requestEntity = new RequestEntity<>(headers, HttpMethod.GET, new URI("http://localhost:8000/stock/btc"));
ResponseEntity<String> stockPriceResp = restTemplate.exchange(requestEntity, String.class);
assertEquals("10000", stockPriceResp.getBody());
}
@Test
public void givenKongAdminAPI_whenAddAPIConsumer_thenAdded() {
restTemplate.delete("http://localhost:8001/consumers/eugenp");
ConsumerObject consumer = new ConsumerObject("eugenp");
HttpEntity<ConsumerObject> addConsumerEntity = new HttpEntity<>(consumer);
ResponseEntity<String> addConsumerResp = restTemplate.postForEntity("http://localhost:8001/consumers/", addConsumerEntity, String.class);
assertEquals(HttpStatus.CREATED, addConsumerResp.getStatusCode());
addConsumerResp = restTemplate.postForEntity("http://localhost:8001/consumers", addConsumerEntity, String.class);
assertEquals(HttpStatus.CONFLICT, addConsumerResp.getStatusCode());
String consumerListResp = restTemplate.getForObject("http://localhost:8001/consumers/", String.class);
assertTrue(consumerListResp.contains("eugenp"));
}
@Test
public void givenAPI_whenEnableAuth_thenAnonymousDenied() throws Exception {
String apiListResp = restTemplate.getForObject("http://localhost:8001/apis/", String.class);
if (!apiListResp.contains("stock-api")) {
givenKongAdminAPI_whenAddAPI_thenAPIAccessibleViaKong();
}
PluginObject authPlugin = new PluginObject("key-auth");
ResponseEntity<String> enableAuthResp = restTemplate.postForEntity("http://localhost:8001/apis/stock-api/plugins", new HttpEntity<>(authPlugin), String.class);
assertTrue(HttpStatus.CREATED == enableAuthResp.getStatusCode() || HttpStatus.CONFLICT == enableAuthResp.getStatusCode());
String pluginsResp = restTemplate.getForObject("http://localhost:8001/apis/stock-api/plugins", String.class);
assertTrue(pluginsResp.contains("key-auth"));
HttpHeaders headers = new HttpHeaders();
headers.set("Host", "stock.api");
RequestEntity<String> requestEntity = new RequestEntity<>(headers, HttpMethod.GET, new URI("http://localhost:8000/stock/btc"));
ResponseEntity<String> stockPriceResp = restTemplate.exchange(requestEntity, String.class);
assertEquals(HttpStatus.UNAUTHORIZED, stockPriceResp.getStatusCode());
}
@Test
public void givenAPIAuthEnabled_whenAddKey_thenAccessAllowed() throws Exception {
String apiListResp = restTemplate.getForObject("http://localhost:8001/apis/", String.class);
if (!apiListResp.contains("stock-api")) {
givenKongAdminAPI_whenAddAPI_thenAPIAccessibleViaKong();
}
String consumerListResp = restTemplate.getForObject("http://localhost:8001/consumers/", String.class);
if (!consumerListResp.contains("eugenp")) {
givenKongAdminAPI_whenAddAPIConsumer_thenAdded();
}
final String consumerKey = "eugenp.pass";
KeyAuthObject keyAuth = new KeyAuthObject(consumerKey);
ResponseEntity<String> keyAuthResp = restTemplate.postForEntity("http://localhost:8001/consumers/eugenp/key-auth", new HttpEntity<>(keyAuth), String.class);
assertTrue(HttpStatus.CREATED == keyAuthResp.getStatusCode() || HttpStatus.CONFLICT == keyAuthResp.getStatusCode());
HttpHeaders headers = new HttpHeaders();
headers.set("Host", "stock.api");
headers.set("apikey", consumerKey);
RequestEntity<String> requestEntity = new RequestEntity<>(headers, HttpMethod.GET, new URI("http://localhost:8000/stock/btc"));
ResponseEntity<String> stockPriceResp = restTemplate.exchange(requestEntity, String.class);
assertEquals("10000", stockPriceResp.getBody());
headers.set("apikey", "wrongpass");
requestEntity = new RequestEntity<>(headers, HttpMethod.GET, new URI("http://localhost:8000/stock/btc"));
stockPriceResp = restTemplate.exchange(requestEntity, String.class);
assertEquals(HttpStatus.FORBIDDEN, stockPriceResp.getStatusCode());
}
@Test
public void givenAdminAPIProxy_whenAddAPIViaProxy_thenAPIAdded() throws Exception {
APIObject adminAPI = new APIObject("admin-api", "admin.api", "http://localhost:8001", "/admin-api");
HttpEntity<APIObject> apiEntity = new HttpEntity<>(adminAPI);
ResponseEntity<String> addAPIResp = restTemplate.postForEntity("http://localhost:8001/apis", apiEntity, String.class);
assertTrue(HttpStatus.CREATED == addAPIResp.getStatusCode() || HttpStatus.CONFLICT == addAPIResp.getStatusCode());
HttpHeaders headers = new HttpHeaders();
headers.set("Host", "admin.api");
APIObject baeldungAPI = new APIObject("baeldung-api", "baeldung.com", "http://ww.baeldung.com", "/");
RequestEntity<APIObject> requestEntity = new RequestEntity<>(baeldungAPI, headers, HttpMethod.POST, new URI("http://localhost:8000/admin-api/apis"));
addAPIResp = restTemplate.exchange(requestEntity, String.class);
assertTrue(HttpStatus.CREATED == addAPIResp.getStatusCode() || HttpStatus.CONFLICT == addAPIResp.getStatusCode());
}
}

View File

@ -0,0 +1,68 @@
package com.baeldung.kong;
import com.baeldung.kong.domain.APIObject;
import com.baeldung.kong.domain.TargetObject;
import com.baeldung.kong.domain.UpstreamObject;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.*;
import org.springframework.test.context.junit4.SpringRunner;
import java.net.URI;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.DEFINED_PORT;
/**
* @author aiet
*/
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = DEFINED_PORT, classes = StockApp.class)
public class KongLoadBalanceLiveTest {
@Before
public void init() {
System.setProperty("sun.net.http.allowRestrictedHeaders", "true");
}
@Autowired TestRestTemplate restTemplate;
@Test
public void givenKongAdminAPI_whenAddAPI_thenAPIAccessibleViaKong() throws Exception {
UpstreamObject upstream = new UpstreamObject("stock.api.service");
ResponseEntity<String> addUpstreamResp = restTemplate.postForEntity("http://localhost:8001/upstreams", new HttpEntity<>(upstream), String.class);
assertTrue(HttpStatus.CREATED == addUpstreamResp.getStatusCode() || HttpStatus.CONFLICT == addUpstreamResp.getStatusCode());
TargetObject testTarget = new TargetObject("localhost:8080", 10);
ResponseEntity<String> addTargetResp = restTemplate.postForEntity("http://localhost:8001/upstreams/stock.api.service/targets", new HttpEntity<>(testTarget), String.class);
assertTrue(HttpStatus.CREATED == addTargetResp.getStatusCode() || HttpStatus.CONFLICT == addTargetResp.getStatusCode());
TargetObject releaseTarget = new TargetObject("localhost:9090", 40);
addTargetResp = restTemplate.postForEntity("http://localhost:8001/upstreams/stock.api.service/targets", new HttpEntity<>(releaseTarget), String.class);
assertTrue(HttpStatus.CREATED == addTargetResp.getStatusCode() || HttpStatus.CONFLICT == addTargetResp.getStatusCode());
APIObject stockAPI = new APIObject("balanced-stock-api", "balanced.stock.api", "http://stock.api.service", "/");
HttpEntity<APIObject> apiEntity = new HttpEntity<>(stockAPI);
ResponseEntity<String> addAPIResp = restTemplate.postForEntity("http://localhost:8001/apis", apiEntity, String.class);
assertTrue(HttpStatus.CREATED == addAPIResp.getStatusCode() || HttpStatus.CONFLICT == addAPIResp.getStatusCode());
HttpHeaders headers = new HttpHeaders();
headers.set("Host", "balanced.stock.api");
for (int i = 0; i < 1000; i++) {
RequestEntity<String> requestEntity = new RequestEntity<>(headers, HttpMethod.GET, new URI("http://localhost:8000/stock/btc"));
ResponseEntity<String> stockPriceResp = restTemplate.exchange(requestEntity, String.class);
assertEquals("10000", stockPriceResp.getBody());
}
int releaseCount = restTemplate.getForObject("http://localhost:9090/stock/reqcount", Integer.class);
int testCount = restTemplate.getForObject("http://localhost:8080/stock/reqcount", Integer.class);
assertTrue(Math.round(releaseCount * 1.0 / testCount) == 4);
}
}

View File

@ -0,0 +1,54 @@
package com.baeldung.kong.domain;
/**
* @author aiet
*/
public class APIObject {
public APIObject() {
}
public APIObject(String name, String hosts, String upstream_url, String uris) {
this.name = name;
this.hosts = hosts;
this.upstream_url = upstream_url;
this.uris = uris;
}
private String name;
private String hosts;
private String upstream_url;
private String uris;
public String getUris() {
return uris;
}
public void setUris(String uris) {
this.uris = uris;
}
public String getUpstream_url() {
return upstream_url;
}
public void setUpstream_url(String upstream_url) {
this.upstream_url = upstream_url;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getHosts() {
return hosts;
}
public void setHosts(String hosts) {
this.hosts = hosts;
}
}

View File

@ -0,0 +1,35 @@
package com.baeldung.kong.domain;
/**
* @author aiet
*/
public class ConsumerObject {
private String username;
private String custom_id;
public ConsumerObject(String username) {
this.username = username;
}
public ConsumerObject(String username, String custom_id) {
this.username = username;
this.custom_id = custom_id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getCustom_id() {
return custom_id;
}
public void setCustom_id(String custom_id) {
this.custom_id = custom_id;
}
}

View File

@ -0,0 +1,21 @@
package com.baeldung.kong.domain;
/**
* @author aiet
*/
public class KeyAuthObject {
public KeyAuthObject(String key) {
this.key = key;
}
private String key;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
}

View File

@ -0,0 +1,30 @@
package com.baeldung.kong.domain;
/**
* @author aiet
*/
public class PluginObject {
private String name;
private String consumer_id;
public PluginObject(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getConsumer_id() {
return consumer_id;
}
public void setConsumer_id(String consumer_id) {
this.consumer_id = consumer_id;
}
}

View File

@ -0,0 +1,31 @@
package com.baeldung.kong.domain;
/**
* @author aiet
*/
public class TargetObject {
public TargetObject(String target, int weight) {
this.target = target;
this.weight = weight;
}
private String target;
private int weight;
public String getTarget() {
return target;
}
public void setTarget(String target) {
this.target = target;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
}

View File

@ -0,0 +1,21 @@
package com.baeldung.kong.domain;
/**
* @author aiet
*/
public class UpstreamObject {
public UpstreamObject(String name) {
this.name = name;
}
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

View File

@ -19,4 +19,6 @@
### Relevant Articles: ### Relevant Articles:
- [Introduction to Spring Cloud Rest Client with Netflix Ribbon](http://www.baeldung.com/spring-cloud-rest-client-with-netflix-ribbon) - [Introduction to Spring Cloud Rest Client with Netflix Ribbon](http://www.baeldung.com/spring-cloud-rest-client-with-netflix-ribbon)
[An Introduction to Spring Cloud Zookeeper](http://www.baeldung.com/spring-cloud-zookeeper) - [An Introduction to Spring Cloud Zookeeper](http://www.baeldung.com/spring-cloud-zookeeper)
- [Spring Cloud Connectors and Heroku](http://www.baeldung.com/spring-cloud-heroku)

View File

@ -11,10 +11,9 @@ public class Person {
private Date dateOfBirth; private Date dateOfBirth;
public Person() { public Person() {
} }
public Person(int age, String fullName, Date dateOfBirth) { Person(int age, String fullName, Date dateOfBirth) {
super(); super();
this.age = age; this.age = age;
this.fullName = fullName; this.fullName = fullName;

View File

@ -19,6 +19,7 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import static org.elasticsearch.node.NodeBuilder.nodeBuilder; import static org.elasticsearch.node.NodeBuilder.nodeBuilder;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
@ -78,12 +79,9 @@ public class ElasticSearchManualTest {
SearchHit[] searchHits = response SearchHit[] searchHits = response
.getHits() .getHits()
.getHits(); .getHits();
List<Person> results = new ArrayList<>(); List<Person> results = Arrays.stream(searchHits)
for (SearchHit hit : searchHits) { .map(hit -> JSON.parseObject(hit.getSourceAsString(), Person.class))
String sourceAsString = hit.getSourceAsString(); .collect(Collectors.toList());
Person person = JSON.parseObject(sourceAsString, Person.class);
results.add(person);
}
} }
@Test @Test
@ -125,11 +123,10 @@ public class ElasticSearchManualTest {
.actionGet(); .actionGet();
response2.getHits(); response2.getHits();
response3.getHits(); response3.getHits();
List<SearchHit> searchHits = Arrays.asList(response
.getHits() final List<Person> results = Arrays.stream(response.getHits().getHits())
.getHits()); .map(hit -> JSON.parseObject(hit.getSourceAsString(), Person.class))
final List<Person> results = new ArrayList<>(); .collect(Collectors.toList());
searchHits.forEach(hit -> results.add(JSON.parseObject(hit.getSourceAsString(), Person.class)));
} }
@Test @Test

View File

@ -1,11 +1,6 @@
package com.baeldung.elasticsearch; package com.baeldung.elasticsearch;
import static org.junit.Assert.assertTrue; import com.baeldung.spring.data.es.config.Config;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.index.IndexResponse; import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchResponse;
@ -15,6 +10,7 @@ import org.elasticsearch.common.geo.builders.ShapeBuilder;
import org.elasticsearch.common.unit.DistanceUnit; import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -24,14 +20,19 @@ import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.baeldung.spring.data.es.config.Config; import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import static org.junit.Assert.assertTrue;
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = Config.class) @ContextConfiguration(classes = Config.class)
public class GeoQueriesTest { public class GeoQueriesTest {
public static final String WONDERS_OF_WORLD = "wonders-of-world"; private static final String WONDERS_OF_WORLD = "wonders-of-world";
public static final String WONDERS = "Wonders"; private static final String WONDERS = "Wonders";
@Autowired @Autowired
private ElasticsearchTemplate elasticsearchTemplate; private ElasticsearchTemplate elasticsearchTemplate;
@ -73,9 +74,7 @@ public class GeoQueriesTest {
.actionGet(); .actionGet();
List<String> ids = Arrays.stream(searchResponse.getHits() List<String> ids = Arrays.stream(searchResponse.getHits()
.getHits()) .getHits())
.map(hit -> { .map(SearchHit::getId)
return hit.getId();
})
.collect(Collectors.toList()); .collect(Collectors.toList());
assertTrue(ids.contains(tajMahalId)); assertTrue(ids.contains(tajMahalId));
} }
@ -103,9 +102,7 @@ public class GeoQueriesTest {
.actionGet(); .actionGet();
List<String> ids = Arrays.stream(searchResponse.getHits() List<String> ids = Arrays.stream(searchResponse.getHits()
.getHits()) .getHits())
.map(hit -> { .map(SearchHit::getId)
return hit.getId();
})
.collect(Collectors.toList()); .collect(Collectors.toList());
assertTrue(ids.contains(pyramidsOfGizaId)); assertTrue(ids.contains(pyramidsOfGizaId));
} }
@ -133,9 +130,7 @@ public class GeoQueriesTest {
.actionGet(); .actionGet();
List<String> ids = Arrays.stream(searchResponse.getHits() List<String> ids = Arrays.stream(searchResponse.getHits()
.getHits()) .getHits())
.map(hit -> { .map(SearchHit::getId)
return hit.getId();
})
.collect(Collectors.toList()); .collect(Collectors.toList());
assertTrue(ids.contains(lighthouseOfAlexandriaId)); assertTrue(ids.contains(lighthouseOfAlexandriaId));
} }
@ -164,9 +159,7 @@ public class GeoQueriesTest {
.actionGet(); .actionGet();
List<String> ids = Arrays.stream(searchResponse.getHits() List<String> ids = Arrays.stream(searchResponse.getHits()
.getHits()) .getHits())
.map(hit -> { .map(SearchHit::getId)
return hit.getId();
})
.collect(Collectors.toList()); .collect(Collectors.toList());
assertTrue(ids.contains(greatRannOfKutchid)); assertTrue(ids.contains(greatRannOfKutchid));
} }
@ -175,5 +168,4 @@ public class GeoQueriesTest {
public void destroy() { public void destroy() {
elasticsearchTemplate.deleteIndex(WONDERS_OF_WORLD); elasticsearchTemplate.deleteIndex(WONDERS_OF_WORLD);
} }
} }

View File

@ -1,15 +1,9 @@
package com.baeldung.spring.data.es; package com.baeldung.spring.data.es;
import static java.util.Arrays.asList; import com.baeldung.spring.data.es.config.Config;
import static org.elasticsearch.index.query.MatchQueryBuilder.Operator.AND; import com.baeldung.spring.data.es.model.Article;
import static org.elasticsearch.index.query.QueryBuilders.fuzzyQuery; import com.baeldung.spring.data.es.model.Author;
import static org.elasticsearch.index.query.QueryBuilders.matchQuery; import com.baeldung.spring.data.es.service.ArticleService;
import static org.elasticsearch.index.query.QueryBuilders.regexpQuery;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.util.List;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -22,10 +16,15 @@ import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.baeldung.spring.data.es.config.Config; import java.util.List;
import com.baeldung.spring.data.es.model.Article;
import com.baeldung.spring.data.es.model.Author; import static java.util.Arrays.asList;
import com.baeldung.spring.data.es.service.ArticleService; import static org.elasticsearch.index.query.MatchQueryBuilder.Operator.AND;
import static org.elasticsearch.index.query.QueryBuilders.fuzzyQuery;
import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
import static org.elasticsearch.index.query.QueryBuilders.regexpQuery;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = Config.class) @ContextConfiguration(classes = Config.class)
@ -72,21 +71,24 @@ public class ElasticSearchIntegrationTest {
@Test @Test
public void givenPersistedArticles_whenSearchByAuthorsName_thenRightFound() { public void givenPersistedArticles_whenSearchByAuthorsName_thenRightFound() {
final Page<Article> articleByAuthorName = articleService.findByAuthorName(johnSmith.getName(), new PageRequest(0, 10)); final Page<Article> articleByAuthorName = articleService
.findByAuthorName(johnSmith.getName(), new PageRequest(0, 10));
assertEquals(2L, articleByAuthorName.getTotalElements()); assertEquals(2L, articleByAuthorName.getTotalElements());
} }
@Test @Test
public void givenCustomQuery_whenSearchByAuthorsName_thenArticleIsFound() { public void givenCustomQuery_whenSearchByAuthorsName_thenArticleIsFound() {
final Page<Article> articleByAuthorName = articleService.findByAuthorNameUsingCustomQuery("John Smith", new PageRequest(0, 10)); final Page<Article> articleByAuthorName = articleService
.findByAuthorNameUsingCustomQuery("John Smith", new PageRequest(0, 10));
assertEquals(3L, articleByAuthorName.getTotalElements()); assertEquals(3L, articleByAuthorName.getTotalElements());
} }
@Test @Test
public void givenPersistedArticles_whenUseRegexQuery_thenRightArticlesFound() { public void givenPersistedArticles_whenUseRegexQuery_thenRightArticlesFound() {
final SearchQuery searchQuery = new NativeSearchQueryBuilder().withFilter(regexpQuery("title", ".*data.*")).build(); final SearchQuery searchQuery = new NativeSearchQueryBuilder().withFilter(regexpQuery("title", ".*data.*"))
.build();
final List<Article> articles = elasticsearchTemplate.queryForList(searchQuery, Article.class); final List<Article> articles = elasticsearchTemplate.queryForList(searchQuery, Article.class);
assertEquals(1, articles.size()); assertEquals(1, articles.size());
@ -112,7 +114,8 @@ public class ElasticSearchIntegrationTest {
final String articleTitle = "Spring Data Elasticsearch"; final String articleTitle = "Spring Data Elasticsearch";
final SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchQuery("title", articleTitle).minimumShouldMatch("75%")).build(); final SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(matchQuery("title", articleTitle).minimumShouldMatch("75%")).build();
final List<Article> articles = elasticsearchTemplate.queryForList(searchQuery, Article.class); final List<Article> articles = elasticsearchTemplate.queryForList(searchQuery, Article.class);
assertEquals(1, articles.size()); assertEquals(1, articles.size());
final long count = articleService.count(); final long count = articleService.count();
@ -124,7 +127,8 @@ public class ElasticSearchIntegrationTest {
@Test @Test
public void givenSavedDoc_whenOneTermMatches_thenFindByTitle() { public void givenSavedDoc_whenOneTermMatches_thenFindByTitle() {
final SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchQuery("title", "Search engines").operator(AND)).build(); final SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(matchQuery("title", "Search engines").operator(AND)).build();
final List<Article> articles = elasticsearchTemplate.queryForList(searchQuery, Article.class); final List<Article> articles = elasticsearchTemplate.queryForList(searchQuery, Article.class);
assertEquals(1, articles.size()); assertEquals(1, articles.size());
} }

View File

@ -1,20 +1,9 @@
package com.baeldung.spring.data.es; package com.baeldung.spring.data.es;
import static java.util.Arrays.asList; import com.baeldung.spring.data.es.config.Config;
import static java.util.stream.Collectors.toList; import com.baeldung.spring.data.es.model.Article;
import static org.elasticsearch.index.query.MatchQueryBuilder.Operator.AND; import com.baeldung.spring.data.es.model.Author;
import static org.elasticsearch.index.query.QueryBuilders.boolQuery; import com.baeldung.spring.data.es.service.ArticleService;
import static org.elasticsearch.index.query.QueryBuilders.matchPhraseQuery;
import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
import static org.elasticsearch.index.query.QueryBuilders.multiMatchQuery;
import static org.elasticsearch.index.query.QueryBuilders.nestedQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.junit.Assert.assertEquals;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.Client; import org.elasticsearch.client.Client;
import org.elasticsearch.common.unit.Fuzziness; import org.elasticsearch.common.unit.Fuzziness;
@ -22,6 +11,7 @@ import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.search.aggregations.Aggregation; import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders; import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.MultiBucketsAggregation;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms; import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms; import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsBuilder; import org.elasticsearch.search.aggregations.bucket.terms.TermsBuilder;
@ -35,10 +25,20 @@ import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.baeldung.spring.data.es.config.Config; import java.util.Collections;
import com.baeldung.spring.data.es.model.Article; import java.util.List;
import com.baeldung.spring.data.es.model.Author; import java.util.Map;
import com.baeldung.spring.data.es.service.ArticleService;
import static java.util.Arrays.asList;
import static java.util.stream.Collectors.toList;
import static org.elasticsearch.index.query.MatchQueryBuilder.Operator.AND;
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.matchPhraseQuery;
import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
import static org.elasticsearch.index.query.QueryBuilders.multiMatchQuery;
import static org.elasticsearch.index.query.QueryBuilders.nestedQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.junit.Assert.assertEquals;
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = Config.class) @ContextConfiguration(classes = Config.class)
@ -86,14 +86,16 @@ public class ElasticSearchQueryIntegrationTest {
@Test @Test
public void givenFullTitle_whenRunMatchQuery_thenDocIsFound() { public void givenFullTitle_whenRunMatchQuery_thenDocIsFound() {
final SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchQuery("title", "Search engines").operator(AND)).build(); final SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(matchQuery("title", "Search engines").operator(AND)).build();
final List<Article> articles = elasticsearchTemplate.queryForList(searchQuery, Article.class); final List<Article> articles = elasticsearchTemplate.queryForList(searchQuery, Article.class);
assertEquals(1, articles.size()); assertEquals(1, articles.size());
} }
@Test @Test
public void givenOneTermFromTitle_whenRunMatchQuery_thenDocIsFound() { public void givenOneTermFromTitle_whenRunMatchQuery_thenDocIsFound() {
final SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchQuery("title", "Engines Solutions")).build(); final SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(matchQuery("title", "Engines Solutions")).build();
final List<Article> articles = elasticsearchTemplate.queryForList(searchQuery, Article.class); final List<Article> articles = elasticsearchTemplate.queryForList(searchQuery, Article.class);
assertEquals(1, articles.size()); assertEquals(1, articles.size());
assertEquals("Search engines", articles.get(0).getTitle()); assertEquals("Search engines", articles.get(0).getTitle());
@ -101,18 +103,21 @@ public class ElasticSearchQueryIntegrationTest {
@Test @Test
public void givenPartTitle_whenRunMatchQuery_thenDocIsFound() { public void givenPartTitle_whenRunMatchQuery_thenDocIsFound() {
final SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchQuery("title", "elasticsearch data")).build(); final SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(matchQuery("title", "elasticsearch data")).build();
final List<Article> articles = elasticsearchTemplate.queryForList(searchQuery, Article.class); final List<Article> articles = elasticsearchTemplate.queryForList(searchQuery, Article.class);
assertEquals(3, articles.size()); assertEquals(3, articles.size());
} }
@Test @Test
public void givenFullTitle_whenRunMatchQueryOnVerbatimField_thenDocIsFound() { public void givenFullTitle_whenRunMatchQueryOnVerbatimField_thenDocIsFound() {
SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchQuery("title.verbatim", "Second Article About Elasticsearch")).build(); SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(matchQuery("title.verbatim", "Second Article About Elasticsearch")).build();
List<Article> articles = elasticsearchTemplate.queryForList(searchQuery, Article.class); List<Article> articles = elasticsearchTemplate.queryForList(searchQuery, Article.class);
assertEquals(1, articles.size()); assertEquals(1, articles.size());
searchQuery = new NativeSearchQueryBuilder().withQuery(matchQuery("title.verbatim", "Second Article About")).build(); searchQuery = new NativeSearchQueryBuilder().withQuery(matchQuery("title.verbatim", "Second Article About"))
.build();
articles = elasticsearchTemplate.queryForList(searchQuery, Article.class); articles = elasticsearchTemplate.queryForList(searchQuery, Article.class);
assertEquals(0, articles.size()); assertEquals(0, articles.size());
} }
@ -130,38 +135,48 @@ public class ElasticSearchQueryIntegrationTest {
@Test @Test
public void givenAnalyzedQuery_whenMakeAggregationOnTermCount_thenEachTokenCountsSeparately() { public void givenAnalyzedQuery_whenMakeAggregationOnTermCount_thenEachTokenCountsSeparately() {
final TermsBuilder aggregation = AggregationBuilders.terms("top_tags").field("title"); final TermsBuilder aggregation = AggregationBuilders.terms("top_tags").field("title");
final SearchResponse response = client.prepareSearch("blog").setTypes("article").addAggregation(aggregation).execute().actionGet(); final SearchResponse response = client.prepareSearch("blog").setTypes("article").addAggregation(aggregation)
.execute().actionGet();
final Map<String, Aggregation> results = response.getAggregations().asMap(); final Map<String, Aggregation> results = response.getAggregations().asMap();
final StringTerms topTags = (StringTerms) results.get("top_tags"); final StringTerms topTags = (StringTerms) results.get("top_tags");
final List<String> keys = topTags.getBuckets().stream().map(b -> b.getKeyAsString()).collect(toList()); final List<String> keys = topTags.getBuckets().stream()
Collections.sort(keys); .map(MultiBucketsAggregation.Bucket::getKeyAsString)
.sorted()
.collect(toList());
assertEquals(asList("about", "article", "data", "elasticsearch", "engines", "search", "second", "spring", "tutorial"), keys); assertEquals(asList("about", "article", "data", "elasticsearch", "engines", "search", "second", "spring", "tutorial"), keys);
} }
@Test @Test
public void givenNotAnalyzedQuery_whenMakeAggregationOnTermCount_thenEachTermCountsIndividually() { public void givenNotAnalyzedQuery_whenMakeAggregationOnTermCount_thenEachTermCountsIndividually() {
final TermsBuilder aggregation = AggregationBuilders.terms("top_tags").field("tags").order(Terms.Order.aggregation("_count", false)); final TermsBuilder aggregation = AggregationBuilders.terms("top_tags").field("tags")
final SearchResponse response = client.prepareSearch("blog").setTypes("article").addAggregation(aggregation).execute().actionGet(); .order(Terms.Order.aggregation("_count", false));
final SearchResponse response = client.prepareSearch("blog").setTypes("article").addAggregation(aggregation)
.execute().actionGet();
final Map<String, Aggregation> results = response.getAggregations().asMap(); final Map<String, Aggregation> results = response.getAggregations().asMap();
final StringTerms topTags = (StringTerms) results.get("top_tags"); final StringTerms topTags = (StringTerms) results.get("top_tags");
final List<String> keys = topTags.getBuckets().stream().map(b -> b.getKeyAsString()).collect(toList()); final List<String> keys = topTags.getBuckets().stream()
.map(MultiBucketsAggregation.Bucket::getKeyAsString)
.collect(toList());
assertEquals(asList("elasticsearch", "spring data", "search engines", "tutorial"), keys); assertEquals(asList("elasticsearch", "spring data", "search engines", "tutorial"), keys);
} }
@Test @Test
public void givenNotExactPhrase_whenUseSlop_thenQueryMatches() { public void givenNotExactPhrase_whenUseSlop_thenQueryMatches() {
final SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchPhraseQuery("title", "spring elasticsearch").slop(1)).build(); final SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(matchPhraseQuery("title", "spring elasticsearch").slop(1)).build();
final List<Article> articles = elasticsearchTemplate.queryForList(searchQuery, Article.class); final List<Article> articles = elasticsearchTemplate.queryForList(searchQuery, Article.class);
assertEquals(1, articles.size()); assertEquals(1, articles.size());
} }
@Test @Test
public void givenPhraseWithType_whenUseFuzziness_thenQueryMatches() { public void givenPhraseWithType_whenUseFuzziness_thenQueryMatches() {
final SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchQuery("title", "spring date elasticserch").operator(AND).fuzziness(Fuzziness.ONE).prefixLength(3)).build(); final SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(matchQuery("title", "spring date elasticserch").operator(AND).fuzziness(Fuzziness.ONE)
.prefixLength(3)).build();
final List<Article> articles = elasticsearchTemplate.queryForList(searchQuery, Article.class); final List<Article> articles = elasticsearchTemplate.queryForList(searchQuery, Article.class);
assertEquals(1, articles.size()); assertEquals(1, articles.size());
@ -169,7 +184,9 @@ public class ElasticSearchQueryIntegrationTest {
@Test @Test
public void givenMultimatchQuery_whenDoSearch_thenAllProvidedFieldsMatch() { public void givenMultimatchQuery_whenDoSearch_thenAllProvidedFieldsMatch() {
final SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(multiMatchQuery("tutorial").field("title").field("tags").type(MultiMatchQueryBuilder.Type.BEST_FIELDS)).build(); final SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(multiMatchQuery("tutorial").field("title").field("tags")
.type(MultiMatchQueryBuilder.Type.BEST_FIELDS)).build();
final List<Article> articles = elasticsearchTemplate.queryForList(searchQuery, Article.class); final List<Article> articles = elasticsearchTemplate.queryForList(searchQuery, Article.class);
assertEquals(2, articles.size()); assertEquals(2, articles.size());

View File

@ -1,92 +0,0 @@
<?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>
<artifactId>spring-reactive-websocket</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>spring-reactive-websocket</name>
<description>Reactive WebSockets with Spring 5</description>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-integration</artifactId>
<version>2.0.0.M7</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<version>2.0.0.M7</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>compile</scope>
<version>RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>

View File

@ -1,38 +0,0 @@
package com.baeldung;
import java.net.URI;
import java.time.Duration;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.reactive.socket.WebSocketMessage;
import org.springframework.web.reactive.socket.client.ReactorNettyWebSocketClient;
import org.springframework.web.reactive.socket.client.WebSocketClient;
import reactor.core.publisher.Mono;
@SpringBootApplication
public class ReactiveWebSocketApplication {
public static void main(String[] args) {
SpringApplication.run(ReactiveWebSocketApplication.class, args);
}
/**
* Spring Reactive WebSocket Client
* **/
@Bean
CommandLineRunner runner() {
return run -> {
WebSocketClient client = new ReactorNettyWebSocketClient();
client.execute(URI.create("ws://localhost:8080/event-emitter"), session -> session.send(Mono.just(session.textMessage("event-me-from-spring-reactive-client")))
.thenMany(session.receive()
.map(WebSocketMessage::getPayloadAsText)
.log())
.then())
.block();
// .block(Duration.ofSeconds(10L));//force timeout after given duration
};
}
}

View File

@ -84,14 +84,13 @@
<exclude>**/JdbcTest.java</exclude> <exclude>**/JdbcTest.java</exclude>
<exclude>**/*LiveTest.java</exclude> <exclude>**/*LiveTest.java</exclude>
</excludes> </excludes>
</configuration> </configuration>
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
<properties> <properties>
<spring.version>5.0.1.RELEASE</spring.version> <spring.version>5.0.2.RELEASE</spring.version>
<maven-surefire-plugin.version>2.19.1</maven-surefire-plugin.version> <maven-surefire-plugin.version>2.19.1</maven-surefire-plugin.version>
<junit.version>4.12</junit.version> <junit.version>4.12</junit.version>
<jackson.library>2.9.2</jackson.library> <jackson.library>2.9.2</jackson.library>

View File

@ -5,3 +5,4 @@
- [The Guide to RestTemplate](http://www.baeldung.com/rest-template) - [The Guide to RestTemplate](http://www.baeldung.com/rest-template)
- [Spring RequestMapping](http://www.baeldung.com/spring-requestmapping) - [Spring RequestMapping](http://www.baeldung.com/spring-requestmapping)
- [ETags for REST with Spring](http://www.baeldung.com/etags-for-rest-with-spring) - [ETags for REST with Spring](http://www.baeldung.com/etags-for-rest-with-spring)
- [Spring and Apache FileUpload](http://www.baeldung.com/spring-apache-file-upload)

View File

@ -12,10 +12,10 @@
<description>Spring OpenID sample project</description> <description>Spring OpenID sample project</description>
<parent> <parent>
<artifactId>parent-boot-5</artifactId> <groupId>org.springframework.boot</groupId>
<groupId>com.baeldung</groupId> <artifactId>spring-boot-starter-parent</artifactId>
<version>0.0.1-SNAPSHOT</version> <version>2.0.0.M7</version>
<relativePath>../parent-boot-5</relativePath> <relativePath />
</parent> </parent>
<dependencies> <dependencies>
@ -37,13 +37,36 @@
<dependency> <dependency>
<groupId>org.springframework.security.oauth</groupId> <groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId> <artifactId>spring-security-oauth2</artifactId>
<version>2.2.1.RELEASE</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.security</groupId> <groupId>org.springframework.security</groupId>
<artifactId>spring-security-jwt</artifactId> <artifactId>spring-security-jwt</artifactId>
<version>1.0.9.RELEASE</version>
</dependency> </dependency>
</dependencies> </dependencies>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project> </project>

View File

@ -2,7 +2,7 @@ package org.baeldung.config;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.support.SpringBootServletInitializer; import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
@SpringBootApplication @SpringBootApplication
public class SpringOpenidApplication extends SpringBootServletInitializer { public class SpringOpenidApplication extends SpringBootServletInitializer {

View File

@ -1,3 +1,6 @@
## Testing Modules ## Testing Modules
### Relevant Articles:
- [Quick Guide to BDDMockito](http://www.baeldung.com/bdd-mockito)