Commit 7e99ade3 authored by Michal-MK's avatar Michal-MK
Browse files

Initial Commit containing the base for web-2 seminar

parents
.idea
.settings
.project
test-output
.classpath
*.iml
*~
target
## Seminar Web 2 Tasks - Spring MVC
**Task 01 (project build)**
In a new folder, checkout the branch step1 from https://gitlab.fi.muni.cz/pa165/seminar-07-web-ii
and build the whole project. Then run the eshop-spring-mvc subproject.
The application needs some time to start, wait for the messages "Tomcat 9.x started on port [8080],
Press Ctrl-C to stop the container...".
```
mkdir seminar-web2
cd seminar-web2
git clone -b step1 https://gitlab.fi.muni.cz/pa165/seminar-07-web-ii
cd seminar-07-web-ii/
mvn clean install
cd eshop-spring-mvc
mvn cargo:run
```
**Task 02 (responsive web design)**
Visit the web application at [http://localhost:8080/eshop/](http://localhost:8080/eshop/).
Today web applications need to display correctly on a wide variety of devices,
from 3" smartphones to 75" desktop monitors, with which users interact by a mouse or a touchscreen.
This provides a challenge for web design. A solution is the so called *responsive web design*
which adapts to various screen sizes. This example project uses the CSS framework [Bootstrap 3](http://getbootstrap.com/) for it.
Bootstrap divides device screens into 4 categories:
- extra small (less than 768px wide)
- small (768px-992px)
- medium (992px-1200px)
- large (>1200px)
It also provides 12-column grid for positioning dependent on screen size.
On the eshop home page, click on the button *Go shopping*.
Change the width of your browser screen to see all four sizes.
Notice what the top navigation menu does for extra small screen.
Also notice how the product images rearrange to 1, 3, 4 and 6 columns respectively on the four screen sizes.
You can stop the Tomcat by pressing CTRL+C, then rebuild and restart the application by issuing the command
```
mvn clean install cargo:run
```
See the examples in the [Grid](https://getbootstrap.com/docs/3.3/css/#grid) section of Bootstrap 3 documentation.
Edit the page *home.jsp* to display twelve buttons labelled *Button1*, ..., *Button12*,
which rearrange themselves to 1 column on extra small screen, 2 columns on small screen, 6 columns on medium screen
and to 12 columns on large screen.
(**Hint**: you can use the JSTL tag `<c:forEach begin="1" end="12" var="i">` or a scriptlet to generate the buttons in a loop.)
**Task 03 (example SpringMVC controller)**
On the eshop home page, click on the button *Call ExampleController*.
Look at the source code of the class ExampleController and understand what it does.
Try to edit the values in the URL in the browser address bar and see how they are received by the controller.
Click on the button labeled *Cause redirect now* and see how the message is passed in as a flash attribute
that exist only during the first request after the redirect.
Also note how the UriBuilder replaces the variables in the URL template.
Create a new method named *bar* mapped to URL */example/bar* in the ExampleController,
that takes three request parameters named *c*,*d*,*e* of types String, int, boolean respectively and a Model as its parameters.
Pass the parameter values to the model. Create a JSP page named *bar.jsp* that would display the values.
Restart the application and call this new method by accessing the URL [http://localhost:8080/eshop/example/bar?c=X&d=9&e=true](http://localhost:8080/eshop/example/bar?c=X&d=9&e=true).
**Task 04 (order management)**
Check out the branch step2 from git:
```
git checkout -f step2
```
New files appeared:
* filter `ProtectFilter` that asks for email and password when administrative pages are accessed
* controller `OrderController` for managing orders
* JSP pages in src/main/webapp/WEB-INF/jsp/order
Rebuild and restart the application.
Access the page [http://localhost:8080/eshop/order/list/all](http://localhost:8080/eshop/order/list/all) either through this link or through the menu item Administration - Orders.
Use email **`admin@eshop.com`** and password **`admin`** for authentication.
(Users are defined in the subproject eshop-sample-data in the class SampleDataLoadingFacadeImpl.)
Click on the various buttons.
- View an order in the state RECEIVED and ship it, then finish it.
- View another order in the state RECEIVED and cancel it.
Inspect the source code for the controller to see how it is done.
**Task 05 (list of users)**
Taking example from the existing controllers, create a new protected page displaying list of existing users.
It means:
* create a new controller `UserController` mapped to URL prefix */user*
* create an instance variable inside with injected `UserFacade` instance
* add a new method mapped to relative URL prefix */list* that retrieves list of users, adds it to model and forwards to JSP to display it
* create a new JSP in a new folder src/main/webapp/WEB-INF/jsp/user/list.jsp that displays a table of users
Rebuild and run the application.
Access the page [http://localhost:8080/eshop/user/list](http://localhost:8080/eshop/user/list).
**Task 06 (validation of input values)**
Check out the branch step3 from git:
```
git checkout -f step3
```
New files appeared:
* class `ProductController`
* JSP pages in src/main/webapp/WEB-INF/jsp/product
* validator class `ProductCreateDTOValidator`
Rebuild and run the application.
Access the page [http://localhost:8080/eshop/product/list](http://localhost:8080/eshop/product/list).
Click on the button *New product*. Submit empty form and see the error messages.
There are two validations going on.
1) JSR-303 validation which is driven by annotations on the class `ProductCreateDTO`
located in the subproject eshop-api, see that class.The annotations `@NotNull`, `@Size` and `@Min` specify requirements for valid data.
2) SpringMVC-specific validation performed in the class `ProductCreateDTOValidator` which can do any complex
checking, even involving relations among multiple properties.
Try to select color BLACK and price higher than 100 to see it in action.
Look at the source code of the class `ProductController` and the JSP pages to see how the form validation is implemented.
**Task 07 (new category form)**
Create a controller and JSP pages which provide creation of new categories.
Using the administration web pages, create a new category and a new product in that category.
**Solution**
You can see the complete solution in the branch [solution](https://gitlab.fi.muni.cz/pa165/seminar-07-web-ii/-/tree/solution).
\ No newline at end of file
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cz.muni.fi.pa165</groupId>
<artifactId>eshop-parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>eshop-api</artifactId>
<packaging>jar</packaging>
<name>API</name>
<dependencies>
<!-- validation annotations for bean properties -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
</dependencies>
</project>
package cz.fi.muni.pa165.dto;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.util.Objects;
public class CategoryCreateDTO {
@NotNull
@Size(min = 3, max = 50)
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CategoryCreateDTO that = (CategoryCreateDTO) o;
return Objects.equals(name, that.name);
}
@Override
public int hashCode() {
return name != null ? name.hashCode() : 0;
}
@Override
public String toString() {
return "CategoryCreateDTO{" +
"name='" + name + '\'' +
'}';
}
}
package cz.fi.muni.pa165.dto;
public class CategoryDTO {
private Long id;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
CategoryDTO other = (CategoryDTO) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
package cz.fi.muni.pa165.dto;
public enum Color {
BLACK, WHITE, RED, GREEN, BLUE, ORANGE, YELLOW, AZURE, MAGENTA, BROWN, PINK, GRAY, UNDEFINED
}
package cz.fi.muni.pa165.dto;
import cz.fi.muni.pa165.enums.Currency;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
public class NewPriceDTO {
private Long productId;
@NotNull
private BigDecimal value;
@NotNull
private Currency currency;
public Long getProductId() {
return productId;
}
public void setProductId(Long productId) {
this.productId = productId;
}
public BigDecimal getValue() {
return value;
}
public void setValue(BigDecimal value) {
this.value = value;
}
public Currency getCurrency() {
return currency;
}
public void setCurrency(Currency currency) {
this.currency = currency;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((currency == null) ? 0 : currency.hashCode());
result = prime * result + ((value == null) ? 0 : value.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
NewPriceDTO other = (NewPriceDTO) obj;
if (currency != other.currency)
return false;
if (value == null) {
if (other.value != null)
return false;
} else if (!value.equals(other.value))
return false;
return true;
}
@Override
public String toString() {
return "NewPriceDTO{" +
"productId=" + productId +
", value=" + value +
", currency=" + currency +
'}';
}
}
package cz.fi.muni.pa165.dto;
import cz.fi.muni.pa165.enums.OrderState;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
public class OrderDTO {
private Long id;
private UserDTO user;
private List<OrderItemDTO> orderItems = new ArrayList<>();
private Date created;
private OrderState state;
public UserDTO getUser() {
return user;
}
public void setUser(UserDTO user) {
this.user = user;
}
public List<OrderItemDTO> getOrderItems() {
return orderItems;
}
public void setOrderItems(List<OrderItemDTO> orderItems) {
this.orderItems=orderItems;
}
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
this.created = created;
}
public OrderState getState() {
return state;
}
public void setState(OrderState state) {
this.state = state;
}
public Long getId() {
return id;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((created == null) ? 0 : created.hashCode());
result = prime * result + ((state == null) ? 0 : state.hashCode());
result = prime * result + ((user == null) ? 0 : user.hashCode());
return result;
}
public void setId(Long id) {
this.id = id;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
OrderDTO other = (OrderDTO) obj;
if (created == null) {
if (other.created != null)
return false;
} else if (!created.equals(other.created))
return false;
if (state != other.state)
return false;
if (user == null) {
if (other.user != null)
return false;
} else if (!user.equals(other.user))
return false;
return true;
}
}
package cz.fi.muni.pa165.dto;
public class OrderItemDTO {
private Long id;
private ProductDTO product;
private Integer amount;
private NewPriceDTO pricePerItem;
public NewPriceDTO getPricePerItem() {
return pricePerItem;
}
public void setPricePerItem(NewPriceDTO pricePerItem) {
this.pricePerItem = pricePerItem;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public ProductDTO getProduct() {
return product;
}
public void setProduct(ProductDTO product) {
this.product = product;
}
public Integer getAmount() {
return amount;
}
public void setAmount(Integer amount) {
this.amount = amount;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((amount == null) ? 0 : amount.hashCode());
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((product == null) ? 0 : product.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
OrderItemDTO other = (OrderItemDTO) obj;
if (amount == null) {
if (other.amount != null)
return false;
} else if (!amount.equals(other.amount))
return false;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (product == null) {
if (other.product != null)
return false;
} else if (!product.equals(other.product))
return false;
return true;
}
}
package cz.fi.muni.pa165.dto;
import cz.fi.muni.pa165.enums.Currency;
import java.math.BigDecimal;
import java.util.Objects;
/**
* Provides total price of an order. Computing total price must be done on service layer,
* as it involves converting currencies.
*
*/
public class OrderTotalPriceDTO {
private OrderDTO order;
private BigDecimal price;
private Currency currency;
public OrderDTO getOrder() {
return order;
}
public void setOrder(OrderDTO order) {
this.order = order;
}
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
public Currency getCurrency() {
return currency;
}
public void setCurrency(Currency currency) {
this.currency = currency;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
OrderTotalPriceDTO that = (OrderTotalPriceDTO) o;
if (!Objects.equals(order, that.order)) return false;
if (!Objects.equals(price, that.price)) return false;
return currency == that.currency;
}
@Override
public int hashCode() {
int result = order != null ? order.hashCode() : 0;
result = 31 * result + (price != null ? price.hashCode() : 0);
result = 31 * result + (currency != null ? currency.hashCode() : 0);
return result;
}