~ refactor web

Signed-off-by: Johannes Theiner <j.theiner@live.de>

#SPM-32: add work 2h development
This commit is contained in:
Johannes Theiner 2019-05-29 12:37:28 +02:00
parent 5d898338ee
commit c19bb535f4
36 changed files with 638 additions and 563 deletions

View File

@ -12,7 +12,7 @@ import java.io.IOException;
*
* @author Johannes Theiner
* @version 0.1
* @since 0.1
* @since 1.0
* @param <T> Type the chosen analysis returns as a result
*/
public interface Analysis<T> {

View File

@ -5,7 +5,7 @@ package de.hsel.spm.baudas.analysis;
*
* @author Johannes Theiner
* @version 0.1
* @since 0.1
* @since 1.0
**/
class Attribute {

View File

@ -15,7 +15,7 @@ import java.util.Map;
*
* @author Johannes Theiner
* @version 0.1
* @since 0.4
* @since 1.0
*/
public class Cluster implements Analysis<Map<Integer, Map<String, String>>> {

View File

@ -15,15 +15,14 @@ import java.util.stream.Stream;
*
* @author Karsten Eden
* @version 0.1
* @since 0.2
* @since 1.0
*/
public class TopFlopArticle implements Analysis<Map<String, Integer>> {
public class SalesNumbers implements Analysis<Map<String, Integer>> {
private Instances instances;
private Map<String, Integer> results;
public TopFlopArticle(File file) {
public SalesNumbers(File file) {
instances = load(file);
}

View File

@ -18,7 +18,7 @@ import java.util.Map;
* The shopping-cart analysis.
*
* @author Julian Hinxlage
* @version 0.4
* @version 1.0
*/
public class ShoppingCart implements Analysis<Map<List<String>, List<String>>> {

View File

@ -13,7 +13,7 @@ import java.util.Map;
*
* @author Johannes Theiner
* @version 0.1
* @since 0.1
* @since 1.0
**/
public class ShoppingTimes implements Analysis<Map<Map.Entry<String, String>, Integer>> {

View File

@ -13,7 +13,7 @@ import java.util.Map;
*
* @author Julian Hinxlage
* @version 0.1
* @since 0.1
* @since 1.0
**/
public class WeekOverview implements Analysis<Map<String, Map.Entry<Double, Integer>>> {
@ -45,14 +45,13 @@ public class WeekOverview implements Analysis<Map<String, Map.Entry<Double, Inte
if (!result.containsKey(day)) {
result.put(day, new AbstractMap.SimpleEntry<>(0.0, 0));
} else {
result.put(day,
new AbstractMap.SimpleEntry<>(
result.get(day).getKey() + amount,
result.get(day).getValue() + 1
)
);
}
result.put(day,
new AbstractMap.SimpleEntry<>(
result.get(day).getKey() + amount,
result.get(day).getValue() + 1
)
);
}

View File

@ -1,67 +0,0 @@
package de.hsel.spm.baudas.web;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
/**
* Filter implementation class AuthenticationFilter.
*
* @author Edgar Schkrob
*/
@WebFilter(urlPatterns = {"/*"})
public class AuthenticationFilter implements Filter {
private ServletContext context;
/**
* Called by the web container to indicate to a filter that it is being placed into service. This filter manages the authentication.
*
* @param filterConfig This parameter provides access to everything the code needs to work.
* @throws ServletException Defines a general exception a servlet can throw when it encounters difficulty.
*/
public void init(FilterConfig filterConfig) throws ServletException {
this.context = filterConfig.getServletContext();
this.context.log("AuthenticationFilter initialized");
}
/**
* The doFilter method of the Filter is called by the container each time a request/response pair is passed through the chain due to a client request for a resource at the end of the chain.
*
* @param request This parameter provides access to everything the code needs to work.
* @param response This parameter provides access to everything the code needs to issue a response.
* @param chain This parameter allows passing request along the chain of potential handlers until one of them handles the request.
* @throws ServletException Defines a general exception a servlet can throw when it encounters difficulty.
* @throws IOException Signals that an I/O exception of some sort has occurred. This class is the general class of exceptions produced by failed or interrupted I/O operations.
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
HttpSession session = req.getSession(false);
String url = req.getRequestURI();
if (url.contains("login") || url.contains("logo") || url.contains("js/")) {
chain.doFilter(request, response);
} else if (session == null || !((boolean) session.getAttribute("authentication"))) { //checking whether the session exists and if authentication succeed
this.context.log("Unauthorized access request");
res.sendRedirect(req.getContextPath() + "/login.html");
} else {
chain.doFilter(request, response);
}
}
public void destroy() {
//close any resources here
}
}

View File

@ -0,0 +1,68 @@
package de.hsel.spm.baudas.web;
import org.jetbrains.annotations.NotNull;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
/**
* handles all authorisation filtering.
*
* @author Edgar Schkrob
* @version 0.1
* @since 0.4
*/
@WebFilter(urlPatterns = {"/*"})
public class AuthorizationFilter implements Filter {
private ServletContext context;
/**
* initialize this filter.
*
* @param filterConfig configuration
* @throws ServletException failed to initialize filter
*/
@Override
public void init(@NotNull FilterConfig filterConfig) throws ServletException {
this.context = filterConfig.getServletContext();
this.context.log("AuthorizationFilter initialized");
}
/**
* filter all unauthorized requests.
*
* @param request request object
* @param response response object
* @param chain filter chain
* @throws ServletException something failed inside the filter chain
* @throws IOException failed to redirect
*/
@Override
public void doFilter(@NotNull ServletRequest request, @NotNull ServletResponse response, @NotNull FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
HttpSession session = req.getSession(false);
String url = req.getRequestURI();
if (url.contains("login") || url.contains("logo") || url.contains("js/")) {
chain.doFilter(request, response);
} else if (session == null || !((boolean) session.getAttribute("authentication"))) { //checking whether the session exists and if authentication succeed
this.context.log("Unauthorized access request");
res.sendRedirect(req.getContextPath() + "/login.jsp");
} else {
chain.doFilter(request, response);
}
}
}

View File

@ -22,9 +22,9 @@ import java.util.concurrent.ConcurrentMap;
*
* @author Johannes Theiner
* @version 0.1
* @since 0.1
* @since 1.0
**/
public class Data {
public class DatasetManagement {
@Getter
private static ConcurrentMap<String, List<SavedFile>> files = new ConcurrentHashMap<>();
@ -46,7 +46,7 @@ public class Data {
if (files.get(session).size() >= 5) {
SavedFile file = files.get(session).iterator().next();
if (!get(file.getUuid()).delete()) {
System.err.println("failed to delete file..." + file);
System.err.println("failed to delete file " + file);
}
files.get(session).remove(file);
}
@ -59,10 +59,12 @@ public class Data {
*
* @param session session id
*/
static void delete(String session) {
static void delete(@NotNull String session) {
if (!files.containsKey(session)) return;
for (SavedFile file : files.get(session)) {
if (!get(file.getUuid()).delete())
System.err.println("failed to delete file..." + file);
System.err.println("failed to delete file " + file);
}
files.remove(session);

View File

@ -12,18 +12,26 @@ import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
/**
* list all currently available files.
* list all currently available datasets.
*
* @author Johannes Theiner
* @version 0.1
* @since 0.1
* @since 1.0
**/
@WebServlet("/files")
public class Files extends HttpServlet {
@WebServlet("/datasets")
public class DatasetsServlet extends HttpServlet {
private static final long serialVersionUID = 148451844848L;
/**
* returns all available datasets for session.
*
* @param req request object
* @param resp response object
* @throws IOException failed to initialize print writer
*/
@Override
protected void doGet(@NotNull HttpServletRequest req, @NotNull HttpServletResponse resp)
throws IOException {
@ -31,6 +39,6 @@ public class Files extends HttpServlet {
resp.setCharacterEncoding(StandardCharsets.UTF_8.name());
PrintWriter out = resp.getWriter();
Gson gson = new Gson();
out.print(gson.toJson(Data.getFiles().get(req.getSession().getId())));
out.print(gson.toJson(DatasetManagement.getFiles().get(req.getSession().getId())));
}
}

View File

@ -8,6 +8,7 @@ import lombok.Getter;
*
* @author Julian Hinxlage
* @version 0.1
* @since 1.0
*/
@Getter
@AllArgsConstructor

View File

@ -1,5 +1,7 @@
package de.hsel.spm.baudas.web;
import org.jetbrains.annotations.NotNull;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
@ -11,9 +13,11 @@ import java.io.IOException;
import java.io.PrintWriter;
/**
* Servlet implementation class LoginServlet.
* authenticates users.
*
* @author Edgar Schkrob
* @version 0.1
* @since 1.0
*/
@WebServlet("/login")
@ -22,25 +26,23 @@ public class LoginServlet extends HttpServlet {
private final String password = "SPM2019SS";
/**
* This is a Servlet that manages the Login and creates Sessions.
* reads from HTTP POST parameter 'password' and compares it.
*
* @param request This parameter provides access to everything the code needs to work.
* @param response This parameter provides access to everything the code needs to issue a response.
* @throws ServletException Defines a general exception a servlet can throw when it encounters difficulty.
* @throws IOException Signals that an I/O exception of some sort has occurred. This class is the general class of exceptions produced by failed or interrupted I/O operations.
* @param request request object
* @param response response object
* @throws IOException failed to initialize print writer
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
protected void doPost(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response) throws ServletException, IOException {
String password = request.getParameter("password");
if (this.password.equals(password)) {
HttpSession newSession = request.getSession(true);
newSession.setAttribute("authentication", true);
newSession.setMaxInactiveInterval(5 * 60 * 60); //setting session to expiry in 5 hours
response.sendRedirect("index.jsp");
response.sendRedirect("/");
} else {
RequestDispatcher rd = getServletContext().getRequestDispatcher("/login.html");
RequestDispatcher rd = getServletContext().getRequestDispatcher("/login.jsp");
PrintWriter out = response.getWriter();
out.println("<font color=red>Das eingegebene Passwort ist falsch.</font>");
out.println("<font color='red' class='align-center'>Das eingegebene Passwort ist falsch.</font>");
rd.include(request, response);
}
}

View File

@ -1,5 +1,7 @@
package de.hsel.spm.baudas.web;
import org.jetbrains.annotations.NotNull;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
@ -8,26 +10,27 @@ import javax.servlet.http.HttpSession;
import java.io.IOException;
/**
* Servlet implementation class LogoutServlet.
* logs out user if they request this.
*
* @author Edgar Schkrob
* @version 0.1
* @since 1.0
*/
@WebServlet("/logout")
public class LogoutServlet extends HttpServlet {
/**
* This is a Servlet that manages the Logout and deletes Sessions.
* if this servlet is request logout the user.
*
* @param request This parameter provides access to everything the code needs to work.
* @param response This parameter provides access to everything the code needs to issue a response.
* @throws IOException Signals that an I/O exception of some sort has occurred. This class is the general class of exceptions produced by failed or interrupted I/O operations.
* @param request request object
* @param response response object
* @throws IOException failed to initialize print writer
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
protected void doGet(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response) throws IOException {
HttpSession session = request.getSession();
if (session != null) {
Data.delete(session.getId());
DatasetManagement.delete(session.getId());
session.invalidate();
}
response.sendRedirect(request.getContextPath() + "/");

View File

@ -12,7 +12,7 @@ import java.util.UUID;
*
* @author Johannes Theiner
* @version 0.1
* @since 0.1
* @since 1.0
*/
@Getter
@AllArgsConstructor

View File

@ -1,70 +0,0 @@
package de.hsel.spm.baudas.web;
import com.google.gson.Gson;
import de.hsel.spm.baudas.analysis.ShoppingCart;
import org.jetbrains.annotations.NotNull;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.*;
/**
* Changes data to readable format for table
*
* @author Karsten Eden
* @version 0.1
* @since 0.1
*/
@WebServlet("/shopping_cart")
public class ShoppingCartDiagram extends HttpServlet {
private static final long serialVersionUID = 5026732432605473505L;
private static List<Map.Entry<String, String>> cache;
protected void doGet(@NotNull HttpServletRequest req, @NotNull HttpServletResponse resp) throws IOException {
req.setCharacterEncoding(StandardCharsets.UTF_8.name());
resp.setCharacterEncoding(StandardCharsets.UTF_8.name());
resp.setContentType("application/json");
PrintWriter out = resp.getWriter();
Gson gson = new Gson();
if(cache != null) {
out.println(gson.toJson(cache));
return;
}
List<Map.Entry<String, String>> result = new ArrayList<>();
if (req.getParameter("id") == null) {
out.print(gson.toJson(result));
return;
}
UUID uuid = UUID.fromString(req.getParameter("id"));
File file = Data.get(uuid);
ShoppingCart cart = new ShoppingCart(file);
Map<List<String>, List<String>> map = cart.getResult();
List<String> col1 = new ArrayList<>();
List<String> col2 = new ArrayList<>();
for(Map.Entry<List<String>, List<String>> entry : map.entrySet()){
col1.add(String.join(", ", entry.getKey()));
col2.add(String.join(", ", entry.getValue()));
}
for(int i = 0; i < col1.size(); i++ ){
result.add(new AbstractMap.SimpleEntry<>(col1.get(i), col2.get(i)));
}
out.print(gson.toJson(result));
}
}

View File

@ -28,7 +28,7 @@ import java.nio.file.StandardCopyOption;
@WebServlet("/upload")
@MultipartConfig
public class Upload extends HttpServlet {
public class UploadServlet extends HttpServlet {
private static final long serialVersionUID = 14144111845151L;
@ -48,6 +48,13 @@ public class Upload extends HttpServlet {
}
}
/**
* validates file and saves it.
*
* @param req request object
* @param resp response object
* @throws IOException failed to initialize print writer
*/
@Override
protected void doPost(@NotNull HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding(StandardCharsets.UTF_8.name());
@ -89,7 +96,7 @@ public class Upload extends HttpServlet {
inputStream = filePart.getInputStream();
}
Path path = Data.add(fileName, req.getSession().getId());
Path path = DatasetManagement.add(fileName, req.getSession().getId());
if (!Files.exists(path)) {
Files.createFile(path);
}

View File

@ -1,7 +1,8 @@
package de.hsel.spm.baudas.web;
package de.hsel.spm.baudas.web.depiction;
import com.google.gson.Gson;
import de.hsel.spm.baudas.analysis.Cluster;
import de.hsel.spm.baudas.web.DatasetManagement;
import org.jetbrains.annotations.NotNull;
import javax.servlet.annotation.WebServlet;
@ -11,45 +12,45 @@ import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* changes data from cluster analysis into a readable format
* changes data from cluster analysis into a readable format.
*
* @author Julian Hinxlage
* @version 0.1
* @since 0.1
* @since 1.0
**/
@WebServlet("/clusters")
public class ClusterDiagram extends HttpServlet {
public class ClusterTable extends HttpServlet implements Depiction {
private static Map<Integer, Map<String, String>> cache;
private static Map<UUID, Map> cache;
/**
* returns formatted analysis result to HTTP GET request from supplied id.
*
* @param req request object
* @param resp response object
* @throws IOException failed to initialize print writer
*/
@Override
protected void doGet(@NotNull HttpServletRequest req, @NotNull HttpServletResponse resp) throws IOException {
req.setCharacterEncoding(StandardCharsets.UTF_8.name());
resp.setCharacterEncoding(StandardCharsets.UTF_8.name());
resp.setContentType("application/json");
PrintWriter out = resp.getWriter();
Gson gson = new Gson();
UUID uuid = setup(req, resp, cache);
if (uuid == null) return;
if(cache != null) {
out.println(gson.toJson(cache));
return;
}
Map<Integer, Map<String, String>> result = new HashMap<>();
if (req.getParameter("id") == null) {
out.print(gson.toJson(result));
return;
}
UUID uuid = UUID.fromString(req.getParameter("id"));
File file = Data.get(uuid);
File file = DatasetManagement.get(uuid);
Cluster cluster = new Cluster(file);
result = cluster.getResult();
PrintWriter out = resp.getWriter();
Gson gson = new Gson();
cache.put(uuid, result);
out.print(gson.toJson(result));
}
}

View File

@ -0,0 +1,73 @@
package de.hsel.spm.baudas.web.depiction;
import com.google.gson.Gson;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Pattern;
/**
* handle all common methods for depictions.
*
* @author Johannes Theiner
* @version 0.1
* @since 1.0
**/
interface Depiction {
/**
* set all default values and handle caching.
*
* @param request request object
* @param response response object
* @param cache cached results
* @return validated uuid
*/
@Nullable
default UUID setup(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Map<UUID, Map> cache) {
try {
request.setCharacterEncoding(StandardCharsets.UTF_8.name());
response.setCharacterEncoding(StandardCharsets.UTF_8.name());
response.setContentType("application/json");
PrintWriter out = response.getWriter();
Gson gson = new Gson();
UUID uuid = validateAndConvert(request.getParameter("id"));
if (uuid == null) return null;
if (cache.containsKey(uuid)) {
out.println(gson.toJson(cache.get(uuid)));
return null;
}
return uuid;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* validates and converts uuid.
*
* @param id potential uuid
* @return UUID object
*/
@Nullable
default UUID validateAndConvert(String id) {
boolean match = Pattern.matches("[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}", id);
if (id == null || !match) {
return null;
}
return UUID.fromString(id);
}
}

View File

@ -1,7 +1,8 @@
package de.hsel.spm.baudas.web;
package de.hsel.spm.baudas.web.depiction;
import com.google.gson.Gson;
import de.hsel.spm.baudas.analysis.TopFlopArticle;
import de.hsel.spm.baudas.analysis.SalesNumbers;
import de.hsel.spm.baudas.web.DatasetManagement;
import org.jetbrains.annotations.NotNull;
import javax.servlet.annotation.WebServlet;
@ -11,13 +12,11 @@ import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Pattern;
/**
* top/flop articles list diagram.
@ -27,38 +26,28 @@ import java.util.regex.Pattern;
* @since 0.1
**/
@WebServlet("/top_flop")
public class TopFlopArticleDiagram extends HttpServlet {
@WebServlet("/sales")
public class SalesNumberChart extends HttpServlet implements Depiction {
private static Map<UUID, Map> cache = new HashMap<>();
private static final long serialVersionUID = 6567531464214L;
/**
* returns formatted analysis result to HTTP GET request from supplied id.
*
* @param req request object
* @param resp response object
* @throws IOException failed to initialize print writer
*/
@Override
protected void doGet(@NotNull HttpServletRequest req, @NotNull HttpServletResponse resp) throws IOException {
req.setCharacterEncoding(StandardCharsets.UTF_8.name());
resp.setCharacterEncoding(StandardCharsets.UTF_8.name());
resp.setContentType("application/json");
PrintWriter out = resp.getWriter();
UUID uuid = setup(req, resp, cache);
if (uuid == null) return;
Gson gson = new Gson();
File file = DatasetManagement.get(uuid);
String id = req.getParameter("id");
boolean match = Pattern.matches("[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}", id);
if (id == null || !match) {
return;
}
UUID uuid = UUID.fromString(id);
if (cache.containsKey(uuid)) {
out.println(gson.toJson(cache.get(uuid)));
return;
}
File file = Data.get(uuid);
TopFlopArticle articles = new TopFlopArticle(file);
SalesNumbers articles = new SalesNumbers(file);
Map<String, Integer> map = articles.getResult();
Map<String, List<String>> result = new HashMap<>();
@ -74,6 +63,8 @@ public class TopFlopArticleDiagram extends HttpServlet {
result.put("labels", labels);
result.put("data", data);
PrintWriter out = resp.getWriter();
Gson gson = new Gson();
cache.put(uuid, result);
out.print(gson.toJson(result));

View File

@ -0,0 +1,80 @@
package de.hsel.spm.baudas.web.depiction;
import com.google.gson.Gson;
import de.hsel.spm.baudas.analysis.ShoppingCart;
import de.hsel.spm.baudas.web.DatasetManagement;
import org.jetbrains.annotations.NotNull;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
/**
* Changes data to readable format for table.
*
* @author Karsten Eden
* @version 0.1
* @since 0.1
*/
@WebServlet("/shopping_cart")
public class ShoppingCartTable extends HttpServlet implements Depiction {
private static final long serialVersionUID = 5026732432605473505L;
private static Map<UUID, Map> cache;
/**
* returns formatted analysis result to HTTP GET request from supplied id.
*
* @param req request object
* @param resp response object
* @throws IOException failed to initialize print writer
*/
protected void doGet(@NotNull HttpServletRequest req, @NotNull HttpServletResponse resp) throws IOException {
UUID uuid = setup(req, resp, cache);
if (uuid == null) return;
List<Map.Entry<String, String>> tmp = new ArrayList<>();
File file = DatasetManagement.get(uuid);
ShoppingCart cart = new ShoppingCart(file);
Map<List<String>, List<String>> map = cart.getResult();
List<String> premises = new ArrayList<>();
List<String> consequences = new ArrayList<>();
for (Map.Entry<List<String>, List<String>> entry : map.entrySet()) {
premises.add(String.join(", ", entry.getKey()));
consequences.add(String.join(", ", entry.getValue()));
}
for (int i = 0; i < premises.size(); i++) {
tmp.add(new AbstractMap.SimpleEntry<>(premises.get(i), consequences.get(i)));
}
Map<Integer, Map.Entry<String, String>> result = new HashMap<>();
int i = 0;
for (Map.Entry<String, String> entry : tmp) {
result.put(i, entry);
i++;
}
cache.put(uuid, result);
PrintWriter out = resp.getWriter();
Gson gson = new Gson();
out.print(gson.toJson(result));
}
}

View File

@ -1,7 +1,8 @@
package de.hsel.spm.baudas.web;
package de.hsel.spm.baudas.web.depiction;
import com.google.gson.Gson;
import de.hsel.spm.baudas.analysis.ShoppingTimes;
import de.hsel.spm.baudas.web.DatasetManagement;
import org.jetbrains.annotations.NotNull;
import javax.servlet.annotation.WebServlet;
@ -11,54 +12,51 @@ import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.regex.Pattern;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.UUID;
/**
* changes data from shopping times diagram into a readable format for chart.js
*
* @author Johannes Theiner
* @version 0.1
* @since 0.1
* @since 1.0
**/
@WebServlet("/shopping_times")
public class ShoppingTimesDiagram extends HttpServlet {
public class ShoppingTimesChart extends HttpServlet implements Depiction {
private static Map<UUID, Map> cache = new HashMap<>();
private static final long serialVersionUID = 6567531484L;
/**
* returns formatted analysis result to HTTP GET request from supplied id.
*
* @param req request object
* @param resp response object
* @throws IOException failed to initialize print writer
*/
@Override
protected void doGet(@NotNull HttpServletRequest req, @NotNull HttpServletResponse resp) throws IOException {
req.setCharacterEncoding(StandardCharsets.UTF_8.name());
resp.setCharacterEncoding(StandardCharsets.UTF_8.name());
resp.setContentType("application/json");
PrintWriter out = resp.getWriter();
UUID uuid = setup(req, resp, cache);
if (uuid == null) return;
List<String> definedOrder = Arrays.asList("<10 Uhr", "10-12 Uhr", "12-14 Uhr", "14-17 Uhr", ">17 Uhr");
Comparator<String> comparator = Comparator.comparingInt(definedOrder::indexOf);
Map<String, Collection<String>> result = new HashMap<>();
Gson gson = new Gson();
String id = req.getParameter("id");
boolean match = Pattern.matches("[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}", id);
if (id == null || !match) {
return;
}
UUID uuid = UUID.fromString(id);
if (cache.containsKey(uuid)) {
out.print(gson.toJson(cache.get(uuid)));
return;
}
File file = Data.get(uuid);
File file = DatasetManagement.get(uuid);
ShoppingTimes shoppingTimes = new ShoppingTimes(file);
Map<Map.Entry<String, String>, Integer> map = shoppingTimes.getResult();
@ -73,14 +71,17 @@ public class ShoppingTimesDiagram extends HttpServlet {
for (String day : days) {
if (!result.containsKey(day))
if (!result.containsKey(day)) {
result.put(day, new ArrayList<>());
}
for (String hour : hours) {
if (map.containsKey(new AbstractMap.SimpleEntry<>(day, hour))) {
result.get(day).add(map.get(new AbstractMap.SimpleEntry<>(day, hour)).toString());
} else result.get(day).add("0");
}
}
PrintWriter out = resp.getWriter();
Gson gson = new Gson();
cache.put(uuid, result);
out.print(gson.toJson(result));

View File

@ -1,7 +1,8 @@
package de.hsel.spm.baudas.web;
package de.hsel.spm.baudas.web.depiction;
import com.google.gson.Gson;
import de.hsel.spm.baudas.analysis.WeekOverview;
import de.hsel.spm.baudas.web.DatasetManagement;
import org.jetbrains.annotations.NotNull;
import javax.servlet.annotation.WebServlet;
@ -11,7 +12,6 @@ import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
@ -19,50 +19,39 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Pattern;
/**
* changes data from week overview into readable format for chart.js
*
* @author Johannes Theiner
* @version 0.1
* @since 0.1
* @since 1.0
**/
@WebServlet("/week_overview")
public class WeekOverviewDiagram extends HttpServlet {
public class WeekOverviewChart extends HttpServlet implements Depiction {
private static Map<UUID, Map> cache = new HashMap<>();
private static final long serialVersionUID = 8484151844118L;
/**
* returns formatted analysis result to HTTP GET request from supplied id.
*
* @param req request object
* @param resp response object
* @throws IOException failed to initialize print writer
*/
@Override
protected void doGet(@NotNull HttpServletRequest req, @NotNull HttpServletResponse resp) throws IOException {
req.setCharacterEncoding(StandardCharsets.UTF_8.name());
resp.setCharacterEncoding(StandardCharsets.UTF_8.name());
resp.setContentType("application/json");
PrintWriter out = resp.getWriter();
UUID uuid = setup(req, resp, cache);
if (uuid == null) return;
List<String> definedOrder = Arrays.asList("Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag");
Map<String, List<String>> result = new HashMap<>();
Gson gson = new Gson();
String id = req.getParameter("id");
boolean match = Pattern.matches("[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}", id);
if (id == null || !match) {
return;
}
UUID uuid = UUID.fromString(id);
if(cache.containsKey(uuid)) {
out.println(gson.toJson(cache.get(uuid)));
return;
}
File file = Data.get(uuid);
File file = DatasetManagement.get(uuid);
WeekOverview overview = new WeekOverview(file);
@ -86,6 +75,9 @@ public class WeekOverviewDiagram extends HttpServlet {
result.put("count", count);
result.put("revenue", revenue);
PrintWriter out = resp.getWriter();
Gson gson = new Gson();
cache.put(uuid, result);
out.print(gson.toJson(result));
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

View File

@ -0,0 +1,87 @@
<!--Cards-->
<!--Analyse-Cards-->
<div id="analysis" class="row container black-text">
<!--Übersicht-->
<div class="col s12 m12">
<div id="overview" class="card white">
<div class="center">
<span class="card-title center">Wochenübersicht</span>
</div>
<div class="card-content">
<div>
<canvas class="black-text" id="overview_chart" width="1000" height="400"></canvas>
</div>
</div>
</div>
</div>
<!--Einkaufszeiten-->
<div class="col s12 m12">
<div id="shopping_times" class="card white">
<div class="card-content">
<div class="center">
<span class="card-title">Einkaufszeiten</span>
</div>
<div class="center">
<div class="input-field col s12">
<select id="day" onchange="changeDay()">
<option value="0">Montag</option>
<option value="1">Dienstag</option>
<option value="2">Mittwoch</option>
<option value="3">Donnerstag</option>
<option value="4">Freitag</option>
<option value="5">Samstag</option>
</select>
<label for="day">Wochentag</label>
</div>
</div>
<div>
<canvas id="shopping_times_chart" width="1000" height="400"></canvas>
</div>
</div>
</div>
</div>
<!--Verkaufszahlen-->
<div class="col s12 m12">
<div id="top_articles" class="card white">
<div class="center">
<span class="card-title center">Verkaufszahlen</span>
</div>
<div class="card-content">
<div>
<canvas id="sales_chart" width="1000" height="400"></canvas>
</div>
</div>
</div>
</div>
<!--Gruppenübersicht-->
<div class="col s12 m12">
<div id="group_overview" class="card white">
<div class="card-content">
<div class="center">
<span class="card-title center">Gruppenübersicht</span>
</div>
<div>
<table id="cluster_table">
</table>
</div>
</div>
</div>
</div>
<!--Warenkorbanlyse-->
<div id="shopping_card_analysis" class="col s12 m12">
<div class="card white">
<div class="center">
<span class="card-title center">Warenkorbanalyse</span>
</div>
<div class="card-content">
<table id="shopping_cart_table">
</table>
</div>
</div>
</div>
</div>

View File

@ -1,19 +1,11 @@
<!--Anfang Skriptbereich-->
<!--Script für Diagramme-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.bundle.min.js"
integrity="sha256-xKeoJ50pzbUGkpQxDYHD7o7hxe0LaOGeguUidbq6vis=" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
<%@include file="theming.jsp"%>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/google-palette@1.1.0/palette.min.js"></script>
<script>
M.AutoInit();
</script>
<script src="js/upload.js"></script>
<script src="js/cache.js"></script>
<script src="js/week_overview.js"></script>
<script src="js/shopping_times.js"></script>
<script src="js/top_flop.js"></script>
<script src="js/clusters.js"></script>
<script src="js/shopping_cart.js"></script>
<!--Ende Skriptbereich-->
</body>

View File

@ -1,3 +1,4 @@
<%@ page import="java.nio.charset.StandardCharsets" %>
<% response.setCharacterEncoding(StandardCharsets.UTF_8.name()); %>
<% request.setCharacterEncoding(StandardCharsets.UTF_8.name()); %>
<!DOCTYPE html>

View File

@ -1,198 +1,10 @@
<%@ page import="java.nio.charset.StandardCharsets" %>
<%@ page contentType="text/html;charset=UTF-8" %>
<%@include file="menu.jsp" %>
<% response.setCharacterEncoding(StandardCharsets.UTF_8.name()); %>
<% request.setCharacterEncoding(StandardCharsets.UTF_8.name()); %>
<%@ page contentType="text/html;charset=UTF-8" %>
<%@include file="menu.jsp" %>
<!--Cards-->
<!--Analyse-Cards-->
<div id="analysis" class="row container black-text">
<!--Übersicht-->
<div class="col s12 m12">
<div id="overview" class="card white">
<div class="center">
<span class="card-title center">Wochenübersicht</span>
</div>
<%@include file="analysis.jsp"%>
<%@include file="marketing.jsp"%>
<div class="card-content">
<div>
<canvas class="black-text" id="overview_chart" width="1000" height="400"></canvas>
</div>
</div>
</div>
</div>
<!--Einkaufszeiten-->
<div class="col s12 m12">
<div id="shopping_times" class="card white">
<div class="card-content">
<div class="center">
<span class="card-title">Einkaufszeiten</span>
</div>
<div class="center">
<div class="input-field col s12">
<select id="day" onchange="changeDay()">
<option value="0">Montag</option>
<option value="1">Dienstag</option>
<option value="2">Mittwoch</option>
<option value="3">Donnerstag</option>
<option value="4">Freitag</option>
<option value="5">Samstag</option>
</select>
<label for="day">Wochentag</label>
</div>
</div>
<div>
<canvas id="shopping_times_chart" width="1000" height="400"></canvas>
</div>
</div>
</div>
</div>
<!--Verkaufszahlen-->
<div class="col s12 m12">
<div id="top_articles" class="card white">
<div class="center">
<span class="card-title center">Verkaufszahlen</span>
</div>
<div class="card-content">
<div>
<canvas id="top_flop_chart" width="1000" height="400"></canvas>
</div>
</div>
</div>
</div>
<!--Gruppenübersicht-->
<div class="col s12 m12">
<div id="group_overview" class="card white">
<div class="card-content">
<div class="center">
<span class="card-title center">Gruppenübersicht</span>
</div>
<div>
<table id="cluster_table">
</table>
</div>
</div>
</div>
</div>
<!--Warenkorbanlyse-->
<div id="shopping_card_analysis" class="col s12 m12">
<div class="card white">
<div class="center">
<span class="card-title center">Warenkorbanalyse</span>
</div>
<div class="card-content">
<table id="shopping_cart_table">
</table>
</div>
</div>
</div>
</div>
<!--Marketing-Cards-->
<div id="marketing" class="row container">
<div class="row">
<div class="col s12 m6">
<div id="marketing_tip_3" class="card white">
<div class="card-content">
<div class="center">
<span class="card-title center">Werbung</span>
</div>
<div>
<p>
Werbung dient dazu, auf bestimmte Produkte, Angebote oder den Markt im
Allgemeinen aufmerksam zu machen. Sie kann über verschiedene Wege verbreitet
werden, etwa das Internet, Zeitungsannoncen oder auch per TV/Radio.
Im Gegensatz zu Rabatten (die zeitabhängig am besten funktionieren) ist Werbung
stark von der Zielgruppe abhängig. Insbesondere in der Kombination mit anderen
Marketingmaßnahmen kann sie so ihre volle Wirkung entfalten.
<br>
<br>
Analysen, die für Werbung nützlich sein könnten:
Clusteranalyse, Wochenübersicht, Verkaufszahlen
</p>
</div>
</div>
</div>
</div>
<div class="col s12 m6">
<div id="marketing_tip_4" class="card white">
<div class="card-content">
<div class="center">
<span class="card-title center">Sortimentsveränderung</span>
</div>
<div>
<p>
Gibt es eine Produktgruppe, die sich besonders gut verkauft, so sollte unter
Umständen über die Erweiterung des Sortiments innerhalb dieser Gruppe
nachgedacht werden.
Im Umkehrschluss dazu bietet sich an, schlecht verkaufte Produkte, welche keinen
hohen Gewinn abwerfen aus dem täglichen Verkaufsgeschäft wieder zu entfernen.
Dies verringert die Bildung von „Ladenhütern“ und schafft Platz für neue, sich
besser verkaufende Produkte.
<br>
<br>
Analysen, die bei der Sortimentswahl nützlich sein könnten:
Verkaufszahlen, Clusterübersicht
</p>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col s12 m6">
<div id="marketing_tip_1" class="card white">
<div class="card-content">
<div class="center">
<span class="card-title center">Rabatt</span>
</div>
<div>
<p>
Rabatte können z.B. an Tagen angeboten werden, an denen nur wenige Kunden
erscheinen. Dadurch wird einerseits an dieses Tagen oder Uhrzeiten das
Kaufverhalten angeregt, als auch der Andrang an anderen reduziert. Dies dient
insbesondere der Entzerrung des zeitabhängigen Kaufverhaltens.
Des Weiteren können durch Rabatte weniger gut laufende Produkte in den
Vordergrund gerückt du vergünstigt angeboten werden.
Zusätzlich dazu können sich gut verkaufende Produkte mit einem (vermeintlich)
verringerten Preis versehen werden. Dies kann beim Kunden den „inneren
Schnäppchenjäger“ wecken und dafür sorgen, dass er sich dieses gute Angebot
nicht entgehen lassen kann.
<br>
<br>
Analysen, die zur Platzierung von Rabatten nützlich sein können:
Wochenübersicht, Einkaufszeiten, Verkaufszahlen
</p>
</div>
</div>
</div>
</div>
<div class="col s12 m6">
<div id="marketing_tip_2" class="card white">
<div class="card-content">
<div class="center">
<span class="card-title center">Produktplatzierung </span>
</div>
<div>
<p>
Es gibt bestimmte Produkte, die werden häufig zusammen erworben. Sind diese
Produkte quer durch den Laden verstreut, so müssen die Kunden zusätzlich zu
ihren Wunschprodukten auch an anderen Auslagen vorbei und die Anzahl an
Spontankäufen eben jener weiteren Produkte steigt.
<br>
<br>
Analysen, die bei der Produktplatzierung hilfreich sein könnten:
Warenkorbsanalyse, Verkaufszahlen
</p>
</div>
</div>
</div>
</div>
</div>
</div>
<%@include file="footer.jsp" %>
<%@include file="theming.jsp" %>

View File

@ -32,7 +32,7 @@ function clearSelected(){
function updateDatasets() {
let dataset = $('#dataset');
request('files').then(results => {
request('datasets').then(results => {
dataset.empty();
for (const result of results) {
dataset.append($("<option></option>")
@ -56,7 +56,7 @@ function updateCache() {
} else {
//requesting files, getting values from html does not work...
//if no selection is provided, select newest file
request('files').then(results => {
request('datasets').then(results => {
let uuid = results[results.length - 1].uuid;
dataset.val(uuid);
updateAll(uuid);
@ -69,7 +69,7 @@ function updateAll(uuid) {
updateWeekOverviewChart(uuid);
updateShoppingTimesChart(uuid);
updateTopFlopChart(uuid);
updateClusters(uuid)
updateClusters(uuid);
updateShoppingCartTable(uuid);
//add new charts here.
}

View File

@ -1,7 +1,7 @@
let top_flop_result;
let top_flop = new Chart($("#top_flop_chart"), {
let sales = new Chart($("#sales_chart"), {
type: 'horizontalBar',
data: {
labels: [],
@ -34,23 +34,23 @@ let top_flop = new Chart($("#top_flop_chart"), {
function updateTopFlopChart(id) {
if (typeof id !== 'undefined') {
request('top_flop', id).then(function (data) {
request('sales', id).then(function (data) {
top_flop_result = data;
updateTopFlop();
});
} else request('top_flop').then(function (data) {
} else request('sales').then(function (data) {
top_flop_result = data;
updateTopFlop();
});
}
function updateTopFlop() {
top_flop.data.labels = top_flop_result.labels;
top_flop.data.datasets[0].data = top_flop_result.data;
sales.data.labels = top_flop_result.labels;
sales.data.datasets[0].data = top_flop_result.data;
let seq = palette('mpn65', 15);
for (let i = 0; i < 15; i++) {
top_flop.data.datasets[0].backgroundColor[i] = "#" + seq[i];
sales.data.datasets[0].backgroundColor[i] = "#" + seq[i];
}
top_flop.update();
sales.update();
}

View File

@ -1,47 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Login</title>
<!--Import Google Icon Font-->
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<!--Import materialize.css-->
<link type="text/css" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css" media="screen,projection" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.min.css" integrity="sha256-aa0xaJgmK/X74WM224KMQeNQC2xYKwlAt08oZqjeF0E=" crossorigin="anonymous" />
<!--Let browser know website is optimized for mobile-->
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body class="blue-grey lighten-5">
<div class="container row">
<!--Login-->
<div class="center">
<div class="card white col s6 push-s3">
<div class="card-content">
<div class="center">
<img style="width: 50%" src="logoOrginal.gif">
</div>
<div class="divider"></div>
<div class="row">
<div class="col s8 push-s2">
<form action="login" method="post">
<input id="password" type="password" class="validate" placeholder="Passwort" name="password">
<input class="white-text btn blue-grey lighten-2" type="submit" value="Login">
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<!--<a class="waves-effect waves-light btn blue-grey lighten-2"><i class="material-icons left">lock_open</i>Login</a>-->
<!--Anfang Skriptbereich-->
<!--Script für Materlialize-->
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<script type="text/javascript" src="js/materialize_components.js"></script>
<!--Ende Skriptbereich-->
</body>
</html>

26
src/main/webapp/login.jsp Normal file
View File

@ -0,0 +1,26 @@
<%@include file="emptyHeader.jsp"%>
<div class="container row">
<!--Login-->
<div class="center">
<div class="card white col s6 push-s3">
<div class="card-content">
<div class="center">
<img style="width: 50%" src="logoOrginal.gif">
</div>
<div class="divider"></div>
<div class="row">
<div class="col s8 push-s2">
<form action="login" method="post">
<input id="password" type="password" class="validate" placeholder="Passwort" name="password">
<input class="white-text btn blue-grey lighten-2" type="submit" value="Login">
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<%@include file="footer.jsp"%>

View File

@ -0,0 +1,102 @@
<!--Marketing-Cards-->
<div id="marketing" class="row container">
<div class="row">
<div class="col s12 m6">
<div id="marketing_tip_3" class="card white">
<div class="card-content">
<div class="center">
<span class="card-title center">Werbung</span>
</div>
<div>
<p>
Werbung dient dazu, auf bestimmte Produkte, Angebote oder den Markt im
Allgemeinen aufmerksam zu machen. Sie kann über verschiedene Wege verbreitet
werden, etwa das Internet, Zeitungsannoncen oder auch per TV/Radio.
Im Gegensatz zu Rabatten (die zeitabhängig am besten funktionieren) ist Werbung
stark von der Zielgruppe abhängig. Insbesondere in der Kombination mit anderen
Marketingmaßnahmen kann sie so ihre volle Wirkung entfalten.
<br>
<br>
Analysen, die für Werbung nützlich sein könnten:
Clusteranalyse, Wochenübersicht, Verkaufszahlen
</p>
</div>
</div>
</div>
</div>
<div class="col s12 m6">
<div id="marketing_tip_4" class="card white">
<div class="card-content">
<div class="center">
<span class="card-title center">Sortimentsveränderung</span>
</div>
<div>
<p>
Gibt es eine Produktgruppe, die sich besonders gut verkauft, so sollte unter
Umständen über die Erweiterung des Sortiments innerhalb dieser Gruppe
nachgedacht werden.
Im Umkehrschluss dazu bietet sich an, schlecht verkaufte Produkte, welche keinen
hohen Gewinn abwerfen aus dem täglichen Verkaufsgeschäft wieder zu entfernen.
Dies verringert die Bildung von „Ladenhütern“ und schafft Platz für neue, sich
besser verkaufende Produkte.
<br>
<br>
Analysen, die bei der Sortimentswahl nützlich sein könnten:
Verkaufszahlen, Clusterübersicht
</p>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col s12 m6">
<div id="marketing_tip_1" class="card white">
<div class="card-content">
<div class="center">
<span class="card-title center">Rabatt</span>
</div>
<div>
<p>
Rabatte können z.B. an Tagen angeboten werden, an denen nur wenige Kunden
erscheinen. Dadurch wird einerseits an dieses Tagen oder Uhrzeiten das
Kaufverhalten angeregt, als auch der Andrang an anderen reduziert. Dies dient
insbesondere der Entzerrung des zeitabhängigen Kaufverhaltens.
Des Weiteren können durch Rabatte weniger gut laufende Produkte in den
Vordergrund gerückt du vergünstigt angeboten werden.
Zusätzlich dazu können sich gut verkaufende Produkte mit einem (vermeintlich)
verringerten Preis versehen werden. Dies kann beim Kunden den „inneren
Schnäppchenjäger“ wecken und dafür sorgen, dass er sich dieses gute Angebot
nicht entgehen lassen kann.
<br>
<br>
Analysen, die zur Platzierung von Rabatten nützlich sein können:
Wochenübersicht, Einkaufszeiten, Verkaufszahlen
</p>
</div>
</div>
</div>
</div>
<div class="col s12 m6">
<div id="marketing_tip_2" class="card white">
<div class="card-content">
<div class="center">
<span class="card-title center">Produktplatzierung </span>
</div>
<div>
<p>
Es gibt bestimmte Produkte, die werden häufig zusammen erworben. Sind diese
Produkte quer durch den Laden verstreut, so müssen die Kunden zusätzlich zu
ihren Wunschprodukten auch an anderen Auslagen vorbei und die Anzahl an
Spontankäufen eben jener weiteren Produkte steigt.
<br>
<br>
Analysen, die bei der Produktplatzierung hilfreich sein könnten:
Warenkorbsanalyse, Verkaufszahlen
</p>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@ -1,5 +1,17 @@
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/google-palette@1.1.0/palette.min.js"></script>
<script>
M.AutoInit();
</script>
<!--Script für Diagramme-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.bundle.min.js"
integrity="sha256-xKeoJ50pzbUGkpQxDYHD7o7hxe0LaOGeguUidbq6vis=" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
<script src="js/upload.js"></script>
<script src="js/cache.js"></script>
<script src="js/week_overview.js"></script>
<script src="js/shopping_times.js"></script>
<script src="js/sales.js"></script>
<script src="js/clusters.js"></script>
<script src="js/shopping_cart.js"></script>
<%@include file="footer.jsp"%>

View File

@ -14,7 +14,7 @@ public class TopFlopArticlesTest {
void test100() {
URL url = getClass().getClassLoader().getResource("kd100.csv");
assert url != null;
TopFlopArticle tfArticle = new TopFlopArticle(new File(url.getFile()));
SalesNumbers tfArticle = new SalesNumbers(new File(url.getFile()));
Map<String, Integer> results = tfArticle.getResult();
assertEquals(529, results.get("Farben"));
@ -29,7 +29,7 @@ public class TopFlopArticlesTest {
void test1000() {
URL url = getClass().getClassLoader().getResource("kd1000.csv");
assert url != null;
TopFlopArticle tfArticle = new TopFlopArticle(new File(url.getFile()));
SalesNumbers tfArticle = new SalesNumbers(new File(url.getFile()));
Map<String, Integer> results = tfArticle.getResult();
assertEquals(5643, results.get("Eisenwaren"));
@ -44,7 +44,7 @@ public class TopFlopArticlesTest {
void test10000() {
URL url = getClass().getClassLoader().getResource("kd10000.csv");
assert url != null;
TopFlopArticle tfArticle = new TopFlopArticle(new File(url.getFile()));
SalesNumbers tfArticle = new SalesNumbers(new File(url.getFile()));
Map<String, Integer> results = tfArticle.getResult();
assertEquals(101665, results.get("Handwerkzeuge"));

View File

@ -13,7 +13,7 @@ import static org.junit.jupiter.api.Assertions.assertTimeout;
/**
* Week WeekOverviewDiagram Analysis Test.
* Week Overview Analysis Test.
*
* @author Johannes Theiner
* @version 0.1