I'm writing an application with Spring framework and I have a question how to do a form validation with extra fields.
I'm new to this but as far as I understand to fill the form with form:form tag I set attribute with
#RequestMapping(value = "/register", method = RequestMethod.GET)
public String register(Model model) {
model.addAttribute("tenant", new Tenant());
return "register";
}
Then create validator class and use it on POST request:
#RequestMapping(value = "/register", method = RequestMethod.POST)
public String registerPost(#ModelAttribute("tenant") Tenant tenant,
Model model,
BindingResult result) {
TenantValidator validator = new TenantValidator();
validator.validate(tenant, result);
if (result.hasErrors()) {
return "register";
}
tenantService.save(tenant);
return "redirect:accountOverview";
}
It works very well and I'm fascinated by how convenient this is!
The only problem is what do I do with extra fields?
For example I have "repeat password" field.
If I create extra fields without using tags and by using and validate them directly I would not be able to use:
<form:errors path="repeatPassword>
tag as 'repeatPassword' is not a member of form object.
The first solution that comes to mind is to create special form object TenantDTO that would hold those extra fields and on save just transfer the data to 'Tenant' (entity bean).
Is this a good approach? What are the best practices in this situation?
Thanks!
Leonty
You can still have these values in the form object. I guess you don't want to save these to the database. You can avoid that by using the annotation Transient (http://docs.oracle.com/javaee/5/api/javax/persistence/Transient.html). This will give a leverage for you to do the path mapping, having in the form object and do all the validation but still dont save in the database. hope it helps.
Related
I'm new to ASP.Net MVC. In PHP, I always use the PRG pattern even when the post request was invalid. It was pretty easy with session flashes (also user friendly).
In ASP.Net MVC, however, I don't see an easy way to do PRG when the request is invalid. I could think of some ways, but I don't think they are good practices and put some extra unnecessary work.
Moreover, from a couple of articles that I've read, a PRG when the request was invalid was discouraged. If it's a bad practice, then what's the better way to handle unsuccessful post requests? Is it really better off without the PRG? And should I just let the rather annoying browser warnings when a user tries to refresh the page?
In Mvc, it's normal practice to handle your Post Actions as it follows:
[HttpPost]
[ValidateAntiForgeryToken]
public virtual ActionResult LoginForm(LoginViewModel loginViewModel)
{
if (!ModelState.IsValid)
return View("Login", loginViewModel);
return Redirect("/");
}
As you can see, the property ModelState.IsValid will tell you if the request is invalid, therefore giving you the ability to return the same view and display the error messages in the ValidationSummary when the Post request contains an error. This is the code for the View:
#using (Html.BeginForm("LoginForm", "Account"}))
{
#Html.ValidationSummary() // THIS WILL SHOW THE ERROR MESSAGES
#Html.AntiForgeryToken()
#Html.TextBoxFor(x => x.Email)
#Html.PasswordFor(x => x.Password)
<button type="submit">Submit</button>
}
We have been using PRG pattern in our asp.net mvc web apps for about 5 years. The main reason we adopted PRG was to support browser navigation (eg back, forward). Our web apps are used by customer and for front/back office operations. Our typical web page flow is starts with a login, then progresses via many list/detail view. We also incorporate partial views which also have their own viewmodel. List views will have links (GETS) for navigation. Detail views will have forms (POSTS) for navigation.
Keys aspects of our PRG:
We incorporate viewmodels so each view has a viewmodel (all data access is done in the viewmodel).
Each viewmodel has a set() & get() method to maintain the key data field values associated with the most recent instance of the view. The set/get values are persisted in sessionstate.
The set method has a parameter for each value that needs to be set. The get method is just called from the viewmodel constructor to populate the viewmodel's public "key" values.
The viewmodel will also have a public load() method that get all neccessary data for its view.
Our PRG pattern overview:
In controllers we have a separate GET method and a POST method for each action. The GET only displays a view; the POST processes the posted data.
For list (menu) views, the controller GET method calls the target view's set('item key values here') method, then invokes a RedirectToAction to to the target view's controller GET action.
The controller GET method will instantiate the viewmodel (thus causing get of set values), call its load method which uses the set/get key values to get it data, and returns the view/viewmodel.
The controller POST method will either have the viewmodel save the valid posted data then redirect to the next desired page (probably the previous list menu) -OR- if redisplay the current view if the data is invalid.
I have not documented all the PRG flow senarios that we implemented, but the above is the basic flow.
SAMPLE VIEWMODEL SET/GET METHODS
private void GetKeys() {
Hashtable viewModelKeys;
if (SdsuSessionState.Exists("RosterDetail"))
{
viewModelKeys = (Hashtable)SdsuSessionState.Get("RosterDetail");
EventId = (int)viewModelKeys["EventId"];
SessionNo = (int)viewModelKeys["SessionNo"];
viewModelKeys = null;
}
}
public static void SetKeys(int eventId, int sessionNo) {
Hashtable viewModelKeys = new Hashtable();
viewModelKeys.Add("EventId",eventId);
viewModelKeys.Add("SessionNo",sessionNo);
SdsuSessionState.Set("RosterDetail",viewModelKeys);
viewModelKeys = null;
}
SAMPLE CONTROLLER
[AcceptVerbs("Get")]
public ActionResult MenuLink(int eventId, int sessionNo, string submitButton) {
if (submitButton == RosterMenu.Button.PrintPreview) {
// P-R-G: set called viewmodel keys.
RosterDetail.SetKeys(eventId,sessionNo);
// Display page.
return RedirectToAction("Detail","Roster");
}
if (submitButton == RosterMenu.Button.Export) { etc ...}
}
I have some questions from a design point of view in Spring Web MVC.
Is it good practice to use Request Object in controller? If not, then what is alternative way to pass pass one text fields value to controller? Do I need to create one new from bean for this single fields?
It depends of the situation, in a few cases I used the HttpServletRequest; for example for writing a file to the output stream.
If you want to get the Request Parameters you can use the annotation #RequestParam, that it´s more easy to get the parameters from the request.
Depends that you want to handle, for example for a form you can use #ModelAttribute and this attribute can be in a session or in the request.
For example:
#Controller
public class YourController {
#RequestMapping(value = "someUrl", method = RequestMethod.GET)
public String someMethod(#RequestParam("someProperty") String myProperty)
{
// ... do some stuff
}
}
Check the documentation here:
#RequestParam
#ModelAttribute
#PathVariable
I use Spring MVC and need to provide ability to change fields of some object separately. For example in controller I have method for every field (new value is assigned in service method) but I'm wondering if there is good design pattern to use in this situation. I mean to have in controller only one method for all fields. I thought about sending new value of field and name and then check which field should be changed in controller but in this situation I get many if statements... Is there any widely used method in this situation?
class Controller {
#RequestMapping(value = "/field", method = RequestMethod.POST)
public String changeFieldValue(#RequestParam("fieldname") String fieldName, #RequestParam("newValue") String newValue, ModelMap model){
if(fieldname.equals("age")){
Object.setAge(newValue);
}
.
.
.
}
}
I think about sth similar to this, I know that I can populate whole object at once. but requirements are to change fields separately
Spring has a BeanWrapper implementation to ease this task.
http://static.springsource.org/spring/docs/3.2.x/javadoc-api/org/springframework/beans/BeanWrapperImpl.html
BeanWrapper wrapper = new BeanWrapperImpl(object);
wrapper.setPropertyValue(fieldName, newValue);
I'm just taking a look at ASP.Net MVC3 and in one of the auto-generated views for Create, it uses "Html.EditorFor(model => model.User)" to provide a text box for the user to enter their username. Ideally, I would auto-populate this with #User.Identity.Name.
What is the correct way to achieve this? Does Html.EditorFor allow me to automatically populate it in the view, or should I be setting that at the controller when passing it in?
I've found that if I change the Create method in the controller from this:
public ActionResult Create()
{
return View();
}
To this:
public ActionResult Create()
{
MyObject myobject = new MyObject();
myobject.User = User.Identity.Name;
return View(myobject);
}
This seems to work. Is this the correct way to do this?
Thanks in advance for any confirmation that I'm doing this right.
Absolutely, the assignment is fine.
This is absolutely the correct way. You define a view model (MyObject) containing the User string property, then have your controller action instantiate and populate this model and finally pass the view model to the view for displaying. It is also easy to unit test because the User.Identity property on the controller is an abstraction that could be mocked.
its a good way in this case, but if you bild a big project it's better to create a global model class where you will put all your models, not in controller.
I'm using linq to SQL and MVC2 with data annotations and I'm having some problems on validation of some types.
For example:
[DisplayName("Geplande sessies")]
[PositiefGeheelGetal(ErrorMessage = "Ongeldige ingave. Positief geheel getal verwacht")]
public string Proj_GeplandeSessies { get; set; }
This is an integer, and I'm validating to get a positive number from the form.
public class PositiefGeheelGetalAttribute : RegularExpressionAttribute {
public PositiefGeheelGetalAttribute() : base(#"\d{1,7}") { }
}
Now the problem is that when I write text in the input, I don't get to see THIS error, but I get the errormessage from the modelbinder saying "The value 'Tomorrow' is not valid for Geplande sessies."
The code in the controller:
[HttpPost]
public ActionResult Create(Projecten p)
{
if (ModelState.IsValid)
{
_db.Projectens.InsertOnSubmit(p);
_db.SubmitChanges();
return RedirectToAction("Index");
}
else
{
SelectList s = new SelectList(_db.Verbonds, "Verb_ID", "Verb_Naam");
ViewData["Verbonden"] = s;
}
return View();
}
What I want is being able to run the Data Annotations before the Model binder, but that sounds pretty much impossible. What I really want is that my self-written error messages show up on the screen.
I have the same problem with a DateTime, which i want the users to write in the specific form 'dd/MM/yyyy' and i have a regex for that. but again, by the time the data-annotations do their job, all i get is a DateTime Object, and not the original string. So if the input is not a date, the regex does not even run, cos the data annotations just get a null, cos the model binder couldn't make it to a DateTime.
Does anyone have an idea how to make this work?
Two options:
(1) You can make a Projecten viewModel where all fields are strings. This way the viewModel will always be created from the posted data and your dataannotations validation will always be evaluated. Obviously, you would then map the viewModel to your properly typed business objects maybe using AutoMapper.
(2) You can subclass the model binder.