diff --git a/core-java/src/main/java/com/baeldung/hexToAscii/HexToAscii.java b/core-java/src/main/java/com/baeldung/hexToAscii/HexToAscii.java
new file mode 100644
index 0000000000..2a3c4b109e
--- /dev/null
+++ b/core-java/src/main/java/com/baeldung/hexToAscii/HexToAscii.java
@@ -0,0 +1,46 @@
+package com.baeldung.hexToAscii;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+public class HexToAscii {
+
+ @Test
+ public static void whenHexToAscii() {
+ String asciiString = "http://www.baeldung.com/jackson-serialize-dates";
+ String hexEquivalent = "687474703a2f2f7777772e6261656c64756e672e636f6d2f6a61636b736f6e2d73657269616c697a652d6461746573";
+
+ assertEquals(asciiString, hexToAscii(hexEquivalent));
+ }
+
+ @Test
+ public static void whenAsciiToHex() {
+ String asciiString = "http://www.baeldung.com/jackson-serialize-dates";
+ String hexEquivalent = "687474703a2f2f7777772e6261656c64756e672e636f6d2f6a61636b736f6e2d73657269616c697a652d6461746573";
+
+ assertEquals(hexEquivalent, asciiToHex(asciiString));
+ }
+
+ //
+
+ private static String asciiToHex(String asciiStr) {
+ char[] chars = asciiStr.toCharArray();
+ StringBuilder hex = new StringBuilder();
+ for (char ch : chars) {
+ hex.append(Integer.toHexString((int) ch));
+ }
+
+ return hex.toString();
+ }
+
+ private static String hexToAscii(String hexStr) {
+ StringBuilder output = new StringBuilder("");
+ for (int i = 0; i < hexStr.length(); i += 2) {
+ String str = hexStr.substring(i, i + 2);
+ output.append((char) Integer.parseInt(str, 16));
+ }
+ return output.toString();
+ }
+
+}
diff --git a/core-java/src/main/java/com/baeldung/java/nio/selector/EchoClient.java b/core-java/src/main/java/com/baeldung/java/nio/selector/EchoClient.java
index 1c034051aa..61f339db58 100644
--- a/core-java/src/main/java/com/baeldung/java/nio/selector/EchoClient.java
+++ b/core-java/src/main/java/com/baeldung/java/nio/selector/EchoClient.java
@@ -17,6 +17,11 @@ public class EchoClient {
return instance;
}
+ public static void stop() throws IOException {
+ client.close();
+ buffer = null;
+ }
+
private EchoClient() {
try {
client = SocketChannel.open(new InetSocketAddress("localhost", 5454));
@@ -42,5 +47,4 @@ public class EchoClient {
return response;
}
-
}
diff --git a/core-java/src/main/java/com/baeldung/java/nio/selector/EchoServer.java b/core-java/src/main/java/com/baeldung/java/nio/selector/EchoServer.java
index 1d4e01bbc3..2ed9a27c4c 100644
--- a/core-java/src/main/java/com/baeldung/java/nio/selector/EchoServer.java
+++ b/core-java/src/main/java/com/baeldung/java/nio/selector/EchoServer.java
@@ -1,21 +1,19 @@
package com.baeldung.java.nio.selector;
+import java.io.File;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
-import java.nio.channels.Selector;
-import java.nio.channels.SelectionKey;
-import java.nio.ByteBuffer;
-import java.io.IOException;
-import java.util.Set;
import java.util.Iterator;
-import java.net.InetSocketAddress;
-import java.io.File;
+import java.util.Set;
public class EchoServer {
- public static void main(String[] args)
-
- throws IOException {
+ public static void main(String[] args) throws IOException {
Selector selector = Selector.open();
ServerSocketChannel serverSocket = ServerSocketChannel.open();
serverSocket.bind(new InetSocketAddress("localhost", 5454));
@@ -49,7 +47,6 @@ public class EchoServer {
}
}
-
public static Process start() throws IOException, InterruptedException {
String javaHome = System.getProperty("java.home");
String javaBin = javaHome + File.separator + "bin" + File.separator + "java";
diff --git a/core-java/src/test/java/com/baeldung/java/nio/selector/NioEchoIntegrationTest.java b/core-java/src/test/java/com/baeldung/java/nio/selector/NioEchoIntegrationTest.java
index 748dc5b9f4..fc64799578 100644
--- a/core-java/src/test/java/com/baeldung/java/nio/selector/NioEchoIntegrationTest.java
+++ b/core-java/src/test/java/com/baeldung/java/nio/selector/NioEchoIntegrationTest.java
@@ -4,19 +4,32 @@ import static org.junit.Assert.assertEquals;
import java.io.IOException;
+import org.junit.After;
+import org.junit.Before;
import org.junit.Test;
public class NioEchoIntegrationTest {
+ Process server;
+ EchoClient client;
+
+ @Before
+ public void setup() throws IOException, InterruptedException {
+ server = EchoServer.start();
+ client = EchoClient.start();
+ }
+
@Test
- public void givenClient_whenServerEchosMessage_thenCorrect() throws IOException, InterruptedException {
- Process process = EchoServer.start();
- EchoClient client = EchoClient.start();
+ public void givenServerClient_whenServerEchosMessage_thenCorrect() {
String resp1 = client.sendMessage("hello");
String resp2 = client.sendMessage("world");
assertEquals("hello", resp1);
assertEquals("world", resp2);
+ }
- process.destroy();
+ @After
+ public void teardown() throws IOException {
+ server.destroy();
+ EchoClient.stop();
}
}
diff --git a/enterprise-patterns/pom.xml b/enterprise-patterns/pom.xml
new file mode 100644
index 0000000000..036a61c44a
--- /dev/null
+++ b/enterprise-patterns/pom.xml
@@ -0,0 +1,35 @@
+
+
+ 4.0.0
+
+ com.baeldung.enterprise.patterns
+ enterprise-patterns-parent
+ pom
+
+ spring-dispatcher-servlet
+
+
+
+ com.baeldung
+ parent-modules
+ 1.0.0-SNAPSHOT
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.5.1
+
+ 1.8
+ 1.8
+
+
+
+
+
+
diff --git a/patterns/intercepting-filter/src/main/java/com/baeldung/patterns/intercepting/filter/commands/LoginCommand.java b/patterns/intercepting-filter/src/main/java/com/baeldung/patterns/intercepting/filter/commands/LoginCommand.java
index cbc8ad9498..46a0329112 100644
--- a/patterns/intercepting-filter/src/main/java/com/baeldung/patterns/intercepting/filter/commands/LoginCommand.java
+++ b/patterns/intercepting-filter/src/main/java/com/baeldung/patterns/intercepting/filter/commands/LoginCommand.java
@@ -3,6 +3,7 @@ package com.baeldung.patterns.intercepting.filter.commands;
import javax.servlet.ServletException;
import javax.servlet.http.HttpSession;
import java.io.IOException;
+import java.util.Optional;
public class LoginCommand extends FrontCommand {
@Override
@@ -12,10 +13,8 @@ public class LoginCommand extends FrontCommand {
session.setAttribute("username", request.getParameter("username"));
response.sendRedirect(request.getParameter("redirect"));
} else {
- String queryString = request.getQueryString();
- if (queryString == null) {
- queryString = "command=Home";
- }
+ String queryString = Optional.ofNullable(request.getQueryString())
+ .orElse("command=Home");
request.setAttribute("redirect", request.getRequestURL()
.append("?").append(queryString).toString());
forward("login");
diff --git a/patterns/intercepting-filter/src/main/java/com/baeldung/patterns/intercepting/filter/commands/LogoutCommand.java b/patterns/intercepting-filter/src/main/java/com/baeldung/patterns/intercepting/filter/commands/LogoutCommand.java
index 3c9475d6af..f309dc5cf3 100644
--- a/patterns/intercepting-filter/src/main/java/com/baeldung/patterns/intercepting/filter/commands/LogoutCommand.java
+++ b/patterns/intercepting-filter/src/main/java/com/baeldung/patterns/intercepting/filter/commands/LogoutCommand.java
@@ -3,14 +3,17 @@ package com.baeldung.patterns.intercepting.filter.commands;
import javax.servlet.ServletException;
import javax.servlet.http.HttpSession;
import java.io.IOException;
+import java.util.Optional;
public class LogoutCommand extends FrontCommand {
@Override
public void process() throws ServletException, IOException {
super.process();
- HttpSession session = request.getSession(false);
- session.removeAttribute("username");
- session.removeAttribute("order");
+ Optional.ofNullable(request.getSession(false))
+ .ifPresent(session -> {
+ session.removeAttribute("username");
+ session.removeAttribute("order");
+ });
response.sendRedirect("/?command=Home");
}
}
diff --git a/patterns/intercepting-filter/src/main/java/com/baeldung/patterns/intercepting/filter/commands/OrderCommand.java b/patterns/intercepting-filter/src/main/java/com/baeldung/patterns/intercepting/filter/commands/OrderCommand.java
index e53fcf78dd..a57785669b 100644
--- a/patterns/intercepting-filter/src/main/java/com/baeldung/patterns/intercepting/filter/commands/OrderCommand.java
+++ b/patterns/intercepting-filter/src/main/java/com/baeldung/patterns/intercepting/filter/commands/OrderCommand.java
@@ -8,6 +8,7 @@ import com.baeldung.patterns.intercepting.filter.data.OrderImpl;
import javax.servlet.ServletException;
import javax.servlet.http.HttpSession;
import java.io.IOException;
+import java.util.Optional;
public class OrderCommand extends FrontCommand {
@Override
@@ -15,11 +16,10 @@ public class OrderCommand extends FrontCommand {
super.process();
if (request.getMethod().equals("POST")) {
HttpSession session = request.getSession(false);
- Order order = (Order) session.getAttribute("order");
- if (order == null) {
- String username = (String) session.getAttribute("username");
- order = new OrderImpl(username);
- }
+ Order order = Optional
+ .ofNullable(session.getAttribute("order"))
+ .map(Order.class::cast)
+ .orElseGet(() -> new OrderImpl((String) session.getAttribute("username")));
Bookshelf bookshelf = (Bookshelf) request.getServletContext()
.getAttribute("bookshelf");
String isbn = request.getParameter("isbn");
diff --git a/patterns/intercepting-filter/src/main/java/com/baeldung/patterns/intercepting/filter/filters/EncodingFilter.java b/patterns/intercepting-filter/src/main/java/com/baeldung/patterns/intercepting/filter/filters/EncodingFilter.java
index ef3f95382e..0806aecba3 100644
--- a/patterns/intercepting-filter/src/main/java/com/baeldung/patterns/intercepting/filter/filters/EncodingFilter.java
+++ b/patterns/intercepting-filter/src/main/java/com/baeldung/patterns/intercepting/filter/filters/EncodingFilter.java
@@ -4,6 +4,7 @@ import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import java.io.IOException;
+import java.util.Optional;
@WebFilter(
servletNames = {"intercepting-filter"},
@@ -24,10 +25,9 @@ public class EncodingFilter extends BaseFilter {
ServletResponse response,
FilterChain chain
) throws IOException, ServletException {
- String encoding = request.getParameter("encoding");
- if (encoding == null) {
- encoding = this.encoding;
- }
+ String encoding = Optional
+ .ofNullable(request.getParameter("encoding"))
+ .orElse(this.encoding);
response.setCharacterEncoding(encoding);
chain.doFilter(request, response);
}
diff --git a/patterns/intercepting-filter/src/main/java/com/baeldung/patterns/intercepting/filter/filters/LoggingFilter.java b/patterns/intercepting-filter/src/main/java/com/baeldung/patterns/intercepting/filter/filters/LoggingFilter.java
index 0ebb397938..322592f84e 100644
--- a/patterns/intercepting-filter/src/main/java/com/baeldung/patterns/intercepting/filter/filters/LoggingFilter.java
+++ b/patterns/intercepting-filter/src/main/java/com/baeldung/patterns/intercepting/filter/filters/LoggingFilter.java
@@ -10,6 +10,7 @@ import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
+import java.util.Optional;
@WebFilter(servletNames = "intercepting-filter")
public class LoggingFilter extends BaseFilter {
@@ -23,10 +24,10 @@ public class LoggingFilter extends BaseFilter {
) throws IOException, ServletException {
chain.doFilter(request, response);
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
- String username = (String) httpServletRequest.getAttribute("username");
- if (username == null) {
- username = "guest";
- }
+ String username = Optional
+ .ofNullable(httpServletRequest.getAttribute("username"))
+ .map(Object::toString)
+ .orElse("guest");
log.info("Request from '{}@{}': {}?{}", username, request.getRemoteAddr(),
httpServletRequest.getRequestURI(), request.getParameterMap());
}
diff --git a/patterns/intercepting-filter/src/main/java/com/baeldung/patterns/intercepting/filter/filters/VisitorCounterFilter.java b/patterns/intercepting-filter/src/main/java/com/baeldung/patterns/intercepting/filter/filters/VisitorCounterFilter.java
index 5521b9faee..42551310d3 100644
--- a/patterns/intercepting-filter/src/main/java/com/baeldung/patterns/intercepting/filter/filters/VisitorCounterFilter.java
+++ b/patterns/intercepting-filter/src/main/java/com/baeldung/patterns/intercepting/filter/filters/VisitorCounterFilter.java
@@ -5,6 +5,7 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.HashSet;
+import java.util.Optional;
import java.util.Set;
public class VisitorCounterFilter implements Filter {
@@ -21,8 +22,9 @@ public class VisitorCounterFilter implements Filter {
FilterChain chain
) throws IOException, ServletException {
HttpSession session = ((HttpServletRequest) request).getSession(false);
- String username = (String) session.getAttribute("username");
- users.add(username);
+ Optional.ofNullable(session.getAttribute("username"))
+ .map(Object::toString)
+ .ifPresent(users::add);
request.setAttribute("counter", users.size());
chain.doFilter(request, response);
}
diff --git a/pom.xml b/pom.xml
index ef24531698..d8830e2a59 100644
--- a/pom.xml
+++ b/pom.xml
@@ -95,6 +95,7 @@
spring-data-neo4j
spring-data-redis
spring-data-rest
+ spring-dispatcher-servlet
spring-exceptions
spring-freemarker
spring-hibernate3
diff --git a/spring-dispatcher-servlet/pom.xml b/spring-dispatcher-servlet/pom.xml
new file mode 100644
index 0000000000..646db663db
--- /dev/null
+++ b/spring-dispatcher-servlet/pom.xml
@@ -0,0 +1,82 @@
+
+
+ 4.0.0
+
+ spring-dispatcher-servlet
+ war
+
+
+ com.baeldung
+ parent-modules
+ 1.0.0-SNAPSHOT
+ ..
+
+
+
+
+ javax.servlet
+ javax.servlet-api
+ 3.1.0
+ provided
+
+
+ org.springframework
+ spring-webmvc
+ 4.3.3.RELEASE
+
+
+ org.thymeleaf
+ thymeleaf-spring4
+ 3.0.2.RELEASE
+
+
+ org.slf4j
+ slf4j-api
+ 1.7.21
+
+
+ org.apache.logging.log4j
+ log4j-core
+ 2.7
+
+
+ org.apache.logging.log4j
+ log4j-slf4j-impl
+ 2.7
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.5.1
+
+ 1.8
+ 1.8
+
+
+
+ org.apache.maven.plugins
+ maven-war-plugin
+ 3.0.0
+
+ false
+
+
+
+ org.eclipse.jetty
+ jetty-maven-plugin
+ 9.3.12.v20160915
+
+
+ /
+
+
+
+
+
+
diff --git a/spring-dispatcher-servlet/src/main/java/com/baeldung/spring/dispatcher/servlet/RootConfiguration.java b/spring-dispatcher-servlet/src/main/java/com/baeldung/spring/dispatcher/servlet/RootConfiguration.java
new file mode 100644
index 0000000000..48281c5e5d
--- /dev/null
+++ b/spring-dispatcher-servlet/src/main/java/com/baeldung/spring/dispatcher/servlet/RootConfiguration.java
@@ -0,0 +1,19 @@
+package com.baeldung.spring.dispatcher.servlet;
+
+import com.baeldung.spring.dispatcher.servlet.models.Task;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.*;
+
+@Configuration
+public class RootConfiguration {
+ @Bean
+ public Map> taskList() {
+ Map> taskMap = new HashMap<>();
+ List taskList = new ArrayList<>();
+ taskList.add(new Task("Clean the dishes!", new Date()));
+ taskMap.put("Cid", taskList);
+ return taskMap;
+ }
+}
diff --git a/spring-dispatcher-servlet/src/main/java/com/baeldung/spring/dispatcher/servlet/WebApplicationInitializer.java b/spring-dispatcher-servlet/src/main/java/com/baeldung/spring/dispatcher/servlet/WebApplicationInitializer.java
new file mode 100644
index 0000000000..016e4a8b4c
--- /dev/null
+++ b/spring-dispatcher-servlet/src/main/java/com/baeldung/spring/dispatcher/servlet/WebApplicationInitializer.java
@@ -0,0 +1,30 @@
+package com.baeldung.spring.dispatcher.servlet;
+
+import org.springframework.web.context.ContextLoaderListener;
+import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
+import org.springframework.web.servlet.DispatcherServlet;
+
+import javax.servlet.MultipartConfigElement;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRegistration;
+
+public class WebApplicationInitializer implements org.springframework.web.WebApplicationInitializer {
+ @Override
+ public void onStartup(ServletContext servletContext) throws ServletException {
+ AnnotationConfigWebApplicationContext rootContext =
+ new AnnotationConfigWebApplicationContext();
+ rootContext.register(RootConfiguration.class);
+ servletContext.addListener(new ContextLoaderListener(rootContext));
+ AnnotationConfigWebApplicationContext webContext =
+ new AnnotationConfigWebApplicationContext();
+ webContext.register(WebConfiguration.class);
+ DispatcherServlet dispatcherServlet = new DispatcherServlet(webContext);
+ ServletRegistration.Dynamic servlet = servletContext.addServlet("dispatcher",
+ dispatcherServlet);
+ servlet.addMapping("/*");
+ MultipartConfigElement multipartConfigElement =
+ new MultipartConfigElement("/tmp");
+ servlet.setMultipartConfig(multipartConfigElement);
+ }
+}
diff --git a/spring-dispatcher-servlet/src/main/java/com/baeldung/spring/dispatcher/servlet/WebConfiguration.java b/spring-dispatcher-servlet/src/main/java/com/baeldung/spring/dispatcher/servlet/WebConfiguration.java
new file mode 100644
index 0000000000..419c1a2908
--- /dev/null
+++ b/spring-dispatcher-servlet/src/main/java/com/baeldung/spring/dispatcher/servlet/WebConfiguration.java
@@ -0,0 +1,129 @@
+package com.baeldung.spring.dispatcher.servlet;
+
+import org.springframework.context.MessageSource;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.support.ResourceBundleMessageSource;
+import org.springframework.ui.context.support.ResourceBundleThemeSource;
+import org.springframework.web.multipart.MultipartResolver;
+import org.springframework.web.multipart.support.StandardServletMultipartResolver;
+import org.springframework.web.servlet.HandlerExceptionResolver;
+import org.springframework.web.servlet.LocaleResolver;
+import org.springframework.web.servlet.ThemeResolver;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
+import org.springframework.web.servlet.i18n.CookieLocaleResolver;
+import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
+import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;
+import org.springframework.web.servlet.theme.CookieThemeResolver;
+import org.springframework.web.servlet.theme.ThemeChangeInterceptor;
+import org.thymeleaf.spring4.SpringTemplateEngine;
+import org.thymeleaf.spring4.view.ThymeleafViewResolver;
+import org.thymeleaf.templatemode.TemplateMode;
+import org.thymeleaf.templateresolver.ServletContextTemplateResolver;
+
+import javax.servlet.ServletContext;
+import java.util.Locale;
+
+@Configuration
+@ComponentScan("com.baeldung.spring.dispatcher.servlet.web")
+@EnableWebMvc
+public class WebConfiguration extends WebMvcConfigurerAdapter {
+ @Override
+ public void addResourceHandlers(ResourceHandlerRegistry registry) {
+ registry
+ .addResourceHandler("/public/**")
+ .addResourceLocations("/public/");
+ }
+
+ @Override
+ public void addInterceptors(InterceptorRegistry registry) {
+ registry.addInterceptor(localeChangeInterceptor());
+ registry.addInterceptor(themeChangeInterceptor());
+ }
+
+ @Bean
+ public ServletContextTemplateResolver templateResolver(ServletContext servletContext) {
+ ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(servletContext);
+ templateResolver.setPrefix("/WEB-INF/views/");
+ templateResolver.setSuffix(".html");
+ templateResolver.setTemplateMode(TemplateMode.HTML);
+ return templateResolver;
+ }
+
+ @Bean
+ public SpringTemplateEngine templateEngine(ServletContextTemplateResolver templateResolver) {
+ SpringTemplateEngine templateEngine = new SpringTemplateEngine();
+ templateEngine.setTemplateResolver(templateResolver);
+ return templateEngine;
+ }
+
+ @Bean
+ public ThymeleafViewResolver viewResolver(SpringTemplateEngine templateEngine) {
+ ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
+ viewResolver.setTemplateEngine(templateEngine);
+ return viewResolver;
+ }
+
+ @Bean
+ public MessageSource messageSource() {
+ ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
+ messageSource.setBasename("messages");
+ messageSource.setFallbackToSystemLocale(false);
+ return messageSource;
+ }
+
+ @Bean
+ public LocaleResolver localeResolver() {
+ CookieLocaleResolver localeResolver = new CookieLocaleResolver();
+ localeResolver.setDefaultLocale(Locale.ENGLISH);
+ localeResolver.setCookieName("locale");
+ localeResolver.setCookieMaxAge(-1);
+ return localeResolver;
+ }
+
+ @Bean
+ public LocaleChangeInterceptor localeChangeInterceptor() {
+ LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
+ localeChangeInterceptor.setParamName("lang");
+ localeChangeInterceptor.setIgnoreInvalidLocale(true);
+ return localeChangeInterceptor;
+ }
+
+ @Bean
+ public ResourceBundleThemeSource themeSource() {
+ ResourceBundleThemeSource themeSource = new ResourceBundleThemeSource();
+ themeSource.setBasenamePrefix("theme-");
+ themeSource.setFallbackToSystemLocale(false);
+ return themeSource;
+ }
+
+ @Bean
+ public ThemeResolver themeResolver() {
+ CookieThemeResolver themeResolver = new CookieThemeResolver();
+ themeResolver.setDefaultThemeName("robotask");
+ themeResolver.setCookieName("theme");
+ themeResolver.setCookieMaxAge(-1);
+ return themeResolver;
+ }
+
+ @Bean
+ public ThemeChangeInterceptor themeChangeInterceptor() {
+ ThemeChangeInterceptor themeChangeInterceptor = new ThemeChangeInterceptor();
+ themeChangeInterceptor.setParamName("theme");
+ return themeChangeInterceptor;
+ }
+
+ @Bean
+ public MultipartResolver multipartResolver() {
+ return new StandardServletMultipartResolver();
+ }
+
+ @Bean
+ public HandlerExceptionResolver handlerExceptionResolver() {
+ return new ExceptionHandlerExceptionResolver();
+ }
+}
diff --git a/spring-dispatcher-servlet/src/main/java/com/baeldung/spring/dispatcher/servlet/models/Attachment.java b/spring-dispatcher-servlet/src/main/java/com/baeldung/spring/dispatcher/servlet/models/Attachment.java
new file mode 100644
index 0000000000..1d6248650f
--- /dev/null
+++ b/spring-dispatcher-servlet/src/main/java/com/baeldung/spring/dispatcher/servlet/models/Attachment.java
@@ -0,0 +1,58 @@
+package com.baeldung.spring.dispatcher.servlet.models;
+
+import java.util.UUID;
+
+public class Attachment {
+ private String id;
+
+ private String name;
+
+ private String description;
+
+ public Attachment() {
+ this.id = UUID.randomUUID().toString();
+ }
+
+ public Attachment(String name, String description) {
+ this();
+ this.name = name;
+ this.description = description;
+ }
+
+ 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 getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ Attachment that = (Attachment) o;
+ return id.equals(that.id);
+ }
+
+ @Override
+ public int hashCode() {
+ return id.hashCode();
+ }
+}
diff --git a/spring-dispatcher-servlet/src/main/java/com/baeldung/spring/dispatcher/servlet/models/Task.java b/spring-dispatcher-servlet/src/main/java/com/baeldung/spring/dispatcher/servlet/models/Task.java
new file mode 100644
index 0000000000..1e6a533e3a
--- /dev/null
+++ b/spring-dispatcher-servlet/src/main/java/com/baeldung/spring/dispatcher/servlet/models/Task.java
@@ -0,0 +1,52 @@
+package com.baeldung.spring.dispatcher.servlet.models;
+
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+
+public class Task {
+ private String description;
+
+ @DateTimeFormat(pattern = "yyyy-MM-dd'T'hh:mm")
+ private Date due;
+
+ private Set attachments = new HashSet<>();
+
+ public Task() {
+ }
+
+ public Task(Date due) {
+ this.due = due;
+ }
+
+ public Task(String description, Date due) {
+ this.description = description;
+ this.due = due;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public Date getDue() {
+ return due;
+ }
+
+ public void setDue(Date due) {
+ this.due = due;
+ }
+
+ public Set getAttachments() {
+ return attachments;
+ }
+
+ public void setAttachments(Set attachments) {
+ this.attachments = attachments;
+ }
+}
diff --git a/spring-dispatcher-servlet/src/main/java/com/baeldung/spring/dispatcher/servlet/web/AttachmentController.java b/spring-dispatcher-servlet/src/main/java/com/baeldung/spring/dispatcher/servlet/web/AttachmentController.java
new file mode 100644
index 0000000000..2521004ff1
--- /dev/null
+++ b/spring-dispatcher-servlet/src/main/java/com/baeldung/spring/dispatcher/servlet/web/AttachmentController.java
@@ -0,0 +1,17 @@
+package com.baeldung.spring.dispatcher.servlet.web;
+
+import org.springframework.core.io.FileSystemResource;
+import org.springframework.http.ResponseEntity;
+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.RequestParam;
+
+@RequestMapping("/attachments")
+public interface AttachmentController {
+ @GetMapping("/{attachmentId}")
+ ResponseEntity getAttachment(
+ @PathVariable("attachmentId") String attachmentId,
+ @RequestParam(name = "download", required = false, defaultValue = "false") boolean forcedDownload
+ );
+}
diff --git a/spring-dispatcher-servlet/src/main/java/com/baeldung/spring/dispatcher/servlet/web/AttachmentControllerImpl.java b/spring-dispatcher-servlet/src/main/java/com/baeldung/spring/dispatcher/servlet/web/AttachmentControllerImpl.java
new file mode 100644
index 0000000000..75a15cf657
--- /dev/null
+++ b/spring-dispatcher-servlet/src/main/java/com/baeldung/spring/dispatcher/servlet/web/AttachmentControllerImpl.java
@@ -0,0 +1,45 @@
+package com.baeldung.spring.dispatcher.servlet.web;
+
+import com.baeldung.spring.dispatcher.servlet.models.Task;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.io.FileSystemResource;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import java.net.URLConnection;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+@Controller
+public class AttachmentControllerImpl implements AttachmentController {
+ @Autowired
+ private Map> taskMap;
+
+ @Override
+ public ResponseEntity getAttachment(
+ @PathVariable("attachmentId") String attachmentId,
+ @RequestParam(name = "download", required = false, defaultValue = "false") boolean forcedDownload
+ ) {
+ FileSystemResource resource = new FileSystemResource("/tmp/" + attachmentId);
+ HttpHeaders headers = new HttpHeaders();
+ taskMap.values().stream()
+ .flatMap(Collection::stream)
+ .flatMap(t -> t.getAttachments().stream())
+ .filter(a -> a.getId().equals(attachmentId))
+ .findFirst()
+ .ifPresent(a -> {
+ headers.add("Content-Disposition",
+ "attachment; filename=" + a.getName());
+ headers.add("Content-Type", forcedDownload ?
+ MediaType.APPLICATION_OCTET_STREAM_VALUE :
+ URLConnection.guessContentTypeFromName(a.getName()));
+ });
+ return new ResponseEntity<>(resource, headers, HttpStatus.OK);
+ }
+}
diff --git a/spring-dispatcher-servlet/src/main/java/com/baeldung/spring/dispatcher/servlet/web/GlobalDefaultExceptionHandler.java b/spring-dispatcher-servlet/src/main/java/com/baeldung/spring/dispatcher/servlet/web/GlobalDefaultExceptionHandler.java
new file mode 100644
index 0000000000..f25eb601a7
--- /dev/null
+++ b/spring-dispatcher-servlet/src/main/java/com/baeldung/spring/dispatcher/servlet/web/GlobalDefaultExceptionHandler.java
@@ -0,0 +1,19 @@
+package com.baeldung.spring.dispatcher.servlet.web;
+
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.servlet.ModelAndView;
+
+import javax.servlet.http.HttpServletRequest;
+
+@ControllerAdvice
+public class GlobalDefaultExceptionHandler {
+ @ExceptionHandler(Exception.class)
+ public ModelAndView defaultErrorHandler(HttpServletRequest request, Exception e) throws Exception {
+ ModelAndView modelAndView = new ModelAndView();
+ modelAndView.addObject("exception", e);
+ modelAndView.addObject("url", request.getRequestURL());
+ modelAndView.setViewName("error");
+ return modelAndView;
+ }
+}
diff --git a/spring-dispatcher-servlet/src/main/java/com/baeldung/spring/dispatcher/servlet/web/HomeController.java b/spring-dispatcher-servlet/src/main/java/com/baeldung/spring/dispatcher/servlet/web/HomeController.java
new file mode 100644
index 0000000000..5ac39fadb4
--- /dev/null
+++ b/spring-dispatcher-servlet/src/main/java/com/baeldung/spring/dispatcher/servlet/web/HomeController.java
@@ -0,0 +1,13 @@
+package com.baeldung.spring.dispatcher.servlet.web;
+
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+@RequestMapping("/")
+public interface HomeController {
+ @GetMapping("/*")
+ String home(
+ Model model
+ );
+}
diff --git a/spring-dispatcher-servlet/src/main/java/com/baeldung/spring/dispatcher/servlet/web/HomeControllerImpl.java b/spring-dispatcher-servlet/src/main/java/com/baeldung/spring/dispatcher/servlet/web/HomeControllerImpl.java
new file mode 100644
index 0000000000..66d869ca67
--- /dev/null
+++ b/spring-dispatcher-servlet/src/main/java/com/baeldung/spring/dispatcher/servlet/web/HomeControllerImpl.java
@@ -0,0 +1,25 @@
+package com.baeldung.spring.dispatcher.servlet.web;
+
+import com.baeldung.spring.dispatcher.servlet.models.Task;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Controller
+public class HomeControllerImpl implements HomeController {
+ @Autowired
+ private Map> taskMap;
+
+ @Override
+ public String home(Model model) {
+ List users = taskMap.keySet().stream()
+ .sorted()
+ .collect(Collectors.toList());
+ model.addAttribute("users", users);
+ return "home";
+ }
+}
diff --git a/spring-dispatcher-servlet/src/main/java/com/baeldung/spring/dispatcher/servlet/web/TaskController.java b/spring-dispatcher-servlet/src/main/java/com/baeldung/spring/dispatcher/servlet/web/TaskController.java
new file mode 100644
index 0000000000..eff93ffb2f
--- /dev/null
+++ b/spring-dispatcher-servlet/src/main/java/com/baeldung/spring/dispatcher/servlet/web/TaskController.java
@@ -0,0 +1,49 @@
+package com.baeldung.spring.dispatcher.servlet.web;
+
+import com.baeldung.spring.dispatcher.servlet.models.Task;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+@RequestMapping("/tasks")
+public interface TaskController {
+ @GetMapping("/{username}/list")
+ String listTasks(
+ @PathVariable("username") String username,
+ Model model
+ );
+
+ @GetMapping("/{username}/add")
+ String addTask(
+ @PathVariable("username") String username,
+ Model model
+ );
+
+ @PostMapping("/{username}/add")
+ String addTask(
+ @PathVariable("username") String username,
+ @ModelAttribute Task task
+ );
+
+ @GetMapping("/{username}/get/{id}")
+ String getTask(
+ @PathVariable("username") String username,
+ @PathVariable("id") int id,
+ Model model
+ );
+
+ @GetMapping("/{username}/get/{id}/attach")
+ String attachToTask(
+ @PathVariable("username") String username,
+ @PathVariable("id") int id,
+ Model model
+ );
+
+ @PostMapping("/{username}/get/{id}/attach")
+ String attachToTask(
+ @PathVariable("username") String username,
+ @PathVariable("id") int id,
+ @RequestParam("attachment") MultipartFile attachment,
+ @RequestParam("description") String description
+ );
+}
diff --git a/spring-dispatcher-servlet/src/main/java/com/baeldung/spring/dispatcher/servlet/web/TaskControllerImpl.java b/spring-dispatcher-servlet/src/main/java/com/baeldung/spring/dispatcher/servlet/web/TaskControllerImpl.java
new file mode 100644
index 0000000000..464e58aa54
--- /dev/null
+++ b/spring-dispatcher-servlet/src/main/java/com/baeldung/spring/dispatcher/servlet/web/TaskControllerImpl.java
@@ -0,0 +1,111 @@
+package com.baeldung.spring.dispatcher.servlet.web;
+
+import com.baeldung.spring.dispatcher.servlet.models.Attachment;
+import com.baeldung.spring.dispatcher.servlet.models.Task;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.ModelAttribute;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.*;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Controller
+public class TaskControllerImpl implements TaskController {
+ @Autowired
+ private Map> taskMap;
+
+ @Override
+ public String listTasks(
+ @PathVariable("username") String username,
+ Model model
+ ) {
+ List tasks = taskMap.get(username).stream()
+ .sorted(Comparator.comparing(Task::getDue))
+ .collect(Collectors.toList());
+ model.addAttribute("username", username);
+ model.addAttribute("tasks", tasks);
+ return "task-list";
+ }
+
+ @Override
+ public String addTask(
+ @PathVariable("username") String username,
+ Model model
+ ) {
+ model.addAttribute("username", username);
+ model.addAttribute("task", new Task(new Date()));
+ return "task-add";
+ }
+
+ @Override
+ public String addTask(
+ @PathVariable("username") String username,
+ @ModelAttribute Task task
+ ) {
+ List taskList = taskMap.get(username);
+ if (taskList == null) {
+ taskList = new ArrayList<>();
+ }
+ taskList.add(task);
+ taskMap.put(username, taskList);
+ return "redirect:list";
+ }
+
+ @Override
+ public String getTask(
+ @PathVariable("username") String username,
+ @PathVariable("id") int id,
+ Model model
+ ) {
+ Task task = taskMap.get(username).get(id);
+ model.addAttribute("username", username);
+ model.addAttribute("id", id);
+ model.addAttribute("task", task);
+ return "task-get";
+ }
+
+ @Override
+ public String attachToTask(
+ @PathVariable("username") String username,
+ @PathVariable("id") int id,
+ Model model
+ ) {
+ model.addAttribute("username", username);
+ model.addAttribute("id", id);
+ return "task-attach";
+ }
+
+ @Override
+ public String attachToTask(
+ @PathVariable("username") String username,
+ @PathVariable("id") int id,
+ @RequestParam("attachment") MultipartFile multipartFile,
+ @RequestParam("description") String description
+ ) {
+ Task task = taskMap.get(username).get(id);
+ Attachment attachment = new Attachment(multipartFile.getOriginalFilename(),
+ description);
+ task.getAttachments().add(attachment);
+ try (InputStream inputStream =
+ new BufferedInputStream(multipartFile.getInputStream());
+ OutputStream outputStream =
+ new BufferedOutputStream(Files.newOutputStream(
+ Paths.get("/tmp", attachment.getId())))) {
+ byte[] buf = new byte[1024 * 16];
+ int len;
+ while ((len = inputStream.read(buf)) != -1) {
+ outputStream.write(buf, 0, len);
+ }
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to upload file!", e);
+ }
+ return "redirect:./";
+ }
+}
diff --git a/spring-dispatcher-servlet/src/main/resources/log4j2.xml b/spring-dispatcher-servlet/src/main/resources/log4j2.xml
new file mode 100644
index 0000000000..fb18e8279a
--- /dev/null
+++ b/spring-dispatcher-servlet/src/main/resources/log4j2.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spring-dispatcher-servlet/src/main/resources/messages.properties b/spring-dispatcher-servlet/src/main/resources/messages.properties
new file mode 100644
index 0000000000..c36eb5aa42
--- /dev/null
+++ b/spring-dispatcher-servlet/src/main/resources/messages.properties
@@ -0,0 +1,22 @@
+home.title=Welcome to TaskTools!
+task.add.description=description
+task.add.due=due
+task.add.header=Adding a task to {0}''s list:
+task.add.submit=Submit
+task.add.title={0}: task add
+task.attach.attachment=attached file
+task.attach.description=description
+task.attach.header=task #{0}: attach file
+task.attach.submit=Submit
+task.attach.title=#{0}: Attach file
+task.get.attach=Attach file
+task.get.attachments=attachments:
+task.get.download=Download
+task.get.header=task #{0}:
+task.get.list=Back
+task.get.title={0}: task details
+task.list.add-new=Add new
+task.list.details=Details
+task.list.header={0}''s tasks:
+task.list.home=Home
+task.list.title={0}: task list
diff --git a/spring-dispatcher-servlet/src/main/resources/messages_de.properties b/spring-dispatcher-servlet/src/main/resources/messages_de.properties
new file mode 100644
index 0000000000..184b72101c
--- /dev/null
+++ b/spring-dispatcher-servlet/src/main/resources/messages_de.properties
@@ -0,0 +1,22 @@
+home.title=Willkommen bei TaskTools!
+task.add.description=Beschreibung
+task.add.due=f\u00e4llig
+task.add.header=F\u00fcge eine Aufgabe zu {0}''s Liste hinzu:
+task.add.submit=Senden
+task.add.title={0}: Task hinzuf\u00fcgen
+task.attach.attachment=Angeh\u00e4ngte Datei
+task.attach.description=Beschreibung
+task.attach.header=Task #{0}: Datei anh\u00e4ngen
+task.attach.submit=Senden
+task.attach.title=#{0}: Datei anh\u00e4ngen
+task.get.attach=Datei anh\u00e4ngen
+task.get.attachments=Anh\u00e4nge:
+task.get.download=Download
+task.get.header=Task #{0}:
+task.get.list=Zur\u00fcck
+task.get.title={0}: Task Details
+task.list.add-new=Neuer Task
+task.list.details=Details
+task.list.header={0}''s Tasks:
+task.list.home=Startseite
+task.list.title={0}: Task Liste
diff --git a/spring-dispatcher-servlet/src/main/resources/theme-post_it.properties b/spring-dispatcher-servlet/src/main/resources/theme-post_it.properties
new file mode 100644
index 0000000000..d2998e2bdf
--- /dev/null
+++ b/spring-dispatcher-servlet/src/main/resources/theme-post_it.properties
@@ -0,0 +1 @@
+stylesheet=/public/css/themes/post_it.css
diff --git a/spring-dispatcher-servlet/src/main/resources/theme-robotask.properties b/spring-dispatcher-servlet/src/main/resources/theme-robotask.properties
new file mode 100644
index 0000000000..68fe270b64
--- /dev/null
+++ b/spring-dispatcher-servlet/src/main/resources/theme-robotask.properties
@@ -0,0 +1 @@
+stylesheet=/public/css/themes/robotask.css
diff --git a/spring-dispatcher-servlet/src/main/webapp/WEB-INF/views/error.html b/spring-dispatcher-servlet/src/main/webapp/WEB-INF/views/error.html
new file mode 100644
index 0000000000..8f0f6afca7
--- /dev/null
+++ b/spring-dispatcher-servlet/src/main/webapp/WEB-INF/views/error.html
@@ -0,0 +1,13 @@
+
+
+
+ Error
+
+
+
+
+ Error:
+
+
+
+
diff --git a/spring-dispatcher-servlet/src/main/webapp/WEB-INF/views/home.html b/spring-dispatcher-servlet/src/main/webapp/WEB-INF/views/home.html
new file mode 100644
index 0000000000..6adec7bb12
--- /dev/null
+++ b/spring-dispatcher-servlet/src/main/webapp/WEB-INF/views/home.html
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+ TaskTools
+
+
+
diff --git a/spring-dispatcher-servlet/src/main/webapp/WEB-INF/views/task-add.html b/spring-dispatcher-servlet/src/main/webapp/WEB-INF/views/task-add.html
new file mode 100644
index 0000000000..520486f52e
--- /dev/null
+++ b/spring-dispatcher-servlet/src/main/webapp/WEB-INF/views/task-add.html
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spring-dispatcher-servlet/src/main/webapp/WEB-INF/views/task-attach.html b/spring-dispatcher-servlet/src/main/webapp/WEB-INF/views/task-attach.html
new file mode 100644
index 0000000000..23246f330b
--- /dev/null
+++ b/spring-dispatcher-servlet/src/main/webapp/WEB-INF/views/task-attach.html
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spring-dispatcher-servlet/src/main/webapp/WEB-INF/views/task-get.html b/spring-dispatcher-servlet/src/main/webapp/WEB-INF/views/task-get.html
new file mode 100644
index 0000000000..e7b35b6780
--- /dev/null
+++ b/spring-dispatcher-servlet/src/main/webapp/WEB-INF/views/task-get.html
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+ -
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spring-dispatcher-servlet/src/main/webapp/WEB-INF/views/task-list.html b/spring-dispatcher-servlet/src/main/webapp/WEB-INF/views/task-list.html
new file mode 100644
index 0000000000..0671f24ba3
--- /dev/null
+++ b/spring-dispatcher-servlet/src/main/webapp/WEB-INF/views/task-list.html
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spring-dispatcher-servlet/src/main/webapp/public/css/base.css b/spring-dispatcher-servlet/src/main/webapp/public/css/base.css
new file mode 100644
index 0000000000..4d3c2597cf
--- /dev/null
+++ b/spring-dispatcher-servlet/src/main/webapp/public/css/base.css
@@ -0,0 +1,8 @@
+a.button {
+ -webkit-appearance: button;
+ -moz-appearance: button;
+ appearance: button;
+ text-decoration: none;
+ color: #2196f3;
+ background-color: #e0e0e0;
+}
diff --git a/spring-dispatcher-servlet/src/main/webapp/public/css/themes/post_it.css b/spring-dispatcher-servlet/src/main/webapp/public/css/themes/post_it.css
new file mode 100644
index 0000000000..578781ec83
--- /dev/null
+++ b/spring-dispatcher-servlet/src/main/webapp/public/css/themes/post_it.css
@@ -0,0 +1,8 @@
+@import url('https://fonts.googleapis.com/css?family=Indie+Flower');
+
+* {
+ font-family: 'Indie Flower', sans-serif;
+ font-size: 18px;
+ color: #ffeb3b;
+ background-color: #212121;
+}
diff --git a/spring-dispatcher-servlet/src/main/webapp/public/css/themes/robotask.css b/spring-dispatcher-servlet/src/main/webapp/public/css/themes/robotask.css
new file mode 100644
index 0000000000..8c0121b536
--- /dev/null
+++ b/spring-dispatcher-servlet/src/main/webapp/public/css/themes/robotask.css
@@ -0,0 +1,8 @@
+@import url('https://fonts.googleapis.com/css?family=Roboto');
+
+* {
+ font-family: Roboto, sans-serif;
+ font-size: 1em;
+ color: #212121;
+ background-color: #fafafa;
+}
diff --git a/spring-jpa/README.md b/spring-jpa/README.md
index bc768bee22..30b39e1a4e 100644
--- a/spring-jpa/README.md
+++ b/spring-jpa/README.md
@@ -13,5 +13,12 @@
- [Hibernate Second-Level Cache](http://www.baeldung.com/hibernate-second-level-cache)
- [Spring, Hibernate and a JNDI Datasource](http://www.baeldung.com/spring-persistence-jpa-jndi-datasource)
-To ignore "No persistence xml file found in project", you do:
-Project -> Properties -> Java Persistance -> JPA -> Error/Warnings -> Select Ignore on "No persistence xml file found in project"
+### Eclipse Config
+After importing the project into Eclipse, you may see the following error:
+"No persistence xml file found in project"
+
+This can be ignored:
+- Project -> Properties -> Java Persistance -> JPA -> Error/Warnings -> Select Ignore on "No persistence xml file found in project"
+Or:
+- Eclipse -> Preferences - Validation - disable the "Build" execution of the JPA Validator
+
diff --git a/spring-mvc-xml/src/main/java/com/baeldung/spring/controller/ErrorController.java b/spring-mvc-xml/src/main/java/com/baeldung/spring/controller/ErrorController.java
new file mode 100644
index 0000000000..96556bd5b1
--- /dev/null
+++ b/spring-mvc-xml/src/main/java/com/baeldung/spring/controller/ErrorController.java
@@ -0,0 +1,52 @@
+package com.baeldung.spring.controller;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.servlet.ModelAndView;
+
+@Controller
+public class ErrorController {
+
+ @RequestMapping(value = "500Error", method = RequestMethod.GET)
+ public void throwRuntimeException() {
+ throw new NullPointerException("Throwing a null pointer exception");
+ }
+
+ @RequestMapping(value = "errors", method = RequestMethod.GET)
+ public ModelAndView renderErrorPage(HttpServletRequest httpRequest) {
+ ModelAndView errorPage = new ModelAndView("errorPage");
+ String errorMsg = "";
+ int httpErrorCode = getErrorCode(httpRequest);
+
+ switch (httpErrorCode) {
+ case 400: {
+ errorMsg = "Http Error Code : 400 . Bad Request";
+ break;
+ }
+ case 401: {
+ errorMsg = "Http Error Code : 401. Unauthorized";
+ break;
+ }
+ case 404: {
+ errorMsg = "Http Error Code : 404. Resource not found";
+ break;
+ }
+ // Handle other 4xx error codes.
+ case 500: {
+ errorMsg = "Http Error Code : 500. Internal Server Error";
+ break;
+ }
+ // Handle other 5xx error codes.
+ }
+ errorPage.addObject("errorMsg", errorMsg);
+ return errorPage;
+ }
+
+ private int getErrorCode(HttpServletRequest httpRequest) {
+ return (Integer) httpRequest
+ .getAttribute("javax.servlet.error.status_code");
+ }
+}
diff --git a/spring-mvc-xml/src/main/webapp/WEB-INF/view/errorPage.jsp b/spring-mvc-xml/src/main/webapp/WEB-INF/view/errorPage.jsp
new file mode 100644
index 0000000000..ba8a836285
--- /dev/null
+++ b/spring-mvc-xml/src/main/webapp/WEB-INF/view/errorPage.jsp
@@ -0,0 +1,10 @@
+<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
+<%@ page session="false"%>
+
+
+ Home
+
+
+ ${errorMsg}
+
+
diff --git a/spring-mvc-xml/src/main/webapp/WEB-INF/web.xml b/spring-mvc-xml/src/main/webapp/WEB-INF/web.xml
index 29608a17ef..2240ac0a22 100644
--- a/spring-mvc-xml/src/main/webapp/WEB-INF/web.xml
+++ b/spring-mvc-xml/src/main/webapp/WEB-INF/web.xml
@@ -43,4 +43,7 @@
index.jsp
+
+ /errors
+
\ No newline at end of file
diff --git a/spring-rest/pom.xml b/spring-rest/pom.xml
index 69ab4ed361..6580f5ecc7 100644
--- a/spring-rest/pom.xml
+++ b/spring-rest/pom.xml
@@ -332,5 +332,17 @@
3.4.1
-
+
+
+
+ org.codehaus.mojo
+ findbugs-maven-plugin
+ 3.0.4
+
+ Max
+ FindDeadLocalStores,FindNullDeref
+
+
+
+
diff --git a/spring-thymeleaf/README.md b/spring-thymeleaf/README.md
index a8ca755044..98fb4b043b 100644
--- a/spring-thymeleaf/README.md
+++ b/spring-thymeleaf/README.md
@@ -2,15 +2,16 @@
## Spring Thymeleaf Example Project
-
### Relevant Articles:
- [Introduction to Using Thymeleaf in Spring](http://www.baeldung.com/thymeleaf-in-spring-mvc)
- [CSRF Protection with Spring MVC and Thymeleaf](http://www.baeldung.com/csrf-thymeleaf-with-spring-security)
+
### Build the Project
mvn clean install
+
### Run the Project
mvn cargo:run
- **note**: starts on port '8082'
diff --git a/testing/README.md b/testing/README.md
index f49aeeb881..121472ae13 100644
--- a/testing/README.md
+++ b/testing/README.md
@@ -5,4 +5,4 @@
### Relevant Articles:
- [Introduction to Mutation Testing Using the PITest Library](http://www.baeldung.com/java-mutation-testing-with-pitest)
- [Intro to JaCoCo](http://www.baeldung.com/jacoco)
-- [Mutation Testing with PITest](http://www.baeldung.com/java-mutation-testing-with-pitest)
+