Innhold er ikke tilgjengelig i valgt språk enda
My experience, it is nearly impossible, but ...
This blog application is built on the principle to store as little state as possible in memory between roundtrips. In a cloud based environment we have no control of server nodes, so this state can be wiped out at any time. Hibernate second level cache could be used to store state. But it is not possible in practice to avoid some state stored between server requests. State could be preserved in different ways:
Typical required state is user login information and conversational state. Spring Boot uses secure cookie for session information and authentication.
Temporary state between pages: Use flash attributes.
If you use a Thymeleaf page template (as in this application) there will be common controller logic belonging to the template. You need to handle redirect from template to the current web page. Errors detected in error handler can redirect users to default error page or write an error message on the current page. What to do depends on the type of error. Be aware to avoid recursive redirects due to unhandled errors.
What I would recommend to store state is to use session state, either using key value store in HttpSession or more advanced Spring session beans. But a session will at some point expire, either by user logging out or by built in timer. The result can be that the user suddenly is redirected to home page. To avoid this to a certain extent, I can increase the 30-min Spring default timeout, but not too much since sessions should not live forever. Spring JDBC session mechanism that automatically stores state in the database can be used, because it is independent of deploy platform and easier than Redis.
As a start I have used some hidden fields, but it has to be included in almost every form post, so a bit cumbersome. Too many hidden fields will usually mess up the code. One advantage with hidden fields, is that it does not matter if the session expires. The biggest disadvantage is that a hidden field can be modified with inspect mode in any browser. This also applies to any type of web storage, except secure cookies. So do not used hidden fields, web local/session storage for critical attributes that e.g. modifies the database. But I will use session storage for blog searching and grouping attributes, and for storing timezone information originating from client.
Loosing this information will not force a return to the homepage anyhow.
Recently I have made collapsable menus based on menu items (blogs) organized by topics. To be efficient, JavaScript was required. I wanted to keep the collapse state stored, so the user do not have to collapse and expand all the time. After some consideration, session storage on the browser was used for this. In addition, I store timezone information in browser session storage.
I have only one container running of Hostinger. This means that users will not be automatically switched to another node that easily can occur with several Kubernetes pods. Perhaps later I will store state in the database using Spring JDBC session. But it is not absolutely required.
Cookies can be practical because kept when session expires, but I am not very fond of cookie abuse. Note: Spring Security uses a cookie by default for user and login information and I use that.
The Spring session scope applies to all tabs and windows (not Incognito mode) for most modern Web browser. This implies that session data is shared between views. This is convenient behavior for users not needing to log in for each view, but is problematic if we really need the session state to be different for every view. Java Server Faces solved this by introducing a View scope. It does not exist in Spring MVC. A custom defined Spring Scope is possible, but a bit hard to implement.
Spring stores the selected language in the session. My website is multilingual. It is possible to use two views e.g. in Chrome to edit blogs with the same content but with different language selected. The result if we depend on the language stored in the session, is that we risk to save a blog in one language and overwrite the blog in the other language. When I first detected the problem I lost my Norwegian text of a blog post. I used the same browser with two edit windows to look at the english text and translate it to Norwegion in the other window. Oops, I did it again. The Norwegian text was overwritten by the English text and vice versa.
The language needs to be stored for every edit view. This can be solved in several ways. One way is including the language in the Url path. But it is clumsy, and it contradicts the Spring way of doing this with a query parameter. What I did was using the old technique of hidden fields in forms. The disadvantage is that the language need to be sent as a parameter for every GET or browser refresh.
The problem of shared session state will appear for all types of data stored in the session, not just the language code. If we do not need to store state on the server, it is not really a problem. Client based web development like React solves this by storing data on the client, but in my web app I try not to use too much JavaScript.
Storing state in the URL path. It seems like a strange idea... What it means is to store some state in path variables, not query parameters since query parameters usually only used for GET. I have used the path to identify which blog and blog post the user is looking at. E.g.
https://techreier/blog/reier/cat/feeding
https://techreier/edit/blog/cat/feeding/published
https://techreier/edit/blog/cat/feeding/draft
https://techreier/blog/cat/feeding (username is skipped for default admin user)
For simplicity a blog post is defined with fixed states (idea, published, draft, backup, ...). This limits the number of instances of the same blogpost, and is done on purpose. Two drafts can not exist, so it is a kind of state. This is a code limitation, not database.
Note: the identifiers must conform with allowed naming rules used for a url segment. The path should uniquely define a database instance, it is easy fetch the instance using the url. If the path does not define a unique database instance, a "duplicate" error message is thrown. The database id I have used is a simple Kotlin Long number (artificial key, the simplest), I do not use path as id in the database directly. SQL selects are used to find the id (unknown to the user) I think it is better to use sequential numbers (synthetic key). that more easily allows for renaming of these identifiers.
Currently, the username is skipped and I use only a default user to create blogs (me). This system makes it very easy to save hyperlinks and return to the same place. The path is always shared with the server, so no problem it is state.
A lang query parameter can be added to adjust language. This is according to conventions for web apps. But it is not state. Spring stores internally language in the session as state.