Spring MVC: Saving values added into a form to load later - spring

I have a ParticipantsController.java which can add/delete/edit participant names.
import java.util.ArrayList;
import java.util.List;
import javax.validation.Valid;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import questForTheBest.domain.Participants;
#Controller
public class ParticipantsController {
#InitBinder("participant") // Validator for participant model
protected void initBinder(WebDataBinder binder) {
binder.addValidators(new ParticipantsValidator());
}
List<Participants> participantList = new ArrayList<>(); // create a list of participants
#RequestMapping("/participants") // Participants page
public String testing(Model model) {
model.addAttribute("participantList", participantList);
return "forms/ParticipantMaster";
}
#RequestMapping(value = "/participantDetail", method = RequestMethod.GET) // Shows participants
public String participantDetail(#ModelAttribute("participant") Participants participant, #RequestParam(value="participantId", required=false, defaultValue="-1") int participantId) {
if (participantId >= 1) { // Shows participants with an id greater than or equal to 1
Participants p2 = participantList.stream().filter(p -> (p.getId() == participantId)).findAny().get(); // gets participants
participant.setId(p2.getId()); // sets participants id
participant.setName(p2.getName()); // sets participants name
} else {
participant.setId(Participants.lastId); // otherwise create a new participant id
Participants.lastId++; // increment last id
}
return "forms/ParticipantDetail";
}
#RequestMapping(value = "/addParticipant", method = RequestMethod.POST) // Adding participants page
public String addParticipant(#Valid #ModelAttribute("participant") Participants participant,BindingResult result, Model model) {
if (result.hasErrors()) { // validation
return "forms/ParticipantDetail";
}
else {
participantList.removeIf(p -> (p.getId() == participant.getId()));
participantList.add(participant); // add participants
model.addAttribute("participantList", participantList);
return "forms/ParticipantMaster";
}
}
#RequestMapping(value = "/deleteParticipant", method = RequestMethod.GET) // Deleting participants
public String deleteParticipant(#RequestParam(value="participantId", required=false, defaultValue="-1") int participantId, Model model) {
participantList.removeIf(p -> (p.getId() == participantId)); // removes the participant with id
model.addAttribute("participantList", participantList);
return "forms/ParticipantMaster";
}
}
I wish to be able to: everytime a list of names are entered into the form I would like them to be saved when a button "Save current names" is pressed so that they can be later loaded again on another page by being able to be selected from a drop down box and then a "load" button is clicked.
The overall application is a leaderboard so I would like the same participants to be able to be saved for example so it can be loaded when a certain class in school will need to use the leaderboard.
Does this require the use of a database or is it possible without.
Thank you.

Ofcourse you will need the database for permanent storage of the leaderboard data on the solid state device (SSD storage) given your use case as memory(RAM) gets flushed/reset on machine reboot or crashes. You can have a layer of in-memory or a distributed cache as a layer above the database layer using an in-memory data structure like you have used a list in your implementation or redis respectively to make your application efficient for serving reads.
You got to have a Database Access Object (DAO) layer in your application for performing database related operations.
Please refer to this link to understand how DAO layer is implemented in spring boot
https://www.baeldung.com/jsf-spring-boot-controller-service-dao
Hope this helps!

Related

REST API return entire queried JSON

I do maintain an small REST API (SpringBoot) offering services to obtain data about ticketing from a small sized retailer. i.e.: you can send a request in order to get some information from a certain ticket (which has unique ID); the JSON response consists of a selection of fields from the unique ticket (which is stored as an unique document in Mongo DB).
Let say the API receives a request, then it would execute a query to Mongo DB, and then apply a projection to parse the queried data into a data model class, which in turn is finally parsed to a response JSON like, i.e.:
{
"ticketData": {
"retailerId": "023",
"ticketId": "09834723469324",
"ticketDate": "2021-06-20"
},
"buyerData": {
"buyerId": "LN4382"
}
}
Well, I am now required to return the entire queried JSON (that is, a JSON containing the whole ticket information, that has a lot of fields). ¿Is there any way to achieve this without creating a data model class with tens or hundreds of properties to match the stored ticket JSON? Even if I specify the API response using YAML and then use a codegen tool, is a lot of tedious work, and whenever the ticket JSON format evolves, I would need to change my DAO and response.
I just would like to send the original Mongo stored JSON and hand it back to the API client. Is there any way to achieve that?
You can utilize Jackson ObjectMapper which Spring already uses to serialize and deserialize JSON.
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.ArrayList;
import java.util.List;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
#RestController
public class HelloWorldController {
private final ObjectMapper objectMapper;
public HelloWorldController(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
#GetMapping("/jsonList")
public ResponseEntity<List<JsonNode>> getJsonList() {
List<String> data = List.of("{\"number\": 1}",
"{\"number\": 2}",
"{\"number\": 3}");
List<JsonNode> nodes = toJsonNodeList(data);
return ResponseEntity.ok(nodes);
}
private List<JsonNode> toJsonNodeList(List<String> strings) {
List<JsonNode> nodes = new ArrayList<>();
for (String s : strings) {
try {
JsonNode node = this.objectMapper.readTree(s);
nodes.add(node);
} catch (IOException ioe) {
throw new UncheckedIOException(ioe);
}
}
return nodes;
}
}

#GetMapping method not calles

I am a beginner so please don't be mean.
I have got an html page index.html
And I want the method MainController::getListEmployee to be called.
In this method, I put a System.err to see if the method is called. And I see nothing.
Controller code
package com.cgi.listeemployes.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.cgi.listeemployes.model.User;
import com.cgi.listeemployes.repository.UserRepository;
#Controller // This means that this class is a Controller
#RequestMapping(path="/") // This means URL's start with /demo (after Application path)
public class MainController {
#Autowired // This means to get the bean called userRepository
// Which is auto-generated by Spring, we will use it to handle the data
private UserRepository userRepository;
#GetMapping(path="/index.html")
public #ResponseBody Iterable<User> getListEmployee() {
// This returns a JSON or XML with the users
System.err.println("getting ");
return userRepository.findAll();
}
#PostMapping(path="/add") // Map ONLY POST Requests
public #ResponseBody String addNewUser (#RequestParam String name
, #RequestParam String email) {
// #ResponseBody means the returned String is the response, not a view name
// #RequestParam means it is a parameter from the GET or POST request
User n = new User();
n.setName(name);
n.setEmail(email);
userRepository.save(n);
return "Saved";
}
#GetMapping(path="/all")
public #ResponseBody Iterable<User> getAllUsers() {
// This returns a JSON or XML with the users
return userRepository.findAll();
}
}
thanks for your help
When you want to return a html, just return a string with the name of the html file, it could be "Index" (without the .html).
In your #GetMapping(path="/index.html"), you are returning an object instead a html.
If you want to load data from database and render it at your html, then add the attribute "Model model" in your parameters, like this:
#GetMapping(path="/index.html")
public String getListEmployee(Model model) {
List<User> users = userRepository.findAll();
model.addAttribute("yourUsers", users); // this gonna inject the list of users in your html
System.err.println("getting ");
return "Index"
}
Then in your html, you can get the users with ${yourUsers} and do whatever you want.
I saw your project, it is missing the template engine. Template engine is what gonna get the data of your backend and show in your front/html. I added the Thymeleaf template engine into your pom.xml, and it worked. Here is the thymeleaf dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
To work with thymeleaf, you have to put all your html into a new folder called "templates" in the "resources", same level of "static". You cannot use html in the static folder, this folder should have only css, javascripts and assets.

How to specify specific request mapping url

sorry i am new to spring boot and trying to learn, i have this code that when i run it will open a json request of my catalog item if i enter any url that is localhost/catalog/(any userid). But i want to narrow it to 1 specific userid how can i do that? for example i dont want any url to work except localhost/catalog/friends or any other item from the list i mention.
Code:
package com.poc.moviecatalog.controller;
import com.poc.moviecatalog.models.CatalogItem;
import java.util.Collections;
import java.util.List;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
#RequestMapping("/catalog")
public class MovieController {
#RequestMapping("/{userId}")
public List<CatalogItem> getCatalog(#PathVariable("userId") String userId) {
return Collections.singletonList(
new CatalogItem("friends", "test", 9)
);
}
}
I hope I've understood your question correctly, you don't want to provide a mapping for any user id, but want one specific endpoint /catalog/friends.
#RestController
#RequestMapping("/catalog")
public class FriendsController {
#GetMapping("/friends")
public List<Friends> getFriends() {
....
}
}
then the url would be: http:<HOST>:<PORT>/catalog/friends

"Cannot resolve symbol" error while implementing method to get data from logged jhipster user

I am a newbie at Java programming and Jhipster framework and maybe my question is an annoying one, but despite the many topics I read on it I can't solve my question. So, I am asking for some help.
In this topic getting the current logged in user in JHipster I found this piece of code:
final Optional<User> isUser = userService.getUserWithAuthorities();
if(!isUser.isPresent()) {
log.error("User is not logged in");
return new Shinything()
}
final User user = isUser.get();
// continue with the user
which is exactly what I need in my class NjdUserConfiguration.java: this class contains a field (User) user and I aim to get NjdUserConfiguration retrieved by logged in user login.
So, firstly, I add to NjdUserConfigurationRepository.java this query annotation:
#Query("select njd_user_configuration from NjdUserConfiguration njd_user_configuration where njd_user_configuration.user =:user")
Optional<NjdUserConfiguration> findOneByUser(#Param("user") User user);
Secondly, I create NjdUserConfigurationService.java like this:
package it.tal.app.service;
import it.tal.app.domain.NjdUserConfiguration;
import it.tal.app.domain.User;
import it.tal.app.repository.NjdUserConfigurationRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
/**
* Service Implementation for managing NdjUserConfiguration.
*/
#Service
#Transactional
public class NjdUserConfigurationService {
private final Logger log = LoggerFactory.getLogger(NjdUserConfigurationService.class);
private final NjdUserConfigurationRepository NjdUserConfigurationRepository;
public NjdUserConfigurationService(NjdUserConfigurationRepository njdUserConfigurationRepository) {
this.NjdUserConfigurationRepository = njdUserConfigurationRepository;
}
/**
* Get one NdjUserConfiguration by user.
*
* #param user the user of the entity
* #return the entity
*/
#Transactional(readOnly = true)
public Optional<NjdUserConfiguration> findOneByUser(User user) {
log.debug("Request to get NdjUserConfiguration : {}", user);
return NjdUserConfigurationRepository.findOneByUser(user);
}
}
Thirdly, I tried to used it in NjdUserConfiguration.java mocking the original code in this new method:
public NjdUserConfiguration getCurrentUser() {
Optional<User> isUser = new UserService.getUserWithAuthorities();
if(isUser.isPresent()) {
//final User user = isUser.get();
return new NjdUserConfigurationService.getOneByUser(isUser.get());
} else {
return null;
}
}
No matter my efforts both getUserWithAuthorities() and getOneByUser(isUser.get()) result in "cannot resolve symbol getUserWithAuthorities()" and "cannot resolve symbol getOneByUser()", though both
import it.tal.app.service.NjdUserConfigurationService;
import it.tal.app.service.UserService;
are present. What did I do so badly or what am I missing?
Thank you
You misuse new operator. Instead of
return new UserService.getUserWithAuthorities();
use
return UserService.getUserWithAuthorities();
assuming UserService is an injected bean.
BTW, java code conventions recommend naming variables so they start with lowercase letter.

Creating a unique Id and saving it in DB

I am new to Spring REST. I have to achieve the below mentioned requirement using Spring REST. I have to use JPA Repository for DB interaction
I have 2 tables, Application and App_Config. Application table has the following rows:
id(Primary Key), ApplicationId, Status, Source_System. App_config table has the following rows: ApplicationId (foreign key), HeaderText, FooterText. I need to use java UUID to generate a unique id for the application every time a new application sends an HTTP POST request. Based on the ApplicationId generated I need to save the data in App_Config table. There is a possibility that the same application appears twice. In that case I have to retrieve the already generated ApplicationId and load the Header and Footer from App_Config table.
Please advise how to achieve this via POST method. I need to send back only the generated ApplicationId to the user
Partial solution of your problem (the other part is not understood) regarding sending a rest with UUID and the rest api will be server+/generator/uuid
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.UUID;
#RestController
#RequestMapping("/generator")
public class UuidGeneratorRestController {
#RequestMapping(value = "/uuid", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<UUID> getUUID() {
UUID generated = UUID.randomUUID();
return new ResponseEntity(generated, HttpStatus.OK);
}
}

Resources