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
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.
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;
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.
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();
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