Spring boot endpoint can not redirect to my view - spring-boot

I have an endpoint:
#GetMapping(value = "/reset-password")
public String displayResetPasswordPage(
It was taking only String token object but then i tried lots of things and last version is:
GetMapping(value = "/reset-password")
public String displayResetPasswordPage(HttpServletRequest request, #RequestParam("token") String token, Model model) {
//here token validate jobs, it is for brevity
Token resetToken = validateToken(token);
ModelAndView modelAndView = prepareModelAndView(currentUser, PASSWORD_RESET);
// modelAndView.addObject("success", request.getParameter("success"));
if (resetToken == null){
modelAndView.addObject("error", "Could not find password reset token.");
model.addAttribute("message","Could not find password reset token." );
} else if (resetToken.isExpired()){
modelAndView.addObject("error", "Token has expired, please request a new password reset.");
model.addAttribute("message","Could not find password reset token." );
} else {
modelAndView.addObject("token", resetToken.getToken());//ihtiyaç var mı emin değilim
model.addAttribute("message","Could not find password reset token." );
}
return "redirect:/Reset-Password.html";
}
What i want is, it should go to simple html of that:
<!DOCTYPE html>
<html layout:decorator="layouts/Master" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
xmlns:th="http://www.thymeleaf.org">
<head>
<title>Bilgilerim</title>
</head>
<body>
fsfasasd
asdsasda
</body>
</html>
its name is Reset-Password.html
It is inside resources-teplates-Reset-Password.html
I also added this
.antMatchers("/reset-password**").permitAll()
For example here , this code goes and shows string on page:
redirect:/Reset-Password.html
when i try to go to
myurl/reset-password?token=122b4e43-0b63-4a6b-8669-f4e6c623ee2d
But instead, when i do
httpServletResponse.sendRedirect("https://twitter.com");
in that method, it goes.
But for
httpServletResponse.sendRedirect("/reset-password");
with void return, it redirects to /reset-password path and
gives error of custom /error page.
What can i do?
Also , when i try to do like this
modelAndView = prepareModelAndView(controllerParams.currentUser, "simplepage");
//todo send only user object
modelAndView.addObject("mobileNumber", mobile);
return modelAndView;
it goes to that view. normally it is another endpoint and view but i copied from there and this can also go that view.
For same approach, i got
template might not exist or might not be accessible by any of the configured Template Resolvers
but Reset-Password and simplepage are in same folder, under templates

Related

How to process TXT e-mail template with Thymeleaf?

I'm trying to send plain text email from Spring application with Thymeleaf.
This is my e-mail service:
#Override
public void sendPasswordToken(Token token) throws ServiceException {
Assert.notNull(token);
try {
Locale locale = Locale.getDefault();
final Context ctx = new Context(locale);
ctx.setVariable("url", url(token));
// Prepare message using a Spring helper
final MimeMessage mimeMessage = mailSender.createMimeMessage();
final MimeMessageHelper message = new MimeMessageHelper(
mimeMessage, false, SpringMailConfig.EMAIL_TEMPLATE_ENCODING
);
message.setSubject("Token");
message.setTo(token.getUser().getUsername());
final String content = this.textTemplateEngine.process("text/token", ctx);
message.setText(content, false);
mailSender.send(mimeMessage);
} catch (Exception e) {
throw new ServiceException("Token has not been sent", e);
}
}
email is sent and delivered into mailbox.
This is my plain text email template:
Token url: ${url}
but in delivered mailbox url variable is not replaced with it's value. Why?
When I use html classic HTML Thymeleaf syntax, variable is replaced:
<span th:text="${url}"></span>
What is proper syntax for e-mail text template?
You can use Thymeleaf in plain text mode as well, like in this example:
Dear [(${customer.name})],
This is the list of our products:
[# th:each="p : ${products}"]
- [(${p.name})]. Price: [(${#numbers.formatdecimal(p.price,1,2)})] EUR/kg
[/]
Thanks,
The Thymeleaf Shop
That means you can have a text-file with just this in it:
Token url: [(${url})]
Take a look at the complete documentation of those features here:
https://github.com/thymeleaf/thymeleaf/issues/395
Edit
As mentioned in a comment, make sure to use version >= 3.0 of Thymeleaf:
<properties>
<thymeleaf.version>3.0.3.RELEASE</thymeleaf.version>
<thymeleaf-layout-dialect.version>2.1.2</thymeleaf-layout-dialect.version>
</properties>
Use an HTML template like this and it will procude plain text.
<html xmlns:th="http://www.thymeleaf.org" th:inline="text" th:remove="tag">
Token url: [[${url}]]
</html>
another way, still using html could be like this
<span th:text="Token url:" th:remove="tag"></span><span th:text="${url}" th:remove="tag"></span>
What you are looking is to produce plain text so thymeleaf will return that for you.

Spring security alert user before logout

here I have a change password page. And I will log the user out once the password has been changed successfully but I have to inform user that the password has been changed successfully before I log him/her out. How should I do the trick? Below is my code:
#RequestMapping(value = "/changepassword", method = RequestMethod.POST)
public String change(Model model, String oldPassword, String newPassword, Principal principal) throws NoSuchAlgorithmException {
//Some method
return "redirect:/somename/j_spring_security_logout";
}
}
I guess it is a simple trick but I just can't figure it out..
I see 2 options:
1.Just make an ajax call to change the password. And then redirect on client side instead of server side. For example (mnemo code in javascript)
ajaxCall.success = {
showMessage("Your session will be terminated. Please login again.")
//wait for 3 seconds and then redirect
setTimeout(function(){ window.location = "/somename/j_spring_security_logout" }, 3000);
}
2.Keep the code as is, just add a request parameter on redirect:
return "redirect:/somename/j_spring_security_logout?notify_about_password=true";
On your logout page add some extra-logic to handle this request parameter.

how to prevent confirm alert In Spring MVC on F5

In Spring I usually did a redirect-after-submit(get method mapping) to prevent the user of submitting a form ,
but when i pressing F5 it will go to get method mapping again and display me this kind of confirm message. how could i prevent this message every time on F5.
Here is the code for controller -
ScheduleDetail objScheduleDetail = new ScheduleDetail();
HttpSession session = request.getSession(true);
String condition = "";
try{
int careProfessionalIDF = (Integer) session.getAttribute("careProfessionalIDF");
condition = "CareProfessionalIDF = "+careProfessionalIDF;
objScheduleDetail.setCareProfessionalIDF(careProfessionalIDF);
}catch (Exception e) {
int careProviderIDF = (Integer) session.getAttribute("careProviderIDF");
condition = "CareProviderIDF = "+careProviderIDF;
objScheduleDetail.setCareProviderIDF(careProviderIDF);
}
List<ScheduleDetail> ScheduleDetailList = objScheduleDetailManager.getAllScheduleDetail(condition+" ORDER BY ScheduleDetailIDP DESC");
model.addObject("List_of_ScheduleDetail",ScheduleDetailList);
model.addAttribute("ScheduleDetail", objScheduleDetail);
return "hospital/scheduleDetail";//jsp page
edited code
#RequestMapping("/editAddressType.html")
public String editAddressType(ModelMap model,HttpServletRequest request)
{
int addressTypeIDP = Integer.parseInt(request.getParameter("AddressTypeIDP"));
AddressType objAddressType = new AddressType();
objAddressType = objAddressTypeManager.getByID(addressTypeIDP);
model.addAttribute("AddressType", objAddressType);
return "jsp/addressType";
it open addressType.jsp with data tht we bind with `model.addAttribute`. now if i press F5 it show alert message as above image.
**get method**
#RequestMapping(value="/getAddressType.html", method=RequestMethod.GET)
public String getAddressType(ModelMap model, HttpServletRequest request) throws RemoteException
{
AddressType objAddressType = new AddressType();
model.addAttribute("AddressType", objAddressType);
return "hospital/addressType";
}
If you implement the POST - REDIRECT - GET pattern correctly, you will not see the warning from the browser that you mentioned. The warning is shown when the Page being viewed is in response to a POST request. The traditional pattern, FORM - POST - SUCCESS page.
The code you provided in the question is not enough to reach the root cause of the problem. I'm listing key points of the implementation here, please compare with your code and you'll understand what the mistake is.
To show the user the form, where they are supposed to enter data for submission. (Just the starting point, could be any page in your application.)
#RequestMapping(value = "/checkout/{cartId}.htm", method = RequestMethod.GET)
public ModelAndView showCheckoutForm(...) {
......
return new ModelAndView("/WEB-INF/jsp/form.jsp")
}
The form POSTs to a handler method, which issues a redirect to the user, pointing to a URL that will show the details of the resource created as a result of the POST.
#RequestMapping(value = "/checkout/{cartId}.htm", method = RequestMethod.POST)
public View submitCheckoutForm(....) {
return new RedirectView("/checkout/confirmation/" + cartId + ".htm");
}
The details of the created resource will be shown by a handler method like the following. Note that at this point, if your implementation worked properly, the URL in the user's browser will change to the path redirected by the POST handler. And a fresh GET request will be issued to the server.
#RequestMapping(value = "/checkout/confirmation/{cartId}.htm", method = RequestMethod.GET)
public ModelAndView showCheckoutConfirmation(....) {
return new ModelAndView("viewThatShowsCheckoutConfirmation");
}
If your implementation is similar, the confirmation page is a result of a GET request, so browsers won't issue a warning for re-POSTing data if you refresh the page.
My suspicion is that your POST handler is not issuing a redirect to the user, it is instead rendering the confirmation page itself.
Hope this helps. Please let me know if this does not solve your problem.

Losing Google Analytics tracking due to Spring Security login redirect

I have a mailing campaign where all links include google analytics tracking code such as:
http://example.com/account/somePage.html?utm_source=example&utm_medium=email&utm_campaign=reminder
The context /account/** is protected via Spring security and once the user clicks on the link on the email, he is re-directed to login BEFORE actually seeing somePage.html. This way the first page that is displayed is something like /login.do which does not have the analytics tracking code. Therefore google does not track my source, medium and campaign parameters.
Any ideas how to solve?
Based on http://support.google.com/analytics/answer/1009614?hl=en , I updated my LoginController that shows the login page to redirect to /login?GOOGLE_PARAMATERS:
private static final String ALREADY_REDIRECTED = "ALREADY_REDIRECTED";
....
#RequestMapping(value = "/login", method = RequestMethod.GET)
public ModelAndView loginView(HttpServletRequest request, HttpServletResponse response){
....
Boolean alreadyRedirected = (Boolean) request.getSession().getAttribute(ALREADY_REDIRECTED);
if (alreadyRedirected==null){
SavedRequest savedRequest = new HttpSessionRequestCache().getRequest(request, response);
if (savedRequest!=null){
String source[] = savedRequest.getParameterValues("utm_source");
if (source!=null && source.length>0){
// we need to redirect with login instead
String mediums[] = savedRequest.getParameterValues("utm_medium");
String medium = mediums.length==0 ? "" : mediums[0];
String campaigns[] = savedRequest.getParameterValues("utm_campaign");
String campaign = campaigns.length==0 ? "" : campaigns[0];
String redirect = "redirect:/login?utm_source=" + source[0] + "&utm_medium=" + medium + "&utm_campaign=" + campaign;
mav.setViewName(redirect);
// mark not to do twice
request.getSession().setAttribute(ALREADY_REDIRECTED, new Boolean(true));
return mav;
}
}
}
We have similar problem and have solved with the next solution.
We have a signup form via Ajax, and in the callback if everything is OK we auto-login the user and lost Google Analytics tracking code for Funnel visualization because of Spring Security session invalidation and set up a new cookie.
What we have done by JS just before auto-login call the new user this
_gaq.push(['_trackPageview', '/signupDone']);
https://gist.github.com/moskinson/5418938
signupDone is a fake url that does not exists.
This way GA receive a call of a new url is loaded and we can track the funnel!
http://packageprogrammer.wordpress.com/2013/04/19/seguimiento-con-google-analytics-a-traves-del-login-con-spring-security/

JSP: RequestDispatcher.forward() not forwarding when servlet called via Ajax POST

I have a login form (login.jsp) with two input fields, username and password.
I am using POST via Ajax to access the login servlet.
I want the user to login, and if the login is successful, be redirected to another page called 'search.jsp'. If unsuccessful, a 'login failed' message is returned as the Ajax responseText to be inserted into a paragraph in the 'login.jsp' page.
I have everything working, my login servlet accesses the database via a separate bean, and an object of that bean is returned with its properties ready to use. So all is good to there.
But, after the username and password pass muster with the database, I'm then using RequestDispatcher to forward to the new landing page (search.jsp).
Here is my doPost()
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username,password;
username = request.getParameter("p");
password = request.getParameter("q");
try {
LoginService ls = new LoginService(username,password);
User user = ls.getUserDetails();
if(user.getUsername()!=null && user.getPassword()!=null){
FormService filler = new FormService();
Form fields = filler.getFields();
request.setAttribute("user",user);
request.setAttribute("fields1",fields);
request.setAttribute("fields2",fields);
request.setAttribute("fields3",fields);
HttpSession session = request.getSession(true);
//set attribute for the session
session.setAttribute("user",user.getUsername());
//Now, the RequestDispatcher.forward() is not forwarding to the new page!
//The whole 'search.jsp' page is being stuffed back into the 'login.jsp' page
RequestDispatcher rd = request.getRequestDispatcher("search.jsp");
rd.forward(request,response);
return;
}
else{
PrintWriter out = response.getWriter();
out.println("login failed!");
return;
}
} catch (Exception e) {
e.printStackTrace();
}
}
But instead of forwarding the request and response to the new jsp page 'search.jsp', the whole search.jsp page is being stuffed back into the the original login.jsp page - in the html element which holds the Ajax responseText in when login fails.
The forward() method in the servlet works when the servlet is called from the form action attribute, but not when the servlet is called the javascript file containing the Ajax code.
But instead of forwarding the request and response to the new jsp page 'search.jsp', the whole search.jsp page is being stuffed back into the the original login.jsp page - in the html element which holds the Ajax responseText in when login fails.
That's indeed the expected behaviour. You're handling the request/response using JavaScript. Your JavaScript code has retrieved the response of search.jsp as responseText and is putting it in the HTML element.
You need to change this approach. You need to let the response return the necessary data which sufficiently informs JavaScript so that it can handle the response properly. A commonly used data format for this is JSON.
Something like
response.setContentType("application/json");
if (user != null) {
// ...
response.getWriter().write("{ 'success': true, 'location': 'search.jsp' }");
} else {
response.getWriter().write("{ 'success': false, 'message': 'Unknown login' }");
}
and in JS:
var responseJson = eval('(' + xhr.responseText + ')');
if (responseJson.success) {
window.location = responseJson.location;
} else {
document.getElementById('message').innerHTML = responseJson.message;
}
If you want to handle this unobtrusively, so that the same servlet is reuseable on normal (non-ajax) HTTP requests (so that your webapp still works when the client has JS disabled!) then you could check if the X-Requested-With header equals to XmlHTTPRequest.
if ("XMLHttpRequest".equals(request.getHeader("X-Requested-With")) {
// Handle ajax response (e.g. return JSON data object).
} else {
// Handle normal response (e.g. forward and/or set message as attribute).
}
See also:
How to use Servlets and Ajax?
Simple calculator with JSP/Servlet and Ajax

Resources