Thymleaf display data from table by date - java

Okay so I have this situation:
User can have a wallets, wallets can have a transactions and user can create a transaction for every wallet he owns.
Now, transactions besides other fields have a field date.
When the user creates a transaction, he also selects the date. Now, imagine a user create next transactions:
26/01/2023 two transactions, then for example yesterday or 25/01/23 and then back to 14/01/2023
So I want to show transactions for example like this:
As you can see, if there is no transactions on date then dont show the date, and if user have a more then one transaction for same date show him inside same element instead of creating a whole new date. For example my current program display transactions like this:
So as you can see I have a two transactions for same date and they are displayed separated.
And I showed on above SS how it would look like.
This is controller that saveIncome transaction and controller that return all transactions by user ID, I mean from logged in user.
#PostMapping("/saveIncome/{walletId}")
public String saveIncome(#PathVariable(value = "walletId") long walletId, #Valid Transaction transaction, BindingResult result, Model model) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
UserDetailsImpl user = (UserDetailsImpl) authentication.getPrincipal();
long userId = user.getId();
Wallet wallet = walletService.getWalletById(walletId);
boolean thereAreErrors = result.hasErrors();
if (thereAreErrors) {
model.addAttribute("incomeCategories", IncomeCategories.values());
return "income_transaction";
}
transaction.setWallet(wallet);
transaction.setUserId(userId);
transaction.setWalletName(wallet.getWalletName());
transactionService.saveIncome(transaction, walletId, userId);
return "redirect:/api/wallet/userWallet/balance/" + userId;
}
#GetMapping("/userTransactions/{user_id}")
public String getUserTransactions(#PathVariable("user_id") long user_id, Model model) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
UserDetailsImpl user = (UserDetailsImpl) authentication.getPrincipal();
long userId = user.getId();
model.addAttribute("userId", userId);
model.addAttribute("transactions", transactionService.findDistinctIdByUserId(user_id));
return "transactions";
}
And this is Thymeleaf so far:
<div>
<div th:each="transactions : ${transactions}">
<h2>Amount: <span th:text="${transactions.amount}"></span></h2>
<br>
<h2>Note: <span th:text="${transactions.note}"></span></h2>
<br>
<h2>Date: <span th:text="${transactions.date}"></span></h2>
<br>
<h2>Wallet name: <span th:text="${transactions.walletName}"></span></h2>
<br>
<h2>Expense Category: <span th:text="${transactions.expenseCategories}"></span></h2>
<br>
<h2>IncomeCategory: <span th:text="${transactions.incomeCategories}"></span></h2>
</div>
How to change it so actually I get a response as from the first picture?
I appreciate any help and sorry for my bad English grammar.
Also, I tried to find something, and searching left and right but nothing useful for something like this. I know I can sort the date but I prefer this option first. Thanks again.

Related

React + Spring #GetMapping with #RequestParam simple app

I am trying to make a simple web app, that will have 3 forms for data input, Submit button and Results form.
Requirements: When I enter a data in forms and push Submit button, these parameters should go to a controller and after that React should also parse data from json response that comes from the controller and show parsed data in the Results form.
I have the Spring Controller that takes 3 parameters and return json file as a response.
But I am new with React. I've tried to use different approaches, but stuck with what way exactly I need to do it in this case. So need a help to create a simple React part.
Controller part:
#GetMapping("/current/city")
public JSONObject getCurrentPollutionDataByCityStateCountry(
#RequestParam(value = "city") String city,
#RequestParam(value = "state") String state,
#RequestParam(value = "country") String country
) {
try {
return pollutionService.getCurrentPollutionDataByCityStateCountry(city, state, country);
} catch (Exception e) {
e.printStackTrace();
}
return new JSONObject();
}
Response example:
{"date":"Tue Dec 06 22:13:32 CET 2022","no2":"48.67","pm10":"9.51","pm2_5":"5.85"}
UPDATE
Here is my App.js part:
import React, {Component} from 'react'
import './App.css'
import axios from 'axios'
class App extends Component {
constructor(props) {
super(props);
this.state = {
city: 'New York',
province: 'New York',
country: 'US',
responseData: ''
};
this.handleInputChange = this.handleInputChange.bind(this);
}
handleInputChange(event) {
const target = event.target;
const value = target.value;
const name = target.name;
this.setState({
[name]: value
});
}
handleSubmit(event) {
axios.get('http://localhost:8080/pollution/current/city?' +
'city=' + this.state.city +
'&state='+ this.state.province +
'&country=' + this.state.country)
//not sure about setState here and what is going after that
.then(response => this.setState({responseData: response.data.date}))
//need to take all fields from response
//just alert message with returned response for now
alert('Response: ' + this.state.responseData);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
City:
<input name="city" type="text" value={this.state.city} onChange={this.handleInputChange}/>
</label>
<br/>
<label>
State:
<input name="state" type="text" value={this.state.province} onChange={this.handleInputChange}/>
</label>
<br/>
<label>
Country:
<input name="country" type="text" value={this.state.country} onChange={this.handleInputChange} />
</label>
<br/>
<input type="submit" value="Submit"/>
</form>
);
}
}
export default App
But I am not sure about my approach in general and particularly about parts where I left comments in App.js.
To be more precise with questions:
Should this approach work for my case or I need to implement some different logic?
If yes, how I can get all fields from response? I mean not only the first one (date) but no2, pm10, pm2_5 also. For now this logic can return only a first value from json.
How I can set these fields to show them in pop-up window (alert) or if question 2 will be solved, this thing also will be good in current form?
The only problem I think you need to solve is to set the data not data.date
use this:
this.setState({responseData: response.data}))
then access your data fields using
responseData.date
you can replace date with any other field.
do the same for alerts.
your code is working fine, furthermore, you can learn to use functional component instead of class, its much easier.

JSP - set <c:param /> value from input field to pass it in URL

I'm creating a web shop in JSP for a school project.
On each product page, there's a button to add it to the cart.
Originally, there is only one item added to the cart when we press the "Add" button.
I send the productId to add to the controller by adding it as parameter in the url as you can see here :
<div class="product-page">
<div class="product">
<h1>${product.title}</h1>
<img src="${product.imageUrl}"/>
<div class="price"><p>${product.price}€</p></div>
</div>
<c:url var="addLineToCart" value="/product/addLineCart">
<c:param name="productId" value="${product.id}" />
</c:url>
<a id="addToCart" type="submit" href="${addLineToCart}"><spring:message code="addCart"/></a>
What I'd like to do, is to add an input field to specify the amount of items to add in the cart. I did it here :
<div class="product-page">
<div class="product">
<h1>${product.title}</h1>
<img src="${product.imageUrl}"/>
<div class="price"><p>${product.price}€</p></div>
</div>
<input type="number" name="quantity" value="1"/>
<c:url var="addLineToCart" value="/product/addLineCart">
<c:param name="productId" value="${product.id}" />
</c:url>
<a id="addToCart" type="submit" href="${addLineToCart}"><spring:message code="addCart"/></a>
My problem is that I don't know how to pass the value from the input field in the <c:param/> property in order to add it in the URL too.
Here is how my controller looks like assuming I get the quantity to add via the URL :
#Controller
#RequestMapping(value="/product")
#SessionAttributes({Constants.CURRENT_CART})
public class ProductController {
private ProductDAO productDAO;
#Autowired
public ProductController(ProductDAO productDAO){
this.productDAO = productDAO;
}
#ModelAttribute(Constants.CURRENT_CART)
public Cart cart()
{
return new Cart();
}
#RequestMapping (method = RequestMethod.GET)
public String home(ModelMap model, #RequestParam("product") int productId, #ModelAttribute(value=Constants.CURRENT_CART) Cart cart){
Product product = productDAO.getById(productId);
model.addAttribute("product", product);
model.addAttribute("title", "Produit");
model.addAttribute("cart", cart);
return "integrated:product";
}
#GetMapping("/addLineCart")
public String addLineCart(#ModelAttribute(value=Constants.CURRENT_CART) Cart cart, #RequestParam("productId") int productId, #RequestParam("quantity") int quantity, ProductService productService)
{
Product product = productService.searchProduct(productId,productDAO);
cart.addProduct(product, quantity);
return "redirect:/product?product=" + productId;
}
}
Thanks for your help.
The easiest way is to wrap the fields in a HTML <form> tag and submit the data to your controller. You should also replace GET with a POST since your browser might decide to cache the response to some combinations of productId and quantity and your application might exhibit some unwanted behavior as result of that (don't forget to change your #GetMapping in your controller with a #PostMapping also).
There is also the option of submiting this to the server with JavaScript as an Ajax request, or to change the value of the URL in your existing link to include the quantity when you click it and before making the request to the server, but using a form with a POST action is the easiest and cleanest solution.
Finally, <c:url> and <c:param> are server side tags. They get evaluated at the server to produce your final HTML that gets sent to the client browser. You can't get your input value from the browser into your <c:param> because you are running client code at this point, no longer server code.

How can I have a model attribute persist between redirects?

I am trying to write a password reset function for a website. I am running into an issue that I am using a couple of redirects to transition from postmappings to getmappings and they dont seem to be carrying the attributes they need to with them, namely the user object that I am trying to reset the password form, here is an example of one of my mappings:
#PostMapping("/user/forgot")
public String emailCheck (#RequestParam String email, Model model){
User user = userDao.findByEmail(email);
if (user==null){
model.addAttribute("wrongEmail", true);
return "redirect:/user/forgot";
}
else {
model.addAttribute("user", user);
return "redirect:/verifysecurity";
}
}
And here is the template where I then call the user attribute:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="en">
<head th:replace="fragments/header :: header('Security', '')"></head>
<body>
<div th:replace="fragments/navbar :: navbar"></div>
<h1 th:if="${wrongAnswer}">Answer does not match record on file, please try again</h1>
<h1>Please answer your security question: WHat is your best friends name?</h1>
<form id="passwordForm" th:action="#{/verifysecurity}" th:method="post">
<label for="answer">Answer</label>
<br/>
<input type="text" id="answer" name="answer"/>
<input type="hidden" name="user" id="user" th:value="${user}"/>
<input type="submit" class="btn btn-block btn-primary" value="Request"/>
</form>
</body>
</html>
Then on the next mapping afterwards I get a null pointer exception for the user:
#PostMapping("/verifysecurity")
public String verify (Model model, #RequestParam User user, #RequestParam String answer){
String security = user.getSecurity_question();
if (answer.equals(security)){
model.addAttribute("user", user);
return "redirect:/reset/password";
} else {
model.addAttribute("wrongAnswer", true);
model.addAttribute("user", user);
return "redirect:/verifysecurity";
}
}
How can I fix this, and if model attributes won't work what should I be doing instead?
Use spring RedirectAttributes.addFlashAttribute(), as name suggested it's stored in flashmap which internally uses user session to pass on this data to next redirect, and removes ones data is used.
Example from spring doc:
#RequestMapping(value = "/accounts", method = RequestMethod.POST)
public String handle(Account account, BindingResult result, RedirectAttributes redirectAttrs) {
// Save account ...
redirectAttrs.addFlashAttribute("message", "Account created!");
return "redirect:/accounts/{id}";
}

How to get modelAttribute values that are not in form, in Spring

I have an hibernate entity object. I need to update this object, so I passed this object to a form. In the form i will change some values and the others are constant. And I can not show these constant values to the client, so they should pass to next page via another method except from diplaying them explicity in a html form.
Here is my object obtained in controller and passed to the view:
#GetMapping("/update")
public String update(#RequestParam("dataId") int id, Model md){
Doctor dr = doctorService.getById(id);
/*for example lets say this doctor object has following properties
dr.setId(3);
dr.setName("James");
dr.setUserId(7);
*/
md.addAttribute("doctor", dr);
return "object-form";
}
Here is my form in view :
<form:form action="save" modelAttribute="doctor" method="post">
<form:errors path="name"></form:errors>
<form:input path="name" placeholder="Doktor İsmi" class="form-control" />
<form:hidden path="id" />
<input type="submit" value="Save doc" />
</form:form>
From form, only name and id values are coming, however, the userId is null. I need to get this userId without post.
Here is my post-process controller that I handle the object:
#PostMapping(value="/save")
public String save(#Valid Doctor dr, BindingResult bindingResult){
doctorValidator.validate(dr, bindingResult);
if (bindingResult.hasErrors()) {
return "object-form";
}
else{
doctorService.save(dr);
return "redirect:list";
}
}
I don't know how can achieve this r even there is way for it. I searched on Google but I did not find any solution.
Thank a lot,,
You can get previous doctor object from db and get the user ID from there like below:
#PostMapping(value="/save")
public String save(#Valid Doctor dr, BindingResult bindingResult){
Doctor prevDr = doctorService.getById(dr.getId());
dr.setUserId(prevDr.getUserId());
doctorValidator.validate(dr, bindingResult);
if (bindingResult.hasErrors()) {
return "object-form";
}
else{
doctorService.save(dr);
return "redirect:list";
}
}

How to create a session object?

I am creating a login page for my web application. I want to create a session object whenever
a new user logged in. I know the concept of sessions, but i didnt used that before. Can i do it with a simple class. Or, i have to move to servlet.
If i shall do it with a simple class means, how to create a session object.
This is my scenario...
The HTML CODE:
<table>
<tr>
<td>User Name: </td><td><input id="uName" class="required" type="text"
size="5" /></td>
</tr>
<tr>
<td>Password: </td><td><input id="pwd" class="required" type="text" size="5"
onclick="login()"/></td>
</tr>
</table>
The JS Code:
function login(){
var userDetails = { uName : null, pwd : null };
dwr.util.getValues(userDetails);//Yes, i am using DWR.
LoginAuthentication.doLogin(userDetails, loginResult);
}
function loginResult(nextPage){
window.location.href = nextPage;
}
The Java Code:
public class LoginAuthentication
{
public String doLogin(User user) throws SQLException, ClassNotFoundException{
String userName = user.getUserName();
boolean loginResult = verifyUser(user);//Another method that verifies user details with the DB.
if (loginResult == true){
/* Here I have to create session object,
and i want to add the current username in that object. How to do it.*/
return "MainPage.html";
}
else{
return "loginRetryPage.html";
}
}
The concept that was given to me about session is pretty simple and clear. I have to create a session object after a valid user input & add the user name to that object, Destroy the object when logout was clicked. But i didnt worked on sessions before. I mean, i dont know the syntax to create a session variable.
How shall i create a session Object here?
Any suggestions would be more appreciative!!!
Thanks in Advance!!!
In a servlet a session is obtained with the following line:
Session session = request.getSession();
And to get the request object with DWR, you do (see here):
WebContext ctx = WebContextFactory.get();
HttpServletRequest request = ctx.getHttpServletRequest();
(The HttpServletRequest contains all data about the HTTP request that has been sent by the browser to the server)
It is better to always use request.getSession(false); after successful login.

Categories