When returning a json, how can you tell using Spring that you want to go to a certain url? - spring

In my code, I am returning a path in String form(/successPassword or /systemError). Basically this tells Spring to go to the path /successPassword or /systemError, /successPassword goes to successPassword.html and /systemError goes to systemError.html. These html files are located in src/main/resources/templates.
#RequestMapping(value = "/user/new_password", method = RequestMethod.POST)
public String createNewPassword(#RequestParam(value = "newpassword", required = false) String password,
#RequestParam(value = "hash") String hash, Model model) {
LOG.info("set new password using hash " + hash);
LOG.info("new password " + password);
boolean hashValid = passwordService.isHashValid(hash);
if (hashValid) {
ValidateMessage message = passwordService.validateNewPassword(password);
if (!message.isError()) {
Account account = passwordService.getAccount(hash);
passwordResetService.saveNewPassword(password, account);
model.addAttribute("account", account);
return "/successPassword";
} else {
LOG.info("Password not complex enough.");
return "/systemError";
}
} else {
LOG.info("Invalid hash.");
return "/systemError";
}
}
Now it looks like I need to return a json object instead. I know that I have to annotate the method with #ResponseBody instead, but my question is how would i package now the object that I will return so that whoever receives it will know to which path it needs to go to? My html codes are using Thymeleaf (no javascript whatsoever).

Related

Modifying SwaggerUI to remove required PathParam

I have a requirement to use optional path parameters. So made it like below;
#ApiOperation(httpMethod = "GET", value = "Get User Details With Optional Path Parameters", notes = "Output depends on values provided")
#ApiResponses(value = {
#ApiResponse(code = 404, message = "We do not unserstand what you mean"),
#ApiResponse(code = 400, message = "You are not requesting like a BOSS.") })
#RequestMapping(value = { "/getuser/userid/{userid}",
"/getuser",
"/getuser/userid/{userid}/alias/{alias}", "getuser/alias/{alias}" }, method = RequestMethod.GET, produces = {
MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE })
#ResponseStatus(HttpStatus.OK)
private UserSchema getUserDetails(
#PathVariable Optional<String> userid,
#PathVariable Optional<String> alias) {
Users user = null;
UserSchema returningSchema = buildDefaultSchema();
if (alias.isPresent()) {
//Get The Value
} else {
//Try Get Other Value and do stuff etc.
}
//Similar for userid
try {
//Get User Data From DB
user = dao.getUserData(userid,alias);
//Bind data to returning schema
} catch (Exception ex) {
Log.error(getClass().getName(), ex);
returningSchema.setResponseText("Something is Wrong");
}
return returningSchema;
}
But with swagger, its not allowing to make a request, as PathVariables are required type. I do not know much javascript. Tried this solution to modify the swagger-ui.js, but seem to get lost in the huge file and cannot find the portion mentioned.
I use the latest Swagger-UI version. Is it possible i can make the request with optional path variables and the correct path should be shown in swagger?
NOTE: I know swagger spec does not allow optional path variables. But i want to change this in my app only.
Thanks.
Yes, you can definitely fork swagger-js and swagger-ui to support this. Take a look at the Operation.prototype.getMissingParams in operation.js.

SpringBoot/MVC & Thymleaf form validation on POST with URL parameters

I have a form and validation works. The problem comes in when a url parameter was added. The url parameter is a token and is required. So this is what my controller looks like:
#RequestMapping(value = "/resetpassword", method = RequestMethod.GET)
public String showResetForm(ResetPassword resetPassword, Model model,
#RequestParam(value = "token", required = true) String token,
#RequestParam(value = "msg", required = false) String msg){
model.addAttribute("token", token);
return "resetpassword";
}
#RequestMapping(value = "/resetpassword", method = RequestMethod.POST)
public String setPwd(#ModelAttribute("resetPassword") #Valid ResetPassword resetPassword,// RedirectAttributes reDirectAttr,
BindingResult bindingResult, Model model,
#RequestParam(value = "token", required = true) String token,
#RequestParam(value = "msg", required = false) String msg){
if (bindingResult.hasErrors()) {
//reDirectAttr.addFlashAttribute("org.springframework.validation.BindingResult.resetPassword",bindingResult);
//reDirectAttr.addFlashAttribute("resetPassword",resetPassword);
return "resetpassword?token="+token;
}
else {
if (token == null) {
// TODO: no token, what to do here??
return "redirect:/resetpassword?token=\"\"&msg=notoken";
}
ResetPasswordResponseDto response = super.resetUserPassword(
resetPassword.getUname(), resetPassword.getPassword(),
token);
if (response.getPasswordResetResult() == PasswordResetResult.SUCCESSFUL) {
// TODO: it worked, what now?
return "redirect:/login";
} else if (response.getPasswordResetResult() == PasswordResetResult.INVALID_TOKEN) {
// TODO: bad token
return "redirect:/resetpassword?token="+token+"&msg=badtoken";
} else if (response.getPasswordResetResult() == PasswordResetResult.OUT_OF_POLICY_PW) {
// TODO: out of policy pw
return "redirect:/resetpassword?token="+token+"&msg=outofpolicy";
} else if (response.getPasswordResetResult() == PasswordResetResult.LDAP_FAILURE) {
// TODO: other failure
return "redirect:/resetpassword?token="+token+"&msg=error";
}
}
return "redirect:/resetpassword?token="+token+"&msg=error";
//return new RedirectView("resetpassword?token=\"\"&msg=notoken");
}
So I tried a bunch of things but nothing seems to work. Here is what I would like to happen when the view is requested /resetpassword?token=1232453 the view is displayed. Then if the form has errors the url parameter persists in the url and the form displays the errors. Right now I get an error saying that the template cannot be resolved. Ok fair enough, so I tried doing a redirect instead
return "redirect:/resetpassword?token="+token;
and that seems to work, however the URL parameter is lost and the view loses the bindingResult errors. In the code, I posted I also tried FlashAttributes but I just get an error "Validation failed for object='resetPassword'. Error count: 4" which is correct but I need it to show the form and the errors I coded with Thymeleaf. Any help or suggestions would be great!
Resources I have looked at:
Spring - Redirect after POST (even with validation errors)
&
SpringMVC controller: how to stay on page if form validation error occurs
Have you tried returning a ModelAndView instead of just the redirect string? Attributes on the model will be available as URL query parameters.
ModelAndView redirect = new ModelAndView("redirect:/resetpassword");
redirect.addObject("token", token);
redirect.addObject("msg", "error");
return redirect;

How do I pass multiple string parameters into WebAPI

I'm trying to write a simple WebAPI controller to validate a userId and password. Both parameters are strings and it's a bit frustrating that this always seems to be so difficult.
The Controller code looks like:
[Route("api/User/{userId}, {password}"), HttpGet]
public bool IsPasswordCorrect(string userId, string password)
{
UserModel sm = new UserModel(userId);
bool rtn = sm.Password == password;
return rtn;
}
The calling code looks like:
public bool IsPasswordValid(string userId, string password)
{
RestRequest request = new RestRequest("IsPasswordCorrect/{userId}, {password}", Method.GET);
request.AddUrlSegment("userId", userId);
request.AddUrlSegment("password", password);
RestClient restClient = new RestClient(Service.Location);
var response = restClient.Execute<bool>(request);
bool rtn = (bool)response.Data;
return true;
}
I am not able to get the calling code to access the controller code. Thanks
You have defined the route as:
GET {host}/api/User/{userId}, {password}
but looks like you are calling it as:
GET {Service.Location}/IsPasswordCorrect/{userId}, {password}
You should call the Web API resource by the route defined in the attribute not by action name as that would result in 404.

Modified data is not saving to database in entity framework database first

I was writing code for changing the passwords but I don't know the reason why the data is not updated to the database. I have built custom membership table and membership Provider class. Here enitiy named IVRControlPanelEntities is generated from entity framework. I have following function to change password.
public bool ChangePassword(string username, string oldPassword, string newPassword)
{
IVRControlPanelMembershipProvider memberservice = new IVRControlPanelMembershipProvider();
if (!memberservice.ValidateUser(username, oldPassword) || string.IsNullOrEmpty(newPassword.Trim()))
{
return false;
}
else
{
using (IVRControlPanelEntities db = new IVRControlPanelEntities())
{
User user = GetUser(username);
// string hash = FormsAuthentication.HashPasswordForStoringInConfigFile(newPassword.Trim(), "md5");
string PasswordSalt = CreateSalt();
user.PasswordSalt = PasswordSalt;
user.Password = CreatePasswordHash(newPassword, PasswordSalt);
db.SaveChanges();
}
return true;
}
}
Problems:
I try changing the password, all is working fine but data for new password is not updated to the table. I have also searched for reason and use following code:
1.
db.Entry(user).State = EntityState.Modified;
2.
db.Users.Attach(user);
db.ApplyCurrentValues("Users", user);
None of above is working and also use TryUpdateModel() function but it's not detecting .
It may be due to state of object is not defined, how can I solve this problem
If method GetUser uses different context, then data will not be updated.
Try this:
User user = db.Users.FirstOrDefault(x=>x.UserName == username);
// string hash = FormsAuthentication.HashPasswordForStoringInConfigFile(newPassword.Trim(), "md5");
string PasswordSalt = CreateSalt();
user.PasswordSalt = PasswordSalt;
user.Password = CreatePasswordHash(newPassword, PasswordSalt);
db.SaveChanges();

ID in Spring-MVC 2.5 edit form using #Controller

I have a problem with the my Controller code. GET works fine (both empty form + form populated from db), POST works fine only for creating new object, but doesn't work for editing. Part of my #Controller class:
#RequestMapping(value = "/vehicle_save.html", method = RequestMethod.GET)
public String setUpForm(#RequestParam(value="id", required = false) Long id, ModelMap model) {
Vehicle v;
if (id == null) {
v = new Vehicle();
} else {
v = vehicleManager.findVehicle(id);
}
model.addAttribute("vehicle", v);
return "vehicle_save";
}
#RequestMapping(value = "/vehicle_save.html", method = RequestMethod.POST)
public String save(#ModelAttribute("vehicle") Vehicle vehicle, BindingResult result, SessionStatus status) {
vehicleValidator.validate(vehicle, result);
if (result.hasErrors()) {
return "vehicle_save";
}
if(vehicle.getId() == null) {
vehicleManager.createVehicle(vehicle);
} else {
vehicleManager.updateVehicle(vehicle);
}
status.setComplete();
return "redirect:vehicle_list.html";
}
The first method creates a vehicle object (including its ID). But the second method gets the same object without the ID field (set to null).
What could I do: manually set vehicle.setID(id from parameters) and then save it to database. This causes JPAOptimisticLockException + I don't like that solution.
Is there a way to pass my Vehicle object with ID to the second method? BTW, I would like to avoid adding hidden ID field to the JSP.
the example you suggested is using session to store the value. the #SessionAttribute is to bind an existing model object to the session. Look at the source code the class is annotated with #SessionAttributes("pet").Which means your model attribute named "pet" is getting stored in session.Also look at the code in processSubmit method of EditPetForm class
#RequestMapping(method = { RequestMethod.PUT, RequestMethod.POST })
public String processSubmit(#ModelAttribute("pet") Pet pet, BindingResult result, SessionStatus status) {
new PetValidator().validate(pet, result);
if (result.hasErrors()) {
return "pets/form";
}
else {
this.clinic.storePet(pet);
status.setComplete(); //look at its documentation
return "redirect:/owners/" + pet.getOwner().getId();
}
}
I havnt used something like this before.But i guess putting ur id in session is the way
BTW, I would like to avoid adding hidden ID field to the JSP.
This is common solution. What's wrong with it ? You should create hidden input with id.
May be you can try using session, cause you cant store info between two request. But that will be uglier i guess.
Btw, Can you please explain a little why you want to avoid adding hidden fields? I'm little curious

Resources