This commit is contained in:
Ahmed Tawila 2017-10-23 10:58:32 +02:00
commit c768592435
81 changed files with 771 additions and 333 deletions

View File

@ -11,3 +11,6 @@
- [String Search Algorithms for Large Texts](http://www.baeldung.com/java-full-text-search-algorithms) - [String Search Algorithms for Large Texts](http://www.baeldung.com/java-full-text-search-algorithms)
- [Test a Linked List for Cyclicity](http://www.baeldung.com/java-linked-list-cyclicity) - [Test a Linked List for Cyclicity](http://www.baeldung.com/java-linked-list-cyclicity)
- [Binary Search Algorithm in Java](http://www.baeldung.com/java-binary-search) - [Binary Search Algorithm in Java](http://www.baeldung.com/java-binary-search)
- [Bubble Sort in Java](http://www.baeldung.com/java-bubble-sort)
- [Introduction to JGraphT](http://www.baeldung.com/jgrapht)
- [Introduction to Minimax Algorithm](http://www.baeldung.com/java-minimax-algorithm)

View File

@ -19,11 +19,13 @@ public class BubbleSort {
void optimizedBubbleSort(Integer[] arr) { void optimizedBubbleSort(Integer[] arr) {
int i = 0, n = arr.length; int i = 0, n = arr.length;
boolean swapNeeded = true; boolean swapNeeded = true;
while (i < n - 1 && swapNeeded) { while (i < n - 1 && swapNeeded) {
swapNeeded = false; swapNeeded = false;
for (int j = i + 1; j < n - i; j++) { for (int j = 1; j < n - i; j++) {
if (arr[j - 1] > arr[j]) { if (arr[j - 1] > arr[j]) {
int temp = arr[j - 1]; int temp = arr[j - 1];
arr[j - 1] = arr[j]; arr[j - 1] = arr[j];
arr[j] = temp; arr[j] = temp;

View File

@ -1,92 +0,0 @@
package algorithms;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import com.baeldung.algorithms.mcts.montecarlo.MonteCarloTreeSearch;
import com.baeldung.algorithms.mcts.montecarlo.State;
import com.baeldung.algorithms.mcts.montecarlo.UCT;
import com.baeldung.algorithms.mcts.tictactoe.Board;
import com.baeldung.algorithms.mcts.tictactoe.Position;
import com.baeldung.algorithms.mcts.tree.Tree;
public class MCTSTest {
Tree gameTree;
MonteCarloTreeSearch mcts;
@Before
public void initGameTree() {
gameTree = new Tree();
mcts = new MonteCarloTreeSearch();
}
@Test
public void givenStats_whenGetUCTForNode_thenUCTMatchesWithManualData() {
double uctValue = 15.79;
assertEquals(UCT.uctValue(600, 300, 20), uctValue, 0.01);
}
@Test
public void giveninitBoardState_whenGetAllPossibleStates_thenNonEmptyList() {
State initState = gameTree.getRoot().getState();
List<State> possibleStates = initState.getAllPossibleStates();
assertTrue(possibleStates.size() > 0);
}
@Test
public void givenEmptyBoard_whenPerformMove_thenLessAvailablePossitions() {
Board board = new Board();
int initAvailablePositions = board.getEmptyPositions().size();
board.performMove(Board.P1, new Position(1, 1));
int availablePositions = board.getEmptyPositions().size();
assertTrue(initAvailablePositions > availablePositions);
}
@Test
public void givenEmptyBoard_whenSimulateInterAIPlay_thenGameDraw() {
Board board = new Board();
int player = Board.P1;
int totalMoves = Board.DEFAULT_BOARD_SIZE * Board.DEFAULT_BOARD_SIZE;
for (int i = 0; i < totalMoves; i++) {
board = mcts.findNextMove(board, player);
if (board.checkStatus() != -1) {
break;
}
player = 3 - player;
}
int winStatus = board.checkStatus();
assertEquals(winStatus, Board.DRAW);
}
@Test
public void givenEmptyBoard_whenLevel1VsLevel3_thenLevel3WinsOrDraw() {
Board board = new Board();
MonteCarloTreeSearch mcts1 = new MonteCarloTreeSearch();
mcts1.setLevel(1);
MonteCarloTreeSearch mcts3 = new MonteCarloTreeSearch();
mcts3.setLevel(3);
int player = Board.P1;
int totalMoves = Board.DEFAULT_BOARD_SIZE * Board.DEFAULT_BOARD_SIZE;
for (int i = 0; i < totalMoves; i++) {
if (player == Board.P1)
board = mcts3.findNextMove(board, player);
else
board = mcts1.findNextMove(board, player);
if (board.checkStatus() != -1) {
break;
}
player = 3 - player;
}
int winStatus = board.checkStatus();
assertTrue(winStatus == Board.DRAW || winStatus == Board.P1);
}
}

View File

@ -1 +1,3 @@
## Relevant articles: ## Relevant articles:
[Introduction to Animal Sniffer Maven Plugin](http://www.baeldung.com/maven-animal-sniffer)

View File

@ -1 +1,4 @@
## Relevant articles: ## Relevant articles:
- [Advanced Querying in Apache Cayenne](http://www.baeldung.com/apache-cayenne-query)
- [Introduction to Apache Cayenne ORM](http://www.baeldung.com/apache-cayenne-orm)

View File

@ -1,2 +1,5 @@
## Relevant Articles: ## Relevant Articles:
- [Introduction to Apache CXF Aegis Data Binding](http://www.baeldung.com/aegis-data-binding-in-apache-cxf) - [Introduction to Apache CXF Aegis Data Binding](http://www.baeldung.com/aegis-data-binding-in-apache-cxf)
- [Apache CXF Support for RESTful Web Services](http://www.baeldung.com/apache-cxf-rest-api)
- [A Guide to Apache CXF with Spring](http://www.baeldung.com/apache-cxf-with-spring)
- [Introduction to Apache CXF](http://www.baeldung.com/introduction-to-apache-cxf)

44
apache-spark/pom.xml Normal file
View File

@ -0,0 +1,44 @@
<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>apache-spark</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>apache-spark</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.apache.spark/spark-core_2.10 -->
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-core_2.10</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<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,53 @@
package com.baeldung;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaPairRDD;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.api.java.function.*;
import org.apache.spark.api.java.function.Function2;
import org.apache.spark.api.java.function.PairFunction;
import scala.Tuple2;
public class WordCount {
private static final Pattern SPACE = Pattern.compile(" ");
public static void main(String[] args) throws Exception {
if (args.length < 1) {
System.err.println("Usage: JavaWordCount <file>");
System.exit(1);
}
SparkConf sparkConf = new SparkConf().setAppName("JavaWordCount").setMaster("local");
JavaSparkContext ctx = new JavaSparkContext(sparkConf);
JavaRDD<String> lines = ctx.textFile(args[0], 1);
JavaRDD<String> words = lines.flatMap(s -> Arrays.asList(SPACE.split(s)).iterator());
JavaPairRDD<String, Integer> ones = words.mapToPair(
new PairFunction<String, String, Integer>() {
@Override
public Tuple2<String, Integer> call(String s) {
return new Tuple2<>(s, 1);
}
});
JavaPairRDD<String, Integer> counts = ones.reduceByKey(
new Function2<Integer, Integer, Integer>() {
@Override
public Integer call(Integer i1, Integer i2) {
return i1 + i2;
}
});
List<Tuple2<String, Integer>> output = counts.collect();
for (Tuple2<?, ?> tuple : output) {
System.out.println(tuple._1() + ": " + tuple._2());
}
ctx.stop();
}
}

View File

@ -0,0 +1,3 @@
Hello from Baeldung
Keep Learning Spark
Bye from Baeldung

View File

@ -1 +1,3 @@
## Relevant articles: ## Relevant articles:
- [Introduction to Atomix](http://www.baeldung.com/atomix)

View File

@ -1,3 +1,6 @@
### Relevant articles ### Relevant articles
- [AWS Lambda Using DynamoDB With Java](http://www.baeldung.com/aws-lambda-dynamodb-java) - [AWS Lambda Using DynamoDB With Java](http://www.baeldung.com/aws-lambda-dynamodb-java)
- [AWS S3 with Java](http://www.baeldung.com/aws-s3-java)
- [AWS Lambda With Java](http://www.baeldung.com/java-aws-lambda)

View File

@ -13,3 +13,7 @@ and a BODY Payload like {"id": 1,"name": "World"}
and we will get a return code of 201 and the response: Hello, World - if the transform() method from Application class is uncommented and the process() method is commented and we will get a return code of 201 and the response: Hello, World - if the transform() method from Application class is uncommented and the process() method is commented
or return code of 201 and the response: {"id": 10,"name": "Hello, World"} - if the transform() method from Application class is commented and the process() method is uncommented or return code of 201 and the response: {"id": 10,"name": "Hello, World"} - if the transform() method from Application class is commented and the process() method is uncommented
## Relevant articles:
- [Apache Camel with Spring Boot](http://www.baeldung.com/apache-camel-spring-boot)

View File

@ -71,8 +71,5 @@ public class URIvsURLUnitTest {
URL url = new URL("http://courses.baeldung.com"); URL url = new URL("http://courses.baeldung.com");
String contents = IOUtils.toString(url.openStream()); String contents = IOUtils.toString(url.openStream());
assertTrue(contents.contains("<!DOCTYPE html>"));
} }
} }

View File

@ -1,3 +1,4 @@
### Relevant Articles: ### Relevant Articles:
[Introduction to Drools](http://www.baeldung.com/drools) - [Introduction to Drools](http://www.baeldung.com/drools)
[Drools Using Rules from Excel Files](http://www.baeldung.com/drools-excel) - [Drools Using Rules from Excel Files](http://www.baeldung.com/drools-excel)
- [Drools Using Rules from Excel Files](http://www.baeldung.com/drools-excel)

View File

@ -5,4 +5,6 @@ This is the implementation of a [spring-hypermedia-api][1] client using Feign.
[1]: https://github.com/eugenp/spring-hypermedia-api [1]: https://github.com/eugenp/spring-hypermedia-api
### Relevant Articles: ### Relevant Articles:
- [Intro to Feign](http://www.baeldung.com/intro-to-feign) - [Intro to Feign](http://www.baeldung.com/intro-to-feign)
- [Introduction to SLF4J](http://www.baeldung.com/slf4j-with-log4j2-logback)

View File

@ -1 +1,3 @@
## Relevant articles: ## Relevant articles:
- [Introduction to GraphQL](http://www.baeldung.com/graphql)

View File

@ -1,3 +1,4 @@
### Relevant articles: ### Relevant articles:
- [New Stream, Comparator and Collector Functionality in Guava 21](http://www.baeldung.com/guava-21-new) - [New Stream, Comparator and Collector Functionality in Guava 21](http://www.baeldung.com/guava-21-new)
- [New in Guava 21 common.util.concurrent](http://www.baeldung.com/guava-21-util-concurrent) - [New in Guava 21 common.util.concurrent](http://www.baeldung.com/guava-21-util-concurrent)
- [Zipping Collections in Java](http://www.baeldung.com/java-collections-zip)

View File

@ -1,3 +1,4 @@
### Relevant Articles: ### Relevant Articles:
- [Cachable Static Assets with Spring MVC](http://www.baeldung.com/cachable-static-assets-with-spring-mvc) - [Cachable Static Assets with Spring MVC](http://www.baeldung.com/cachable-static-assets-with-spring-mvc)
- [Minification of JS and CSS Assets with Maven](http://www.baeldung.com/maven-minification-of-js-and-css-assets) - [Minification of JS and CSS Assets with Maven](http://www.baeldung.com/maven-minification-of-js-and-css-assets)
- [Serve Static Resources with Spring](http://www.baeldung.com/spring-mvc-static-resources)

View File

@ -20,3 +20,5 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring
- [HttpAsyncClient Tutorial](http://www.baeldung.com/httpasyncclient-tutorial) - [HttpAsyncClient Tutorial](http://www.baeldung.com/httpasyncclient-tutorial)
- [HttpClient 4 Tutorial](http://www.baeldung.com/httpclient-guide) - [HttpClient 4 Tutorial](http://www.baeldung.com/httpclient-guide)
- [Advanced HttpClient Configuration](http://www.baeldung.com/httpclient-advanced-config) - [Advanced HttpClient Configuration](http://www.baeldung.com/httpclient-advanced-config)
- [HttpClient 4 Do Not Follow Redirects](http://www.baeldung.com/httpclient-stop-follow-redirect)
- [HttpClient 4 Setting a Custom User-Agent](http://www.baeldung.com/httpclient-user-agent-header)

View File

@ -28,3 +28,10 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring
- [A Guide to Optional with Jackson](http://www.baeldung.com/jackson-optional) - [A Guide to Optional with Jackson](http://www.baeldung.com/jackson-optional)
- [Map Serialization and Deserialization with Jackson](http://www.baeldung.com/jackson-map) - [Map Serialization and Deserialization with Jackson](http://www.baeldung.com/jackson-map)
- [Jackson Streaming API](http://www.baeldung.com/jackson-streaming-api) - [Jackson Streaming API](http://www.baeldung.com/jackson-streaming-api)
- [Jackson JsonMappingException (No serializer found for class)](http://www.baeldung.com/jackson-jsonmappingexception)
- [How To Serialize Enums as JSON Objects with Jackson](http://www.baeldung.com/jackson-serialize-enums)
- [Jackson Marshall String to JsonNode](http://www.baeldung.com/jackson-json-to-jsonnode)
- [Ignore Null Fields with Jackson](http://www.baeldung.com/jackson-ignore-null-fields)
- [Jackson Unmarshall to Collection/Array](http://www.baeldung.com/jackson-collection-array)
- [Jackson Change Name of Field](http://www.baeldung.com/jackson-name-of-property)
- [Serialize Only Fields that meet a Custom Criteria with Jackson](http://www.baeldung.com/jackson-serialize-field-custom-criteria)

View File

@ -129,7 +129,7 @@
<properties> <properties>
<!-- marshalling --> <!-- marshalling -->
<jackson.version>2.9.0</jackson.version> <jackson.version>2.9.2</jackson.version>
<!-- util --> <!-- util -->
<guava.version>19.0</guava.version> <guava.version>19.0</guava.version>

View File

@ -0,0 +1,70 @@
package com.baeldung.jackson.deserialization.nested;
import static org.junit.Assert.*;
import java.io.IOException;
import org.junit.Test;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
public class DeserializeWithNestedPropertiesUnitTest {
private String SOURCE_JSON = "{\"id\":\"957c43f2-fa2e-42f9-bf75-6e3d5bb6960a\",\"name\":\"The Best Product\",\"brand\":{\"id\":\"9bcd817d-0141-42e6-8f04-e5aaab0980b6\",\"name\":\"ACME Products\",\"owner\":{\"id\":\"b21a80b1-0c09-4be3-9ebd-ea3653511c13\",\"name\":\"Ultimate Corp, Inc.\"}}}";
@Test
public void whenUsingJacksonAnnotations_thenOk() throws IOException {
Product product = new ObjectMapper().readerFor(Product.class)
.readValue(SOURCE_JSON);
assertEquals(product.getName(), "The Best Product");
assertEquals(product.getBrandName(), "ACME Products");
assertEquals(product.getOwnerName(), "Ultimate Corp, Inc.");
}
@Test
public void whenUsingJacksonJsonNode_thenOk() throws IOException {
JsonNode productNode = new ObjectMapper().readTree(SOURCE_JSON);
Product product = new Product();
product.setId(productNode.get("id")
.textValue());
product.setName(productNode.get("name")
.textValue());
product.setBrandName(productNode.get("brand")
.get("name")
.textValue());
product.setOwnerName(productNode.get("brand")
.get("owner")
.get("name")
.textValue());
assertEquals(product.getName(), "The Best Product");
assertEquals(product.getBrandName(), "ACME Products");
assertEquals(product.getOwnerName(), "Ultimate Corp, Inc.");
}
@Test
public void whenUsingJacksonDeserializerManuallyRegistered_thenOk() throws IOException {
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(Product.class, new ProductDeserializer());
mapper.registerModule(module);
Product product = mapper.readValue(SOURCE_JSON, Product.class);
assertEquals(product.getName(), "The Best Product");
assertEquals(product.getBrandName(), "ACME Products");
assertEquals(product.getOwnerName(), "Ultimate Corp, Inc.");
}
@Test
public void whenUsingJacksonDeserializerAutoRegistered_thenOk() throws IOException {
ObjectMapper mapper = new ObjectMapper();
Product product = mapper.readValue(SOURCE_JSON, Product.class);
assertEquals(product.getName(), "The Best Product");
assertEquals(product.getBrandName(), "ACME Products");
assertEquals(product.getOwnerName(), "Ultimate Corp, Inc.");
}
}

View File

@ -0,0 +1,55 @@
package com.baeldung.jackson.deserialization.nested;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
@JsonDeserialize(using = ProductDeserializer.class)
public class Product {
private String id;
private String name;
private String brandName;
private String ownerName;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getBrandName() {
return brandName;
}
public void setBrandName(String brandName) {
this.brandName = brandName;
}
public String getOwnerName() {
return ownerName;
}
public void setOwnerName(String ownerName) {
this.ownerName = ownerName;
}
@SuppressWarnings("unchecked")
@JsonProperty("brand")
private void unpackNested(Map<String, Object> brand) {
this.brandName = (String) brand.get("name");
Map<String, String> owner = (Map<String, String>) brand.get("owner");
this.ownerName = owner.get("name");
}
}

View File

@ -0,0 +1,40 @@
package com.baeldung.jackson.deserialization.nested;
import java.io.IOException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
@SuppressWarnings("serial")
public class ProductDeserializer extends StdDeserializer<Product> {
public ProductDeserializer() {
this(null);
}
public ProductDeserializer(Class<?> vc) {
super(vc);
}
@Override
public Product deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
JsonNode productNode = jp.getCodec()
.readTree(jp);
Product product = new Product();
product.setId(productNode.get("id")
.textValue());
product.setName(productNode.get("name")
.textValue());
product.setBrandName(productNode.get("brand")
.get("name")
.textValue());
product.setOwnerName(productNode.get("brand")
.get("owner")
.get("name")
.textValue());
return product;
}
}

View File

@ -7,3 +7,4 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring
### Relevant Articles: ### Relevant Articles:
- [Java Bean Validation Basics](http://www.baeldung.com/javax-validation) - [Java Bean Validation Basics](http://www.baeldung.com/javax-validation)
- [Validating Container Elements with Bean Validation 2.0](http://www.baeldung.com/bean-validation-container-elements)

View File

@ -1 +1,4 @@
## Relevant articles: ## Relevant articles:
- [JHipster with a Microservice Architecture](http://www.baeldung.com/jhipster-microservices)
- [Intro to JHipster](http://www.baeldung.com/jhipster)

View File

@ -43,3 +43,7 @@ Available commands (assumes httpie - https://github.com/jkbrzt/httpie):
``` ```
The Baeldung post that compliments this repo can be found [here](http://www.baeldung.com/) The Baeldung post that compliments this repo can be found [here](http://www.baeldung.com/)
## Relevant articles:
- [Supercharge Java Authentication with JSON Web Tokens (JWTs)](http://www.baeldung.com/java-json-web-tokens-jjwt)

View File

@ -1 +1,3 @@
## Relevant articles: ## Relevant articles:
- [Microbenchmarking with Java](http://www.baeldung.com/java-microbenchmark-harness)

View File

@ -1 +1,3 @@
## Relevant articles: ## Relevant articles:
- [Introduction to Jooby Project](http://www.baeldung.com/jooby)

View File

@ -1 +1,3 @@
## Relevant articles: ## Relevant articles:
- [Introduction to JsonPath](http://www.baeldung.com/guide-to-jayway-jsonpath)

View File

@ -1,2 +1,4 @@
### Relevant articles ### Relevant articles
- [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 Kryo](http://www.baeldung.com/kryo)

View File

@ -8,9 +8,9 @@
- [Embedded Jetty Server in Java](http://www.baeldung.com/jetty-embedded) - [Embedded Jetty Server in Java](http://www.baeldung.com/jetty-embedded)
- [Introduction to Apache Flink with Java](http://www.baeldung.com/apache-flink) - [Introduction to Apache Flink with Java](http://www.baeldung.com/apache-flink)
- [Introduction to JSONassert](http://www.baeldung.com/jsonassert) - [Introduction to JSONassert](http://www.baeldung.com/jsonassert)
- [Intro to JaVer](http://www.baeldung.com/javers) - [Intro to JaVers](http://www.baeldung.com/javers)
- [Introduction to Apache Commons Math](http://www.baeldung.com/apache-commons-math) - [Introduction to Apache Commons Math](http://www.baeldung.com/apache-commons-math)
- [Intro to JaVer](http://www.baeldung.com/serenity-bdd) - [Intro to Serenity BDD](http://www.baeldung.com/serenity-bdd)
- [Introduction to Netty](http://www.baeldung.com/netty) - [Introduction to Netty](http://www.baeldung.com/netty)
- [Merging Streams in Java](http://www.baeldung.com/java-merge-streams) - [Merging Streams in Java](http://www.baeldung.com/java-merge-streams)
- [Serenity BDD and Screenplay](http://www.baeldung.com/serenity-screenplay) - [Serenity BDD and Screenplay](http://www.baeldung.com/serenity-screenplay)
@ -53,6 +53,7 @@
- [Using Pairs in Java](http://www.baeldung.com/java-pairs) - [Using Pairs in Java](http://www.baeldung.com/java-pairs)
- [Apache Commons Collections Bag](http://www.baeldung.com/apache-commons-bag) - [Apache Commons Collections Bag](http://www.baeldung.com/apache-commons-bag)
- [Introduction to Caffeine](http://www.baeldung.com/java-caching-caffeine) - [Introduction to Caffeine](http://www.baeldung.com/java-caching-caffeine)
+-[Introduction to Chronicle Queue](http://www.baeldung.com/java-chronicle-queue)
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 +1,3 @@
## Relevant articles: ## Relevant articles:
- [Guide to LinkRest](http://www.baeldung.com/linkrest)

View File

@ -1 +1,7 @@
## Relevant articles: ## Relevant articles:
- [Introduction to MockServer](http://www.baeldung.com/mockserver)
- [JMockit Advanced Usage](http://www.baeldung.com/jmockit-advanced-usage)
- [A Guide to JMockit Expectations](http://www.baeldung.com/jmockit-expectations)
- [JMockit 101](http://www.baeldung.com/jmockit-101)
- [Mockito vs EasyMock vs JMockit](http://www.baeldung.com/mockito-vs-easymock-vs-jmockit)

View File

@ -1 +1,3 @@
## Relevant articles: ## Relevant articles:
- [Introduction to MockServer](http://www.baeldung.com/mockserver)

View File

@ -1 +1,3 @@
## Relevant articles: ## Relevant articles:
- [List of Rules Engines in Java](http://www.baeldung.com/java-rule-engines)

View File

@ -1 +1,3 @@
## Relevant articles: ## Relevant articles:
- [JIRA REST API Integration](http://www.baeldung.com/jira-rest-api)

View File

@ -1 +1,3 @@
## Relevant articles: ## Relevant articles:
- [Drools Spring Integration](http://www.baeldung.com/drools-spring-integration)

View File

@ -1 +1,7 @@
## Relevant articles: ## Relevant articles:
- [Guide to UriComponentsBuilder in Spring](http://www.baeldung.com/spring-uricomponentsbuilder)
- [Returning Custom Status Codes from Spring Controllers](http://www.baeldung.com/spring-mvc-controller-custom-http-status-code)
- [The Guide to RestTemplate](http://www.baeldung.com/rest-template)
- [Spring RequestMapping](http://www.baeldung.com/spring-requestmapping)
- [ETags for REST with Spring](http://www.baeldung.com/etags-for-rest-with-spring)

View File

@ -8,7 +8,10 @@ The "REST With Spring" Classes: http://github.learnspringsecurity.com
### Relevant Articles: ### Relevant Articles:
- [Spring Security Remember Me](http://www.baeldung.com/spring-security-remember-me) - [Spring Security Remember Me](http://www.baeldung.com/spring-security-remember-me)
- [Redirect to different pages after Login with Spring Security](http://www.baeldung.com/spring_redirect_after_login) - [Redirect to different pages after Login with Spring Security](http://www.baeldung.com/spring_redirect_after_login)
- [Changing Spring Model Parameters with Handler Interceptor](http://www.baeldung.com/spring-model-parameters-with-handler-interceptor)
- [Introduction to Spring MVC HandlerInterceptor](http://www.baeldung.com/spring-mvc-handlerinterceptor)
- [Using a Custom Spring MVCs Handler Interceptor to Manage Sessions](http://www.baeldung.com/spring-mvc-custom-handler-interceptor)
- [A Guide to CSRF Protection in Spring Security](http://www.baeldung.com/spring-security-csrf)
### Build the Project ### Build the Project
``` ```

View File

@ -113,6 +113,40 @@
<!-- <version>3.0.1</version> --> <!-- <version>3.0.1</version> -->
<!-- </dependency> --> <!-- </dependency> -->
<!-- util -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson-databind.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<!-- test -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${org.springframework.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<version>${org.springframework.security.version}</version>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>
<build> <build>
@ -174,6 +208,7 @@
<!-- util --> <!-- util -->
<guava.version>19.0</guava.version> <guava.version>19.0</guava.version>
<commons-lang3.version>3.5</commons-lang3.version> <commons-lang3.version>3.5</commons-lang3.version>
<jackson-databind.version>2.9.1</jackson-databind.version>
<httpclient.version>4.5.2</httpclient.version> <httpclient.version>4.5.2</httpclient.version>
<httpcore.version>4.4.5</httpcore.version> <httpcore.version>4.4.5</httpcore.version>

View File

@ -1,9 +1,14 @@
package org.baeldung.spring; package org.baeldung.spring;
import org.baeldung.web.interceptor.LoggerInterceptor;
import org.baeldung.web.interceptor.SessionTimerInterceptor;
import org.baeldung.web.interceptor.UserInterceptor;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver; import org.springframework.web.servlet.view.InternalResourceViewResolver;
@ -11,6 +16,7 @@ import org.springframework.web.servlet.view.JstlView;
@EnableWebMvc @EnableWebMvc
@Configuration @Configuration
@ComponentScan("org.baeldung.web.controller")
public class MvcConfig extends WebMvcConfigurerAdapter { public class MvcConfig extends WebMvcConfigurerAdapter {
public MvcConfig() { public MvcConfig() {
@ -28,6 +34,7 @@ public class MvcConfig extends WebMvcConfigurerAdapter {
registry.addViewController("/login.html"); registry.addViewController("/login.html");
registry.addViewController("/homepage.html"); registry.addViewController("/homepage.html");
registry.addViewController("/console.html"); registry.addViewController("/console.html");
registry.addViewController("/csrfHome.html");
} }
@Bean @Bean
@ -40,4 +47,11 @@ public class MvcConfig extends WebMvcConfigurerAdapter {
return bean; return bean;
} }
@Override
public void addInterceptors(final InterceptorRegistry registry) {
registry.addInterceptor(new LoggerInterceptor());
registry.addInterceptor(new UserInterceptor());
registry.addInterceptor(new SessionTimerInterceptor());
}
} }

View File

@ -12,7 +12,6 @@ import org.springframework.web.bind.annotation.ResponseStatus;
// to test csrf // to test csrf
@Controller @Controller
@RequestMapping(value = "/auth/")
public class BankController { public class BankController {
private final Logger logger = LoggerFactory.getLogger(getClass()); private final Logger logger = LoggerFactory.getLogger(getClass());

View File

@ -0,0 +1,59 @@
package org.baeldung.web.controller;
import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
import java.util.Arrays;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import org.baeldung.web.dto.Foo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.util.UriComponentsBuilder;
@Controller
@RequestMapping(value = "/auth/foos")
public class FooController {
@Autowired
private ApplicationEventPublisher eventPublisher;
public FooController() {
super();
}
// API
// read - single
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
@ResponseBody
public Foo findById(@PathVariable("id") final Long id, final UriComponentsBuilder uriBuilder, final HttpServletResponse response) {
return new Foo(randomAlphabetic(6));
}
// read - multiple
@RequestMapping(method = RequestMethod.GET)
@ResponseBody
public List<Foo> findAll() {
return Arrays.asList(new Foo(randomAlphabetic(6)));
}
// write - just for test
@RequestMapping(method = RequestMethod.POST)
@ResponseStatus(HttpStatus.CREATED)
@ResponseBody
public Foo create(@RequestBody final Foo foo) {
return foo;
}
}

View File

@ -0,0 +1,80 @@
package org.baeldung.web.dto;
import java.io.Serializable;
public class Foo implements Serializable {
private long id;
private String name;
public Foo() {
super();
}
public Foo(final String name) {
super();
this.name = name;
}
// API
public long getId() {
return id;
}
public void setId(final long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
//
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Foo other = (Foo) obj;
if (name == null) {
if (other.name != null) {
return false;
}
} else if (!name.equals(other.name)) {
return false;
}
return true;
}
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append("Foo [name=")
.append(name)
.append("]");
return builder.toString();
}
}

View File

@ -33,4 +33,8 @@
</authentication-provider> </authentication-provider>
</authentication-manager> </authentication-manager>
<!-- <mvc:interceptors>
<bean id="loggerInterceptor" class="org.baeldung.web.interceptor.LoggerInterceptor" />
</mvc:interceptors> -->
</beans:beans> </beans:beans>

View File

@ -5,7 +5,7 @@ import static org.springframework.security.test.web.servlet.request.SecurityMock
import javax.servlet.Filter; import javax.servlet.Filter;
import org.baeldung.persistence.model.Foo; import org.baeldung.web.dto.Foo;
import org.junit.Before; import org.junit.Before;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -14,15 +14,15 @@ import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.RequestPostProcessor; import org.springframework.test.web.servlet.request.RequestPostProcessor;
import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.WebApplicationContext;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration @WebAppConfiguration
@Transactional
public abstract class CsrfAbstractIntegrationTest { public abstract class CsrfAbstractIntegrationTest {
@Autowired @Autowired

View File

@ -0,0 +1,25 @@
package org.baeldung.security.csrf;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.baeldung.security.spring.SecurityWithoutCsrfConfig;
import org.baeldung.spring.MvcConfig;
import org.junit.Test;
import org.springframework.http.MediaType;
import org.springframework.test.context.ContextConfiguration;
@ContextConfiguration(classes = { SecurityWithoutCsrfConfig.class, MvcConfig.class })
public class CsrfDisabledIntegrationTest extends CsrfAbstractIntegrationTest {
@Test
public void givenNotAuth_whenAddFoo_thenUnauthorized() throws Exception {
mvc.perform(post("/auth/foos").contentType(MediaType.APPLICATION_JSON).content(createFoo())).andExpect(status().isUnauthorized());
}
@Test
public void givenAuth_whenAddFoo_thenCreated() throws Exception {
mvc.perform(post("/auth/foos").contentType(MediaType.APPLICATION_JSON).content(createFoo()).with(testUser())).andExpect(status().isCreated());
}
}

View File

@ -5,13 +5,12 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.baeldung.security.spring.SecurityWithCsrfConfig; import org.baeldung.security.spring.SecurityWithCsrfConfig;
import org.baeldung.spring.PersistenceConfig; import org.baeldung.spring.MvcConfig;
import org.baeldung.spring.WebConfig;
import org.junit.Test; import org.junit.Test;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;
@ContextConfiguration(classes = { SecurityWithCsrfConfig.class, PersistenceConfig.class, WebConfig.class }) @ContextConfiguration(classes = { SecurityWithCsrfConfig.class, MvcConfig.class })
public class CsrfEnabledIntegrationTest extends CsrfAbstractIntegrationTest { public class CsrfEnabledIntegrationTest extends CsrfAbstractIntegrationTest {
@Test @Test

View File

@ -1,8 +1,5 @@
package org.baeldung.security.spring; package org.baeldung.security.spring;
import org.baeldung.web.error.CustomAccessDeniedHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
@ -12,14 +9,10 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration @Configuration
@EnableAutoConfiguration
@EnableWebSecurity @EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) @EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityWithCsrfConfig extends WebSecurityConfigurerAdapter { public class SecurityWithCsrfConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomAccessDeniedHandler accessDeniedHandler;
public SecurityWithCsrfConfig() { public SecurityWithCsrfConfig() {
super(); super();
} }
@ -46,8 +39,6 @@ public class SecurityWithCsrfConfig extends WebSecurityConfigurerAdapter {
.and() .and()
.httpBasic() .httpBasic()
.and() .and()
.exceptionHandling().accessDeniedHandler(accessDeniedHandler)
.and()
.headers().cacheControl().disable() .headers().cacheControl().disable()
; ;
// @formatter:on // @formatter:on

View File

@ -1,8 +1,5 @@
package org.baeldung.security.spring; package org.baeldung.security.spring;
import org.baeldung.web.error.CustomAccessDeniedHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
@ -12,16 +9,10 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration @Configuration
@EnableAutoConfiguration
//
@EnableWebSecurity @EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) @EnableGlobalMethodSecurity(prePostEnabled = true)
// @ImportResource({ "classpath:webSecurityConfig.xml" })
public class SecurityWithoutCsrfConfig extends WebSecurityConfigurerAdapter { public class SecurityWithoutCsrfConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomAccessDeniedHandler accessDeniedHandler;
public SecurityWithoutCsrfConfig() { public SecurityWithoutCsrfConfig() {
super(); super();
} }
@ -42,18 +33,15 @@ public class SecurityWithoutCsrfConfig extends WebSecurityConfigurerAdapter {
protected void configure(final HttpSecurity http) throws Exception { protected void configure(final HttpSecurity http) throws Exception {
// @formatter:off // @formatter:off
http http
.csrf().disable()
.authorizeRequests() .authorizeRequests()
.antMatchers("/auth/admin/*").hasRole("ADMIN") .antMatchers("/auth/admin/*").hasAnyRole("ROLE_ADMIN")
.antMatchers("/auth/*").hasAnyRole("ADMIN","USER") .anyRequest().authenticated()
.antMatchers("/*").permitAll()
.and() .and()
.httpBasic() .httpBasic()
.and() .and()
// .exceptionHandling().accessDeniedPage("/my-error-page")
.exceptionHandling().accessDeniedHandler(accessDeniedHandler)
.and()
.headers().cacheControl().disable() .headers().cacheControl().disable()
.and()
.csrf().disable()
; ;
// @formatter:on // @formatter:on
} }

View File

@ -4,8 +4,7 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.baeldung.security.spring.SecurityWithoutCsrfConfig; import org.baeldung.security.spring.SecurityWithoutCsrfConfig;
import org.baeldung.spring.PersistenceConfig; import org.baeldung.spring.MvcConfig;
import org.baeldung.spring.WebConfig;
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;
@ -16,13 +15,11 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.WebApplicationContext;
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration @WebAppConfiguration
@Transactional @ContextConfiguration(classes = { SecurityWithoutCsrfConfig.class, MvcConfig.class })
@ContextConfiguration(classes = { SecurityWithoutCsrfConfig.class, PersistenceConfig.class, WebConfig.class })
public class LoggerInterceptorIntegrationTest { public class LoggerInterceptorIntegrationTest {
@Autowired @Autowired
@ -46,7 +43,8 @@ public class LoggerInterceptorIntegrationTest {
*/ */
@Test @Test
public void testInterceptors() throws Exception { public void testInterceptors() throws Exception {
mockMvc.perform(get("/graph.html")).andExpect(status().isOk()); mockMvc.perform(get("/login.html"))
.andExpect(status().isOk());
} }
} }

View File

@ -6,8 +6,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSession;
import org.baeldung.security.spring.SecurityWithoutCsrfConfig; import org.baeldung.security.spring.SecurityWithoutCsrfConfig;
import org.baeldung.spring.PersistenceConfig; import org.baeldung.spring.MvcConfig;
import org.baeldung.spring.WebConfig;
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;
@ -20,13 +19,11 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.WebApplicationContext;
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration @WebAppConfiguration
@Transactional @ContextConfiguration(classes = { SecurityWithoutCsrfConfig.class, MvcConfig.class })
@ContextConfiguration(classes = { SecurityWithoutCsrfConfig.class, PersistenceConfig.class, WebConfig.class })
@WithMockUser(username = "admin", roles = { "USER", "ADMIN" }) @WithMockUser(username = "admin", roles = { "USER", "ADMIN" })
public class SessionTimerInterceptorIntegrationTest { public class SessionTimerInterceptorIntegrationTest {
@ -47,9 +44,14 @@ public class SessionTimerInterceptorIntegrationTest {
*/ */
@Test @Test
public void testInterceptors() throws Exception { public void testInterceptors() throws Exception {
HttpSession session = mockMvc.perform(get("/auth/admin")).andExpect(status().is2xxSuccessful()).andReturn().getRequest().getSession(); HttpSession session = mockMvc.perform(get("/auth/foos"))
.andExpect(status().is2xxSuccessful())
.andReturn()
.getRequest()
.getSession();
Thread.sleep(51000); Thread.sleep(51000);
mockMvc.perform(get("/auth/admin").session((MockHttpSession) session)).andExpect(status().is2xxSuccessful()); mockMvc.perform(get("/auth/foos").session((MockHttpSession) session))
.andExpect(status().is2xxSuccessful());
} }
} }

View File

@ -1,8 +1,10 @@
package org.baeldung.web.interceptor; package org.baeldung.web.interceptor;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.baeldung.security.spring.SecurityWithoutCsrfConfig; import org.baeldung.security.spring.SecurityWithoutCsrfConfig;
import org.baeldung.spring.PersistenceConfig; import org.baeldung.spring.MvcConfig;
import org.baeldung.spring.WebConfig;
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;
@ -14,16 +16,11 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.WebApplicationContext;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration @WebAppConfiguration
@Transactional @ContextConfiguration(classes = { SecurityWithoutCsrfConfig.class, MvcConfig.class })
@ContextConfiguration(classes = { SecurityWithoutCsrfConfig.class, PersistenceConfig.class, WebConfig.class })
@WithMockUser(username = "admin", roles = { "USER", "ADMIN" }) @WithMockUser(username = "admin", roles = { "USER", "ADMIN" })
public class UserInterceptorIntegrationTest { public class UserInterceptorIntegrationTest {
@ -46,7 +43,8 @@ public class UserInterceptorIntegrationTest {
*/ */
@Test @Test
public void testInterceptors() throws Exception { public void testInterceptors() throws Exception {
mockMvc.perform(get("/auth/admin")).andExpect(status().is2xxSuccessful()); mockMvc.perform(get("/auth/foos"))
.andExpect(status().is2xxSuccessful());
} }
} }

View File

@ -1,18 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<beansProjectDescription> <beansProjectDescription>
<version>1</version> <version>1</version>
<pluginVersion><![CDATA[3.8.2.201610040608-RELEASE]]></pluginVersion> <pluginVersion><![CDATA[3.6.3.201411271034-RELEASE]]></pluginVersion>
<configSuffixes> <configSuffixes>
<configSuffix><![CDATA[xml]]></configSuffix> <configSuffix><![CDATA[xml]]></configSuffix>
</configSuffixes> </configSuffixes>
<enableImports><![CDATA[false]]></enableImports> <enableImports><![CDATA[false]]></enableImports>
<configs> <configs>
<config>java:org.baeldung.security.spring.SecurityWithoutCsrfConfig</config>
</configs> </configs>
<autoconfigs> <autoconfigs>
<config>src/main/webapp/WEB-INF/api-servlet.xml</config> <config>src/main/webapp/WEB-INF/api-servlet.xml</config>
<config>java:org.baeldung.spring.Application</config> <config>java:org.baeldung.spring.Application</config>
<config>java:org.baeldung.security.spring.SecurityWithCsrfConfig</config>
</autoconfigs> </autoconfigs>
<configSets> <configSets>
</configSets> </configSets>

View File

@ -8,12 +8,10 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring
The "Learn Spring Security" Classes: http://github.learnspringsecurity.com The "Learn Spring Security" Classes: http://github.learnspringsecurity.com
### Relevant Articles: ### Relevant Articles:
- [Spring Security Expressions - hasRole Example](http://www.baeldung.com/spring-security-expressions-basic)
- [REST Pagination in Spring](http://www.baeldung.com/2012/01/18/rest-pagination-in-spring/) - [REST Pagination in Spring](http://www.baeldung.com/2012/01/18/rest-pagination-in-spring/)
- [HATEOAS for a Spring REST Service](http://www.baeldung.com/2011/11/13/rest-service-discoverability-with-spring-part-5/) - [HATEOAS for a Spring REST Service](http://www.baeldung.com/2011/11/13/rest-service-discoverability-with-spring-part-5/)
- [REST API Discoverability and HATEOAS](http://www.baeldung.com/2011/11/06/restful-web-service-discoverability-part-4/) - [REST API Discoverability and HATEOAS](http://www.baeldung.com/2011/11/06/restful-web-service-discoverability-part-4/)
- [ETags for REST with Spring](http://www.baeldung.com/2013/01/11/etags-for-rest-with-spring/) - [ETags for REST with Spring](http://www.baeldung.com/2013/01/11/etags-for-rest-with-spring/)
- [Error Handling for REST with Spring 3](http://www.baeldung.com/2013/01/31/exception-handling-for-rest-with-spring-3-2/)
- [Integration Testing with the Maven Cargo plugin](http://www.baeldung.com/2011/10/16/how-to-set-up-integration-testing-with-the-maven-cargo-plugin/) - [Integration Testing with the Maven Cargo plugin](http://www.baeldung.com/2011/10/16/how-to-set-up-integration-testing-with-the-maven-cargo-plugin/)
- [Introduction to Spring Data JPA](http://www.baeldung.com/2011/12/22/the-persistence-layer-with-spring-data-jpa/) - [Introduction to Spring Data JPA](http://www.baeldung.com/2011/12/22/the-persistence-layer-with-spring-data-jpa/)
- [Project Configuration with Spring](http://www.baeldung.com/2012/03/12/project-configuration-with-spring/) - [Project Configuration with Spring](http://www.baeldung.com/2012/03/12/project-configuration-with-spring/)
@ -24,11 +22,6 @@ The "Learn Spring Security" Classes: http://github.learnspringsecurity.com
- [Metrics for your Spring REST API](http://www.baeldung.com/spring-rest-api-metrics) - [Metrics for your Spring REST API](http://www.baeldung.com/spring-rest-api-metrics)
- [REST Query Language with RSQL](http://www.baeldung.com/rest-api-search-language-rsql-fiql) - [REST Query Language with RSQL](http://www.baeldung.com/rest-api-search-language-rsql-fiql)
- [Spring RestTemplate Tutorial](http://www.baeldung.com/rest-template) - [Spring RestTemplate Tutorial](http://www.baeldung.com/rest-template)
- [A Guide to CSRF Protection in Spring Security](http://www.baeldung.com/spring-security-csrf)
- [Intro to Spring Security Expressions](http://www.baeldung.com/spring-security-expressions)
- [Changing Spring Model Parameters with Handler Interceptor](http://www.baeldung.com/spring-model-parameters-with-handler-interceptor)
- [Introduction to Spring MVC HandlerInterceptor](http://www.baeldung.com/spring-mvc-handlerinterceptor)
- [Using a Custom Spring MVCs Handler Interceptor to Manage Sessions](http://www.baeldung.com/spring-mvc-custom-handler-interceptor)
- [Bootstrap a Web Application with Spring 4](http://www.baeldung.com/bootstraping-a-web-application-with-spring-and-java-based-configuration) - [Bootstrap a Web Application with Spring 4](http://www.baeldung.com/bootstraping-a-web-application-with-spring-and-java-based-configuration)
- [REST Query Language Implementing OR Operation](http://www.baeldung.com/rest-api-query-search-or-operation) - [REST Query Language Implementing OR Operation](http://www.baeldung.com/rest-api-query-search-or-operation)

View File

@ -38,17 +38,6 @@
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<!-- Spring Security -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
</dependency>
<!-- Spring --> <!-- Spring -->
<dependency> <dependency>
@ -220,10 +209,6 @@
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
</dependency>
<!-- <dependency> --> <!-- <dependency> -->
<!-- <groupId>org.hamcrest</groupId> --> <!-- <groupId>org.hamcrest</groupId> -->

View File

@ -10,7 +10,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.PagingAndSortingRepository; import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -36,6 +35,7 @@ public class FooService extends AbstractService<Foo> implements IFooService {
// custom methods // custom methods
@Override
public Foo retrieveByName(final String name) { public Foo retrieveByName(final String name) {
return dao.retrieveByName(name); return dao.retrieveByName(name);
} }
@ -44,7 +44,6 @@ public class FooService extends AbstractService<Foo> implements IFooService {
@Override @Override
@Transactional(readOnly = true) @Transactional(readOnly = true)
@PreAuthorize("hasRole('ROLE_ADMIN')")
public List<Foo> findAll() { public List<Foo> findAll() {
return Lists.newArrayList(getDao().findAll()); return Lists.newArrayList(getDao().findAll());
} }

View File

@ -1,14 +1,10 @@
package org.baeldung.spring; package org.baeldung.spring;
import org.baeldung.web.interceptor.LoggerInterceptor;
import org.baeldung.web.interceptor.SessionTimerInterceptor;
import org.baeldung.web.interceptor.UserInterceptor;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver; import org.springframework.web.servlet.view.InternalResourceViewResolver;
@ -35,15 +31,7 @@ public class WebConfig extends WebMvcConfigurerAdapter {
public void addViewControllers(final ViewControllerRegistry registry) { public void addViewControllers(final ViewControllerRegistry registry) {
super.addViewControllers(registry); super.addViewControllers(registry);
registry.addViewController("/graph.html"); registry.addViewController("/graph.html");
registry.addViewController("/csrfHome.html");
registry.addViewController("/homepage.html"); registry.addViewController("/homepage.html");
} }
@Override
public void addInterceptors(final InterceptorRegistry registry) {
registry.addInterceptor(new LoggerInterceptor());
registry.addInterceptor(new UserInterceptor());
registry.addInterceptor(new SessionTimerInterceptor());
}
} }

View File

@ -11,7 +11,6 @@ import org.baeldung.web.metric.IMetricService;
import org.baeldung.web.util.LinkUtil; import org.baeldung.web.util.LinkUtil;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestMethod;
@ -53,7 +52,6 @@ public class RootController {
return metricService.getFullMetric(); return metricService.getFullMetric();
} }
@PreAuthorize("hasRole('ROLE_ADMIN')")
@RequestMapping(value = "/status-metric", method = RequestMethod.GET) @RequestMapping(value = "/status-metric", method = RequestMethod.GET)
@ResponseBody @ResponseBody
public Map getStatusMetric() { public Map getStatusMetric() {
@ -70,16 +68,5 @@ public class RootController {
return result; return result;
} }
@RequestMapping(value = "/admin/x", method = RequestMethod.GET)
@ResponseBody
public String sampleAdminPage() {
return "Hello";
}
@RequestMapping(value = "/my-error-page", method = RequestMethod.GET)
@ResponseBody
public String sampleErrorPage() {
return "Error Occurred";
}
} }

View File

@ -11,13 +11,11 @@ import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest; import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
//import org.springframework.security.access.AccessDeniedException;
@ControllerAdvice @ControllerAdvice
public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler { public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
@ -55,12 +53,6 @@ public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionH
return handleExceptionInternal(ex, bodyOfResponse, headers, HttpStatus.BAD_REQUEST, request); return handleExceptionInternal(ex, bodyOfResponse, headers, HttpStatus.BAD_REQUEST, request);
} }
// 403
@ExceptionHandler({ AccessDeniedException.class })
public ResponseEntity<Object> handleAccessDeniedException(final Exception ex, final WebRequest request) {
System.out.println("request" + request.getUserPrincipal());
return new ResponseEntity<Object>("Access denied message here", new HttpHeaders(), HttpStatus.FORBIDDEN);
}
// 404 // 404

View File

@ -1,40 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"
xsi:schemaLocation="
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"
>
<http pattern="/securityNone" security="none"/>
<http use-expressions="true" >
<intercept-url pattern="/admin/*" access="hasAnyRole('ROLE_ADMIN')"/>
<intercept-url pattern="/**" access="isAuthenticated()"/>
<http-basic/>
<csrf disabled="true"/>
<!-- <access-denied-handler error-page="/my-error-page" /> -->
<access-denied-handler ref="customAccessDeniedHandler" />
</http>
<authentication-manager>
<authentication-provider>
<user-service>
<user name="user1" password="user1Pass" authorities="ROLE_USER"/>
<user name="admin" password="adminPass" authorities="ROLE_ADMIN"/>
</user-service>
</authentication-provider>
</authentication-manager>
<global-method-security pre-post-annotations="enabled"/>
<!-- <mvc:interceptors>
<bean id="loggerInterceptor" class="org.baeldung.web.interceptor.LoggerInterceptor" />
</mvc:interceptors> -->
</beans:beans>

View File

@ -1,7 +1,6 @@
package org.baeldung; package org.baeldung;
import org.baeldung.persistence.PersistenceTestSuite; import org.baeldung.persistence.PersistenceTestSuite;
import org.baeldung.security.SecurityTestSuite;
import org.baeldung.web.LiveTestSuite; import org.baeldung.web.LiveTestSuite;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.junit.runners.Suite; import org.junit.runners.Suite;
@ -10,7 +9,6 @@ import org.junit.runners.Suite;
@Suite.SuiteClasses({ @Suite.SuiteClasses({
// @formatter:off // @formatter:off
PersistenceTestSuite.class PersistenceTestSuite.class
,SecurityTestSuite.class
,LiveTestSuite.class ,LiveTestSuite.class
}) // }) //
public class TestSuite { public class TestSuite {

View File

@ -1,16 +0,0 @@
package org.baeldung.security;
import org.baeldung.security.csrf.CsrfDisabledIntegrationTest;
import org.baeldung.security.csrf.CsrfEnabledIntegrationTest;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@RunWith(Suite.class)
@Suite.SuiteClasses({
// @formatter:off
CsrfEnabledIntegrationTest.class
,CsrfDisabledIntegrationTest.class
}) //
public class SecurityTestSuite {
}

View File

@ -1,44 +0,0 @@
package org.baeldung.security.csrf;
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.status;
import org.baeldung.security.spring.SecurityWithoutCsrfConfig;
import org.baeldung.spring.PersistenceConfig;
import org.baeldung.spring.WebConfig;
import org.junit.Test;
import org.springframework.http.MediaType;
import org.springframework.test.context.ContextConfiguration;
@ContextConfiguration(classes = { SecurityWithoutCsrfConfig.class, PersistenceConfig.class, WebConfig.class })
public class CsrfDisabledIntegrationTest extends CsrfAbstractIntegrationTest {
@Test
public void givenNotAuth_whenAddFoo_thenUnauthorized() throws Exception {
mvc.perform(post("/auth/foos").contentType(MediaType.APPLICATION_JSON).content(createFoo())).andExpect(status().isUnauthorized());
}
@Test
public void givenAuth_whenAddFoo_thenCreated() throws Exception {
mvc.perform(post("/auth/foos").contentType(MediaType.APPLICATION_JSON).content(createFoo()).with(testUser())).andExpect(status().isCreated());
}
@Test
public void accessMainPageWithoutAuthorization() throws Exception {
mvc.perform(get("/graph.html").contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk());
}
@Test
public void accessOtherPages() throws Exception {
mvc.perform(get("/auth/transfer").contentType(MediaType.APPLICATION_JSON).param("accountNo", "1").param("amount", "100")).andExpect(status().isUnauthorized()); // without authorization
mvc.perform(get("/auth/transfer").contentType(MediaType.APPLICATION_JSON).param("accountNo", "1").param("amount", "100").with(testUser())).andExpect(status().isOk()); // with authorization
}
@Test
public void accessAdminPage() throws Exception {
mvc.perform(get("/auth/admin/x").contentType(MediaType.APPLICATION_JSON)).andExpect(status().isUnauthorized()); // without authorization
mvc.perform(get("/auth/admin/x").contentType(MediaType.APPLICATION_JSON).with(testAdmin())).andExpect(status().isOk()); // with authorization
}
}

View File

@ -14,3 +14,6 @@ The "Learn Spring Security" Classes: http://github.learnspringsecurity.com
- [An Intro to Spring HATEOAS](http://www.baeldung.com/spring-hateoas-tutorial) - [An Intro to Spring HATEOAS](http://www.baeldung.com/spring-hateoas-tutorial)
- [Spring Security Context Propagation with @Async](http://www.baeldung.com/spring-security-async-principal-propagation) - [Spring Security Context Propagation with @Async](http://www.baeldung.com/spring-security-async-principal-propagation)
- [Servlet 3 Async Support with Spring MVC and Spring Security](http://www.baeldung.com/spring-mvc-async-security) - [Servlet 3 Async Support with Spring MVC and Spring Security](http://www.baeldung.com/spring-mvc-async-security)
- [Intro to Spring Security Expressions](http://www.baeldung.com/spring-security-expressions)
- [Spring Security Expressions - hasRole Example](http://www.baeldung.com/spring-security-expressions-basic)
- [Error Handling for REST with Spring 3](http://www.baeldung.com/2013/01/31/exception-handling-for-rest-with-spring-3-2/)

View File

@ -1,10 +1,13 @@
package org.baeldung.spring; package org.baeldung.spring;
import org.baeldung.security.MySavedRequestAwareAuthenticationSuccessHandler; import org.baeldung.security.MySavedRequestAwareAuthenticationSuccessHandler;
import org.baeldung.web.error.CustomAccessDeniedHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; 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.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@ -13,9 +16,13 @@ import org.springframework.security.web.authentication.SimpleUrlAuthenticationFa
@Configuration @Configuration
@EnableWebSecurity @EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@ComponentScan("org.baeldung.security") @ComponentScan("org.baeldung.security")
public class SecurityJavaConfig extends WebSecurityConfigurerAdapter { public class SecurityJavaConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomAccessDeniedHandler accessDeniedHandler;
// @Autowired // @Autowired
// private RestAuthenticationEntryPoint restAuthenticationEntryPoint; // private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
@ -40,7 +47,7 @@ public class SecurityJavaConfig extends WebSecurityConfigurerAdapter {
.csrf().disable() .csrf().disable()
.authorizeRequests() .authorizeRequests()
.and() .and()
.exceptionHandling() .exceptionHandling().accessDeniedHandler(accessDeniedHandler)
// .authenticationEntryPoint(restAuthenticationEntryPoint) // .authenticationEntryPoint(restAuthenticationEntryPoint)
.and() .and()
.authorizeRequests() .authorizeRequests()
@ -48,6 +55,7 @@ public class SecurityJavaConfig extends WebSecurityConfigurerAdapter {
.antMatchers("/api/customer/**").permitAll() .antMatchers("/api/customer/**").permitAll()
.antMatchers("/api/foos/**").authenticated() .antMatchers("/api/foos/**").authenticated()
.antMatchers("/api/async/**").permitAll() .antMatchers("/api/async/**").permitAll()
.antMatchers("/api/admin/**").hasRole("ADMIN")
.and() .and()
.httpBasic() .httpBasic()
// .and() // .and()

View File

@ -1,19 +1,23 @@
package org.baeldung.spring; package org.baeldung.spring;
import static com.google.common.collect.Lists.newArrayList;
import java.util.Collections;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestMethod;
import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.builders.ResponseMessageBuilder; import springfox.documentation.builders.ResponseMessageBuilder;
import springfox.documentation.schema.ModelRef; import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo; import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType; import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2; import springfox.documentation.swagger2.annotations.EnableSwagger2;
import static com.google.common.collect.Lists.newArrayList;
@Configuration @Configuration
@EnableSwagger2 @EnableSwagger2
public class SwaggerConfig { public class SwaggerConfig {
@ -25,7 +29,7 @@ public class SwaggerConfig {
} }
private ApiInfo apiInfo() { private ApiInfo apiInfo() {
ApiInfo apiInfo = new ApiInfo("My REST API", "Some custom description of API.", "API TOS", "Terms of service", "myeaddress@company.com", "License of API", "API license URL"); ApiInfo apiInfo = new ApiInfo("My REST API", "Some custom description of API.", "API TOS", "Terms of service", new Contact("John Doe", "www.example.com", "myeaddress@company.com"), "License of API", "API license URL", Collections.emptyList());
return apiInfo; return apiInfo;
} }
} }

View File

@ -0,0 +1,30 @@
package org.baeldung.web.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class RootController {
public RootController() {
super();
}
// API
@RequestMapping(value = "/admin/x", method = RequestMethod.GET)
@ResponseBody
public String sampleAdminPage() {
return "Hello";
}
@RequestMapping(value = "/my-error-page", method = RequestMethod.GET)
@ResponseBody
public String sampleErrorPage() {
return "Error Occurred";
}
}

View File

@ -0,0 +1,74 @@
package org.baeldung.web.error;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
//import org.springframework.security.access.AccessDeniedException;
@ControllerAdvice
public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
public RestResponseEntityExceptionHandler() {
super();
}
// API
// 400
@ExceptionHandler({ DataIntegrityViolationException.class })
public ResponseEntity<Object> handleBadRequest(final DataIntegrityViolationException ex, final WebRequest request) {
final String bodyOfResponse = "This should be application specific";
return handleExceptionInternal(ex, bodyOfResponse, new HttpHeaders(), HttpStatus.BAD_REQUEST, request);
}
@Override
protected ResponseEntity<Object> handleHttpMessageNotReadable(final HttpMessageNotReadableException ex, final HttpHeaders headers, final HttpStatus status, final WebRequest request) {
final String bodyOfResponse = "This should be application specific";
// ex.getCause() instanceof JsonMappingException, JsonParseException // for additional information later on
return handleExceptionInternal(ex, bodyOfResponse, headers, HttpStatus.BAD_REQUEST, request);
}
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(final MethodArgumentNotValidException ex, final HttpHeaders headers, final HttpStatus status, final WebRequest request) {
final String bodyOfResponse = "This should be application specific";
return handleExceptionInternal(ex, bodyOfResponse, headers, HttpStatus.BAD_REQUEST, request);
}
// 403
@ExceptionHandler({ AccessDeniedException.class })
public ResponseEntity<Object> handleAccessDeniedException(final Exception ex, final WebRequest request) {
System.out.println("request" + request.getUserPrincipal());
return new ResponseEntity<Object>("Access denied message here", new HttpHeaders(), HttpStatus.FORBIDDEN);
}
// 409
@ExceptionHandler({ InvalidDataAccessApiUsageException.class, DataAccessException.class })
protected ResponseEntity<Object> handleConflict(final RuntimeException ex, final WebRequest request) {
final String bodyOfResponse = "This should be application specific";
return handleExceptionInternal(ex, bodyOfResponse, new HttpHeaders(), HttpStatus.CONFLICT, request);
}
// 412
// 500
@ExceptionHandler({ NullPointerException.class, IllegalArgumentException.class, IllegalStateException.class })
/*500*/public ResponseEntity<Object> handleInternal(final RuntimeException ex, final WebRequest request) {
logger.error("500 Status Code", ex);
final String bodyOfResponse = "This should be application specific";
return handleExceptionInternal(ex, bodyOfResponse, new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR, request);
}
}

View File

@ -0,0 +1,21 @@
package org.baeldung.web.exception;
public final class MyResourceNotFoundException extends RuntimeException {
public MyResourceNotFoundException() {
super();
}
public MyResourceNotFoundException(final String message, final Throwable cause) {
super(message, cause);
}
public MyResourceNotFoundException(final String message) {
super(message);
}
public MyResourceNotFoundException(final Throwable cause) {
super(cause);
}
}

View File

@ -10,6 +10,8 @@
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd"> http://www.springframework.org/schema/beans/spring-beans-4.2.xsd">
<http use-expressions="true" entry-point-ref="restAuthenticationEntryPoint"> <http use-expressions="true" entry-point-ref="restAuthenticationEntryPoint">
<intercept-url pattern="/admin/*" access="hasAnyRole('ROLE_ADMIN')"/>
<intercept-url pattern="/api/**" access="isAuthenticated()" /> <intercept-url pattern="/api/**" access="isAuthenticated()" />
<csrf disabled="true" /> <csrf disabled="true" />
@ -17,6 +19,11 @@
<form-login authentication-success-handler-ref="mySuccessHandler" <form-login authentication-success-handler-ref="mySuccessHandler"
authentication-failure-handler-ref="myFailureHandler" /> authentication-failure-handler-ref="myFailureHandler" />
<!-- <access-denied-handler error-page="/my-error-page" /> -->
<access-denied-handler ref="customAccessDeniedHandler" />
<logout /> <logout />
</http> </http>
@ -30,8 +37,12 @@
<user-service> <user-service>
<user name="temporary" password="temporary" authorities="ROLE_ADMIN" /> <user name="temporary" password="temporary" authorities="ROLE_ADMIN" />
<user name="user" password="userPass" authorities="ROLE_USER" /> <user name="user" password="userPass" authorities="ROLE_USER" />
<user name="user1" password="user1Pass" authorities="ROLE_USER"/>
<user name="admin" password="adminPass" authorities="ROLE_ADMIN"/>
</user-service> </user-service>
</authentication-provider> </authentication-provider>
</authentication-manager> </authentication-manager>
<global-method-security pre-post-annotations="enabled"/>
</beans:beans> </beans:beans>

View File

@ -17,17 +17,20 @@ import com.jayway.restassured.specification.RequestSpecification;
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { TestConfig.class }, loader = AnnotationConfigContextLoader.class) @ContextConfiguration(classes = { TestConfig.class }, loader = AnnotationConfigContextLoader.class)
public class FooLiveTest { public class FooLiveTest {
private static final String URL_PREFIX = "http://localhost:8082/spring-security-rest"; private static final String URL_PREFIX = "http://localhost:8080/spring-security-rest";
// private FormAuthConfig formConfig = new FormAuthConfig(URL_PREFIX + "/login", "temporary", "temporary"); // private FormAuthConfig formConfig = new FormAuthConfig(URL_PREFIX + "/login", "temporary", "temporary");
private String cookie; private String cookie;
private RequestSpecification givenAuth() { private RequestSpecification givenAuth() {
// return RestAssured.given().auth().form("user", "userPass", formConfig); // return RestAssured.given().auth().form("user", "userPass", formConfig);
if (cookie == null) { // if (cookie == null) {
cookie = RestAssured.given().contentType("application/x-www-form-urlencoded").formParam("password", "userPass").formParam("username", "user").post(URL_PREFIX + "/login").getCookie("JSESSIONID"); // cookie = RestAssured.given().contentType("application/x-www-form-urlencoded").formParam("password", "userPass").formParam("username", "user").post(URL_PREFIX + "/login").getCookie("JSESSIONID");
} // }
return RestAssured.given().cookie("JSESSIONID", cookie); // return RestAssured.given().cookie("JSESSIONID", cookie);
return RestAssured.given()
.auth()
.basic("user", "userPass");
} }
@Test @Test

View File

@ -8,7 +8,7 @@ import com.jayway.restassured.RestAssured;
import com.jayway.restassured.response.Response; import com.jayway.restassured.response.Response;
public class SwaggerLiveTest { public class SwaggerLiveTest {
private static final String URL_PREFIX = "http://localhost:8082/spring-security-rest/api"; private static final String URL_PREFIX = "http://localhost:8080/spring-security-rest/api";
@Test @Test
public void whenVerifySpringFoxIsWorking_thenOK() { public void whenVerifySpringFoxIsWorking_thenOK() {

View File

@ -1 +1,3 @@
## Relevant articles: ## Relevant articles:
- [Introduction to Vaadin](http://www.baeldung.com/vaadin)