Spring MVC stop refreshing the page after GetMapping - html

I am working on a page where I have to retrieve the "tasks" of a specific date from the database. My current approach is to use GetMapping at the server, and return the list of tasks
Below is part of my TaskController
#Controller
#RequestMapping()
public class TaskController {
#Autowired
private TaskService taskService;
#GetMapping("/calendar/{date}")
public String displayTasksByClick(#PathVariable("date") int date, Model model) {
long userId = this.getCurrentUserId(); // just a method to get the user id requesting the task
List<Task> taskList = taskService.findByDateAndUserId(date, userId);
model.addAttribute("taskList", taskList);
return "/calendar";
}
And calendar.html looks like this (I'm only pasting the relevant part)
<html lang='en' xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset='utf-8' />
<title>Dashboard</title>
<link rel="stylesheet" href="../static/css/calendar.css">
<script src="jquery-3.5.1.min.js"></script>
</head>
<body>
<ul style="list-style-type: none; margin: 0;">
<li><a th:href="#{/calendar/20220228}">show</a></li>
<li><a th:href="#{/calendar/20220301}">show</a></li>
<li><a th:href="#{/calendar/20220301}">show</a></li>
</ul>
......
<div th:each="task : ${taskList}">
<label th:text="${task.name}"></label>
</div>
<!-- the rest is irrelevant to the question --!>
.......
</html>
So whenever I click on the <a> elements, the client sends a request to the server, and the URL is handled by GetMapping method, returning the tasks. But while this happens, the page is also refreshed. Is there a way to display the tasks without having to refresh the page?
I tried returning void from the display method, but Spring ends up automatically returning /calendar/{date}, and it's still not what I want
#GetMapping("/calendar/{date}")
public void displayTasksByClick(#PathVariable("date") int date, Model model) {
long userId = this.getCurrentUserId(); // just a method to get the user id requesting the task
List<Task> taskList = taskService.findByDateAndUserId(date, userId);
model.addAttribute("taskList", taskList);
}

For your current implementation, no, it is not possible. You have to refresh the page for the tasks to be displayed. That's how server side rendering works. The page is created on the server with the dynamic data, then the static page is returned to the browser.

Related

Is there a way to inline a Spring MVC model attribute in JSON in thymeleaf for an html attribute?

Okay, So, I have a model object that we will call Station, with a list of codes associated.
class Station {
public List<String> codes;
}
I have a controller method which render a view showing the list of a station.
class StationController {
#Autowired
private StationService stationService;
#GetMapping()
public String showAllStations(Model model) {
model.addAttribute("stations", stationService.getAllStations())
return "stationsView"
}
}
Here is my template
<html xmlns:th="http://www.thymeleaf.org">
<body>
<div th:each="station : ${stations}" th:text="${station.codes}">
</div>
</body>
</html>
So, let's say my first station as two codes, CD1 et CD2. The rendered html will be the following :
<html xmlns:th="http://www.thymeleaf.org">
<body>
<div>[CD1, CD2]</div>
...Skipping the additional divs.
</body>
</html>
Is there a way to render the codes as a JSON array ? I know thymeleaf can do it in javascript, using inline.
For example,
<script type="text/javascript" th:inline="javascript">
/*<![CDATA[*/
var data = [[${renter.sabreCodes}]];
/*]]>*/
</script>
will be rendered as
<script type="text/javascript" th:inline="javascript">
/*<![CDATA[*/
var data = ["CD1","CD2"];
/*]]>*/
</script>
So I would want the same result for an attribute value.
Of course, I have a lot of workaround for this, but I would want to know if these workaround are needed, or if it just me who don't know how to get straight to the point.

Thymeleaf Content-Type is being ignored in HTML Email (not rendered as HTML)

I'm developing a RESTful API with Spring Boot as backend and an Angular 9 frontend. Upon user registration, a verification email is sent, in which the user needs to click on a link to verify their account. Functionally, all is set and working. However, the HTML is never rendered despite having Content-Type set to 'text/html' and charset to UTF-8. I'm using Thymeleaf to generate the HTML:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta http-equiv="Content-Type" content="text/html charset=UTF-8" />
</head>
<body>
<header>TooManyThoughts</header>
<section>
<p th:text="#{registration.mail.greeting(${#messages.msg('mail.greeting.title.' + user.personalData.title.representation, user.personalData.firstName, user.personalData.lastName)})}"></p>
<p th:text="#{registration.mail.preamble}"></p>
<p>
<a th:text="#{registration.mail.link}"
th:href="#{http://localhost:8081/auth/register/email/verify/{id}/{key}(id = ${user.id}, key = ${user.emailValidationKey}, send='auth,login', verified='email')}"></a>
</p>
<p>
<span th:text="#{registration.mail.clue01(${user.credentials.username})}"></span>
<span th:text="#{registration.mail.clue02}"></span>
</p>
<p th:text="#{registration.mail.catchphrase}"></p>
<p th:text="#{registration.mail.goodbye}"></p>
<p>
<span th:text="#{registration.mail.signature01}"></span>
<br>
<span th:text="#{registration.mail.signature02}"></span>
</p>
</section>
<footer></footer>
</body>
At the time of writing, all frameworks used are in their latest versions. Currently, I'm sending the email to my personal gmail account. When googling the issue, I've found some rendering issues with gmail, but they've all been old and from around 2011 or so. The only other posts and entries I could find were about setting Content-Type and charset properly, which in my opinion I've done.
I'm kinda stuck here since two days with what I believe should be a very basic issue, so any help is highly appreciated.
Thanks to Andrew's hint on using setContent() instead of setText() for javax.mail.Message, I realized that I've never actually set the content type of my email anywhere in the code. I'm not using javax.mail but springframework.mail.javamail, so I had to look for a solution and I found it here. The working code now looks like this:
public EmailVerificationModel sendMail(final EmailVerificationModel model) {
final MimeMessagePreparator msgPreparator = mimeMessage -> {
final MimeMessageHelper msgHelper = new MimeMessageHelper(mimeMessage, "UTF-8");
msgHelper.setFrom("petesideburner#gmail.com");
msgHelper.setTo(model.getCredentials().getEmail());
msgHelper.setSubject(this.mailBuilder.subject(model));
msgHelper.setText(this.mailBuilder.build(model), true);
};
this.mailSender.send(msgPreparator);
return this.verificationMailSent(model);
}
All that I had to do was to pass true as 2nd argument to Spring's MimeMessageHelper.setText() method. The hidden quirks of method signatures. Personally, I prefer more distinct names for methods and variables, and so for better readability of my code I've changed it to:
public EmailVerificationModel sendHtmlMail(final EmailVerificationModel model) {
final boolean html = true;
final MimeMessagePreparator msgPreparator = mimeMessage -> {
[...]
msgHelper.setText(this.mailBuilder.build(model), html);
};
this.mailSender.send(msgPreparator);
return this.verificationMailSent(model);
}

How to open specific user profile based on what is clicked on

At first this sounded very simple, but actually I couldn't find a way to implement this.
I have Spring web app, with rest controllers and database. I have users in my web app and I want to open specific page in which details of that user will be shown. So how do I send information about what is clicked on (link to that specific user's details) to another page where the details about user are being displayed?
This is what I tried and when I load profile page nothing appears on it:
index.html
<html ng-app="app" ng-controller="appController">
<head >
<script src="js/angular.min.js"></script>
<script src="js/App.js"></script>
<p ng-click = "setProfileDetails(john)">profile</p>
profile.html
Here I use the same App.js file so I can read the same controller.
<body ng-controller = "appController">
<div ng-model = "profileDetails">
{{profileDetails.username}}
</div>
</body>
App.js
$sopce.profileDetails = null;
$scope.setProfileDetails = function(username){
$http.get("services/rest/getUser/" + username).then(function(response){
$scope.profileDetails = response.data;
}, function(Response){
});
}
on jsp page:
<form action="user-details/${userid}">
//list of users or whatever you want
</form>
on controller
#RequestMapping("user-details/{userid}")
public String showUserDetails(#PathVariable int userid, Model model) {
model.addAttribute("userDetails",userDAO.getUserDetailsById(userid);
return "/ac_user/user-details";
}
You should expose an endpoint which returns user details provided some user identifier like userId. So, when someone clicks on a user, send the userId to the API and retrieve the response and display it. You just need to make a simple API call. Details about your front-end implementation are missing.

how can display html page in action

my project structure :
RouteConfig :
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
index.html :
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8" />
</head>
<body>
<h3>hi</h3>
</body>
</html>
Home Controller :
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
}
WebApi is startup project.
how can display index.html in Index action or replace Index view with index.html.
The files are in different profects, you canĀ“t do it at this way.
Why you dont use the home/index action and views/home/index.cshtml to put your index.html content?
Or you can make a redirect to index.html URL on home/index action.
By default, your controller action will return Index.cshtml view instead of Index.html page. If you want to do redirection pointed at Index.html on WebClient project, modify your Index action method inside controller like this (set your WebClient's full address path, because tidle sign to replace site root path doesn't work at this case):
public class HomeController : Controller
{
public ActionResult Index()
{
return Redirect("http://ServerAddressOrName:Port/WebClient/Index.html");
}
}
Afterwards, you need to build both projects then assign your WebApi and WebClient to different sites, since it is impossible to combine them with different Web.config content.

On Spring Boot, how to get the html to communicate with the model

This probably a very simple question, but I can't figure it out alone. I have the following controller:
#RestController
public class TestController extends AbstractCloudController {
private final EquipmentRepository equipmentRepository;
#Autowired
TestController(EquipmentRepository er) {
equipmentRepository = er;
}
#RequestMapping(method=RequestMethod.GET) void index() {
List<String> codes = equipmentRepository.findAllEquipments();
String output = "";
for (String code : codes) {
output += "ID "+code+"\n";
}
}
}
And the following index.html:
<!doctype html>
<html>
<head>
<title>Test Page</title>
<link rel="stylesheet"
href="./bower_components/bootstrap-css-only/css/bootstrap.min.css" />
</head>
<body ng-app="testApp">
<div class="outer">
<h1>Hello World!</h1>
<div class="container">
<div ng-controller="TestController" ng-cloak="ng-cloak">
<p>This is a test page</p>
</div>
</div>
<script src="js/angular-bootstrap.js" type="text/javascript"></script>
<script src="js/hello.js"></script>
</div>
</body>
</html>
How do I get the information from the controller to the server side without it overriding the html? When I make the controller return something, it ends up overwriting the html and printing only the equipment code instead instead of the "Hello World", even the page title doesn't show.
I don't know what do you returned in your controller, but you may check this document: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-return-types
If you want to print the content of output, you may add it to a Model
#RequestMapping(method=RequestMethod.GET, Model model) void index() {
List<String> codes = equipmentRepository.findAllEquipments();
String output = "";
for (String code : codes) {
output += "ID "+code+"\n";
}
model.addAttribute("output", output);
}
then use JSP Expression Language to get the content
${output}
PS. Spring will treat a returned string as view name, not html content by default.