6 Commits
hw2 ... master

Author SHA1 Message Date
079be0ba5c hw6 2018-10-28 19:54:52 +02:00
b668c9f427 hw5 2018-10-21 14:40:14 +03:00
b0a4a27928 hw4 2018-10-14 20:37:46 +03:00
fa0dc0bd2c Move things around 2018-10-13 19:15:07 +03:00
9c38800214 hw3 2018-10-07 19:23:56 +03:00
e8260b1700 start hw3 2018-10-07 16:23:51 +03:00
21 changed files with 610 additions and 44 deletions

View File

@@ -1,6 +1,7 @@
plugins { plugins {
id 'war' id 'war'
id 'org.gretty' version '2.2.0' id 'org.gretty' version '2.2.0'
id 'io.franzbecker.gradle-lombok' version '1.14'
} }
repositories { repositories {
@@ -11,9 +12,25 @@ repositories {
sourceCompatibility = 10 sourceCompatibility = 10
dependencies { dependencies {
// https://mvnrepository.com/artifact/org.hsqldb/hsqldb
compile group: 'org.hsqldb', name: 'hsqldb', version: '2.4.1'
// https://mvnrepository.com/artifact/org.apache.commons/commons-dbcp2
compile group: 'org.apache.commons', name: 'commons-dbcp2', version: '2.5.0'
// https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.9.7'
compile 'com.fasterxml.jackson.core:jackson-databind:2.9.6'
compileOnly 'javax.servlet:javax.servlet-api:4.0.1' compileOnly 'javax.servlet:javax.servlet-api:4.0.1'
} }
gretty { gretty {
contextPath = '/' contextPath = '/'
} }
lombok {
version = '1.18.2'
sha256 = ""
}

View File

@@ -0,0 +1,78 @@
package DAO;
import DTO.Order;
import DTO.OrderItem;
import util.DataSourceProvider;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.List;
public class OrderItemDao {
public static List<OrderItem> getItemsForOrderId(int id) {
List<OrderItem> result = new LinkedList<>();
String sql = "select item_name, quantity, price from order_items where ORDER_ID=?";
try (Connection con = DataSourceProvider.getDataSource().getConnection();
PreparedStatement ps = con.prepareStatement(sql)) {
ps.setInt(1, id);
try(ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
OrderItem item = new OrderItem();
item.setItemName(rs.getString(1));
item.setQuantity(rs.getInt(2));
item.setPrice(rs.getInt(3));
result.add(item);
}
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
return result;
}
public static void saveOrderItem(OrderItem item, int orderId) {
String sql = "insert into order_items (order_id, item_name, quantity, price) VALUES (?,?,?,?);";
try (Connection con = DataSourceProvider.getDataSource().getConnection();
PreparedStatement ps = con.prepareStatement(sql)) {
ps.setInt(1, orderId);
ps.setString(2, item.getItemName());
ps.setInt(3, item.getQuantity());
ps.setInt(4, item.getPrice());
ps.execute();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public static void saveOrderItems(List<OrderItem> items, int orderId) {
for (OrderItem item: items){
saveOrderItem(item, orderId);
}
}
public static void deleteOrderItemsForOrderId(int id) {
String sql = "delete from order_items where ORDER_ID=?";
try (Connection con = DataSourceProvider.getDataSource().getConnection();
PreparedStatement ps = con.prepareStatement(sql)) {
ps.setInt(1, id);
ps.executeUpdate();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public static void deleteAllOrderItems() {
String sql = "delete from order_items";
try (Connection con = DataSourceProvider.getDataSource().getConnection();
PreparedStatement ps = con.prepareStatement(sql)) {
ps.executeUpdate();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -0,0 +1,114 @@
package DAO;
import DTO.Order;
import Exceptions.ValidationException;
import util.DataSourceProvider;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class OrdersDao {
public static Order getOrderForId(int id) {
Order order = new Order();
String sql = "select order_number from ORDERS where id=?;";
try (Connection connection = DataSourceProvider.getDataSource().getConnection();
PreparedStatement ps = connection.prepareStatement(sql)) {
ps.setInt(1, id);
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
order.setId(id);
order.setOrderNumber(rs.getString(1));
order.setOrderRows(OrderItemDao.getItemsForOrderId(id));
return order;
}
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
return null;
}
public static List<Order> getAllOrders() {
List<Order> orders = new ArrayList<Order>();
String sql = "select id, order_number from orders;";
try (Connection connection = DataSourceProvider.getDataSource().getConnection();
Statement statement = connection.createStatement() ){
try (ResultSet rs = statement.executeQuery(sql)) {
while(rs.next()) {
Order order = new Order();
order.setId(rs.getInt(1));
order.setOrderNumber(rs.getString(2));
order.setOrderRows(OrderItemDao.getItemsForOrderId(order.getId()));
orders.add(order);
}
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
return orders;
}
public static void saveOrder(Order order) {
String sql = "insert into orders (order_number) values (?);";
try (Connection connection = DataSourceProvider.getDataSource().getConnection();
PreparedStatement ps = connection.prepareStatement(sql);
PreparedStatement call = connection.prepareCall("CALL IDENTITY();")) {
ps.setString(1, order.getOrderNumber());
ps.executeUpdate();
try (ResultSet rs = call.executeQuery()) {
if (rs.next()) {
order.setId(rs.getInt(1));
OrderItemDao.saveOrderItems(order.getOrderRows(), order.getId());
}
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public static void deleteOrderForId(int id) {
String sql = "DELETE FROM orders WHERE id=?;";
try (Connection connection = DataSourceProvider.getDataSource().getConnection();
PreparedStatement ps = connection.prepareStatement(sql)) {
ps.setInt(1, id);
ps.executeUpdate();
OrderItemDao.deleteOrderItemsForOrderId(id);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public static int getCount() {
String sql = "select count(*) from orders;";
try (Connection connection = DataSourceProvider.getDataSource().getConnection();
Statement ps = connection.createStatement()) {
try (ResultSet rs = ps.executeQuery(sql)) {
if (rs.next()) {
return rs.getInt(1);
}
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
return 0;
}
public static void deleteAllOrders() {
String sql = "delete from orders;";
try (Connection connection = DataSourceProvider.getDataSource().getConnection();
PreparedStatement ps = connection.prepareStatement(sql)) {
OrderItemDao.deleteAllOrderItems();
ps.executeUpdate();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -0,0 +1,25 @@
package DAO;
import DTO.Order;
import DTO.OrderItem;
import DTO.Report;
public class ReportDao {
public static Report getReport() {
Report report = new Report();
report.setCount(OrdersDao.getCount());
report.setTurnoverWithoutVAT(0);
int itemCount = 0;
for (Order order: OrdersDao.getAllOrders()) {
for (OrderItem orderItem: order.getOrderRows()) {
int turnover = report.getTurnoverWithoutVAT() + (orderItem.getPrice() * orderItem.getQuantity());
report.setTurnoverWithoutVAT(turnover);
itemCount++;
}
}
report.setAverageOrderAmount(report.getTurnoverWithoutVAT() / itemCount);
report.setTurnoverVAT((int)(report.getTurnoverWithoutVAT() * 0.2));
report.setTurnoverWithVAT(report.getTurnoverVAT() + report.getTurnoverWithoutVAT());
return report;
}
}

View File

@@ -0,0 +1,12 @@
package DTO;
import Exceptions.ValidationException;
import lombok.Data;
import java.util.LinkedList;
import java.util.List;
public @Data class Order {
private int id;
private String orderNumber;
private List<OrderItem> orderRows = new LinkedList<>();
}

View File

@@ -0,0 +1,9 @@
package DTO;
import lombok.Data;
public @Data class OrderItem {
private String itemName;
private Integer quantity;
private Integer price;
}

View File

@@ -0,0 +1,14 @@
package DTO;
import lombok.Data;
@Data
public class Report {
private Integer count;
private Integer averageOrderAmount;
private Integer turnoverWithoutVAT;
private Integer turnoverVAT;
private Integer turnoverWithVAT;
}

View File

@@ -0,0 +1,10 @@
package DTO;
import lombok.Data;
import java.util.List;
@Data
public class ValidationError {
private String code;
private List<String> arguments;
}

View File

@@ -0,0 +1,16 @@
package DTO;
import lombok.Data;
import java.util.LinkedList;
import java.util.List;
@Data
public class ValidationErrors {
private List<ValidationError> errors = new LinkedList<>();
public void addError(ValidationError error) {
errors.add(error);
}
}

View File

@@ -0,0 +1,13 @@
package Exceptions;
import DTO.ValidationError;
import lombok.Getter;
import lombok.Setter;
public class ValidationException extends Exception {
@Getter private ValidationError error = new ValidationError();
public ValidationException(String code) {
error.setCode(code);
}
}

View File

@@ -0,0 +1,39 @@
import util.DataSourceProvider;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import static util.FileUtil.readFileFromClasspath;
@WebListener
public class Startup implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("Set jdbc provider url");
DataSourceProvider.setDbUrl("jdbc:hsqldb:mem:shop.");
System.out.println("Load sql");
String sql = readFileFromClasspath("sql/schema.sql");
try (Connection connection = DataSourceProvider.getDataSource().getConnection();
Statement statement = connection.createStatement()) {
statement.execute(sql);
} catch (SQLException e) {
throw new RuntimeException(e);
}
System.out.println("Ready");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
}
}

View File

@@ -1,42 +0,0 @@
package api;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@WebServlet("/api/orders")
public class Orders extends HttpServlet {
private static final long serialVersionUID = 1L;
private int lastOrderId = 0;
private Pattern orderPattern = Pattern.compile(".*\"orderNumber\":\\s*\"(.*)\".*");
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().format("%d", lastOrderId);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("application/json");
String order = req.getReader().lines().collect(Collectors.joining(" "));
int orderId = lastOrderId++;
Matcher matcher = orderPattern.matcher(order);
boolean matches = matcher.matches();
if (matches && matcher.groupCount() > 0) {
String orderNumber = matcher.group(1);
System.out.format("request data: %s, orderNumber: %s\n", order, orderNumber);
resp.getWriter().printf("{\"id\": %d, \"orderNumber\": \"%s\"}", orderId, orderNumber);
} else {
resp.getWriter().print("\"Invalid request\"");
}
}
}

View File

@@ -0,0 +1,74 @@
package servlet.api;
import DAO.OrdersDao;
import DTO.Order;
import DTO.ValidationError;
import DTO.ValidationErrors;
import com.fasterxml.jackson.databind.ObjectMapper;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;
@WebServlet(urlPatterns = "/api/orders", name="Orders")
public class Orders extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("application/json");
String idString = req.getParameter("id");
if (idString != null) {
int id = Integer.parseInt(idString);
Order order = OrdersDao.getOrderForId(id);
if (order == null) {
resp.setStatus(404);
return;
}
resp.getWriter().print(new ObjectMapper().writeValueAsString(order));
return;
}
List<Order> orders = OrdersDao.getAllOrders();
resp.getWriter().print(new ObjectMapper().writeValueAsString(orders));
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("application/json");
String orderJson = req.getReader().lines().collect(Collectors.joining(" "));
Order order = new ObjectMapper().readValue(orderJson, Order.class);
if (order.getOrderNumber().length() < 2) {
resp.setStatus(400, "orderNumber parameter is empty");
resp.setContentType("application/json");
ValidationErrors errors = new ValidationErrors();
ValidationError error = new ValidationError();
error.setCode("too_short_number");
errors.addError(error);
resp.getWriter().print(new ObjectMapper().writeValueAsString(errors));
return;
}
OrdersDao.saveOrder(order);
resp.getWriter().print(new ObjectMapper().writeValueAsString(order));
}
@Override
protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("application/json");
String idString = req.getParameter("id");
if (idString != null) {
int id = Integer.parseInt(idString);
OrdersDao.deleteOrderForId(id);
} else {
OrdersDao.deleteAllOrders();
}
}
}

View File

@@ -0,0 +1,22 @@
package servlet.api;
import DAO.ReportDao;
import com.fasterxml.jackson.databind.ObjectMapper;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(urlPatterns = "/api/orders/report", name="OrdersReport")
public class OrdersReport extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("application/json");
resp.getWriter().print(new ObjectMapper().writeValueAsString(ReportDao.getReport()));
}
}

View File

@@ -0,0 +1,20 @@
package servlet.html;
import util.FileUtil;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(urlPatterns = "/", name="Index")
public class Index extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html; charset=utf-8");
String index = FileUtil.readFileFromClasspath("html/index.html");
response.getWriter().print(index);
}
}

View File

@@ -0,0 +1,59 @@
package servlet.html;
import DAO.OrdersDao;
import DTO.Order;
import DTO.ValidationError;
import DTO.ValidationErrors;
import Exceptions.ValidationException;
import com.fasterxml.jackson.databind.ObjectMapper;
import servlet.api.Orders;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(urlPatterns = "/orders/form", name="OrdersForm")
public class OrdersForm extends HttpServlet
{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html; charset=utf-8");
resp.getWriter().print(
"<form method=post>" +
"<label for=orderNumber>Order Number</label> " +
"<input type=text name=orderNumber></input> " +
"<input type=submit></input>" +
"</form>"
);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("application/json");
String orderNumber = req.getParameter("orderNumber");
if (orderNumber == null) {
resp.setStatus(400, "orderNumber parameter is empty");
resp.getWriter().print("orderNumber parameter is empty");
return;
}
Order order = new Order();
order.setOrderNumber(orderNumber);
if (order.getOrderNumber().length() < 2) {
resp.setStatus(400, "orderNumber parameter is empty");
resp.setContentType("application/json");
ValidationErrors errors = new ValidationErrors();
ValidationError error = new ValidationError();
error.setCode("too_short_number");
errors.addError(error);
resp.getWriter().print(new ObjectMapper().writeValueAsString(errors));
return;
}
OrdersDao.saveOrder(order);
resp.getWriter().format("%d", order.getId());
}
}

View File

@@ -1,4 +1,4 @@
package test; package servlet.test;
import java.io.IOException; import java.io.IOException;
import javax.servlet.ServletException; import javax.servlet.ServletException;
@@ -7,7 +7,7 @@ import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
@WebServlet("/hello") @WebServlet(urlPatterns = "/hello", name="Hello")
public class HelloServlet extends HttpServlet { public class HelloServlet extends HttpServlet {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;

View File

@@ -0,0 +1,35 @@
package util;
import org.apache.commons.dbcp2.BasicDataSource;
import javax.sql.DataSource;
public class DataSourceProvider {
private static String dbUrl = null;
private static BasicDataSource dataSource = null;
public static void setDbUrl(String url) {
dbUrl = url;
}
public static DataSource getDataSource() {
if (dataSource != null) {
return dataSource;
}
if (dbUrl == null) {
throw new IllegalStateException(
"Database url not configured. Use setDbUrl()");
}
dataSource = new BasicDataSource();
dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
dataSource.setUrl(dbUrl);
dataSource.setMaxTotal(3);
return dataSource;
}
}

View File

@@ -0,0 +1,26 @@
package util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.stream.Collectors;
public class FileUtil {
public static String readFileFromClasspath(String pathOnClasspath) {
try (InputStream is = FileUtil.class.getClassLoader().getResourceAsStream(pathOnClasspath)) {
if (is == null) {
throw new IllegalStateException("can't load file: " + pathOnClasspath);
}
BufferedReader buffer = new BufferedReader(new InputStreamReader(is));
return buffer.lines().collect(Collectors.joining("\n"));
} catch (IOException e) {
throw new RuntimeException();
}
}
}

View File

@@ -0,0 +1,9 @@
<!doctype html>
<html>
<title>Index</title>
<h1>Shop</h1>
<h3>Menu</h3>
<ul>
<li><a href=/orders/form>Orders form</a></li>
</ul>
</html>

View File

@@ -0,0 +1,16 @@
CREATE TABLE orders (
id BIGINT NOT NULL PRIMARY KEY IDENTITY,
order_number VARCHAR (255)
);
CREATE TABLE order_items (
id BIGINT NOT NULL PRIMARY KEY IDENTITY,
order_id BIGINT NOT NULL,
item_name VARCHAR (255),
quantity INT,
price INT,
FOREIGN KEY (order_id) REFERENCES orders (id)
);
--INSERT INTO orders (order_number) values ('asdf');
--INSERT INTO order_items (order_id, item_name, quantity, price) values (0, 'test', 1, 10);