In my MVC controller I have a handler method with a signature:
public void myAction(ActionRequest request, ActionResponse response, Model model) {...}
And in this method I check if some submitted data is okay. If it's not valid, I want to set an error. Currently I do it this simple way:
model.addAttribute("operationStatus", "error");
model.addAttribute("operationMessage", "a lot of things went wrong");
and in the view JSP:
<c:if test="${requestScope.operationStatus == 'error'}">
<div class="msg-error">${requestScope.operationMessage}</div>
</c:if>
Surely there has to be a better way to handle errors in Spring Portlet MVC. Note that I need to display the error messages in different places, not only in <form> tag.
So how should I handle errors?
If you're targeting just Liferay, then you can use the SessionErrors class so you can do the following:
SessionErrors.add(actionRequest, "some-error");
Then on your JSP you have:
<%# taglib uri="http://liferay.com/tld/ui" prefix="liferay-ui" %>
<liferay-ui:error key="some-error" message="Your error message goes here!" />
You can also use do this with exceptions. Check out my answer here.
Related
I am creating a multipage forms application. I'd like to use Validator interface to validate the content provided by the user.
The question: Is this https://mkyong.com/spring-mvc/spring-mvc-handling-multipage-forms-with-abstractwizardformcontroller/ approach still valid in terms of Spring MVC 5.2.*?
Ofc, we should forget about AbstractWizardFormController for a moment.
And answering on my own question:
You do not have to do it. Normally validator will catch errors before the page was switched. Basically, one needs to implement validator as told here https://docs.spring.io/spring/docs/5.2.6.RELEASE/spring-framework-reference/core.html#validator. Then bind it to the controller with
#InitBinder
public void initBinder(WebDataBinder binder) {
binder.setValidator(<validaotrs_variable_name>);
}
And then use #Validated on #ModelAttribute("myobjectnameintemplate") MyPojo myPojo.
That is it.
If the one wants to validate page at a time, then I think it is necessary to run validation methods separately. For this I found a number of answers on stackoverflow:
One can use #Valid and validation groups (Hibernate)
Simple switch case in validate() based on the current page or something else
Nested objects in one object that is being populated, and multiple validators as described here https://docs.spring.io/spring/docs/5.2.6.RELEASE/spring-framework-reference/core.html#validator
Business validations are implemented by throwing CustomeException(key) such that user will be displayed error messages when something goes wrong.
I have to forward to input jsp (like struts) when business exception raised, to correct the user actions then continue with application.
we have custom HandlerExceptionResolverImpl to handle the all exceptions at once place. when exception raised then we don't know the input page.
How to do this in spring4 like struts ?
Please suggest the way how to accomplish this?
Thanks
Dhorrairaajj
base requirement is explained in this
I have solved this, all controllers should extends CustomeWebReq Class, which has getter method to get the input page like String getInputPage(String path). Controllers are responsible to return the input page based on the servlet path argument. getInputPage(string path) method will be invoked from HandlerExceptionMapping where exceptions are handling.
Thanks
Dhorrairaajj
I am using tiles, Spring MVC, Spring form tag. I want to make a form that step by step. When click a button, show more inputs from another tiles definition. But throw a exception can not find "Neither BindingResult nor plain target object for bean name " , It looks the "more inputs" can not get bindle object from previous request, is it right?
Source code:
<form:form action="/saveTicker.do" commandName="ticker" modelAttribute="ticker" method="post">
...
<form:input path="name" id="name"/>
Confirm
<div class="row" id="filelist">
</div>
</form>
js
var confirmTicker=function(){
var ticker=$('input:text').val();
$.get("/confirmTicker.do",{ticker:ticker}).success(function(data){
$('#filelist').html(data);
});
}
want to import another file
<table class="table ">
<c:forEach var="f" items="${fileList}">
<tr>
<td>
<form:checkbox path="files" value="${f}"></form:checkbox>
</td>
</tr>
</c:forEach>
</table>
The error is
Neither BindingResult nor plain target object for bean name 'files' available as request attribute
If I am reading this correct, what you want is a "wizard" form where the user is passed from one form to the next as a series of steps. First, I believe Spring Web Flow does this out of the box, but, if like me, you cannot use Spring Web Flow you can do this manually.
First, you need a Form Bean (read Command object) that has all the possible inputs from all the forms.
Next, you will either have one Controller method that accepts your Form Bean and returns the proper step (this is what I did), or you can have multiple methods...it doesn't matter. You will use the #ModelAttribute annotation on the handler method to bind the Form Bean to the view form. Also, #SessionAttributes annotation at the top of the controller to set the Form Bean as a session attribute. Make sure the name of the #ModelAttribute, #SessionAttribute, and the view all correspond to the same attribute name.
Last, create multiple views, each with the same , but each with only the pieces you want to set on the FormBean at that point. You cannot use JSR 303, or at least I don't know how you can, since you can't have validation done between steps. You will have to handle validation at the end on your own.
While doing some hacking on my own site I encountered (after some googling) a common problem.
"A potentially dangerous Request.Form value was detected from the client may it be a XSS attempt or a malicious character
case 1 : A potentially dangerous Request.Form value was detected from the client (Firstname ="<script> alert("x");...").
case 2 : A potentially dangerous Request.Form value was detected from the client (*)."
The asp mvc team did a good job catching the error for me but how do I show a nicer error to my users. for example "Something happened, please repeat your steps, if this messegage appears again please contact person x ...".
Solution for asp MVC developers.
Create an ErrorController with a Index
Add the following line to your web.config :
<customErrors mode="On" defaultRedirect="~/Error/Index"/>
Write tests to check the controller operations.
Don't forget to create the actual view.
Optional you might want to put mode="RemoteOnly"
Note for more information on CustomErrors attributes : customErrors Element
It's not MVC-specific. ASP.Net webforms will give you the same error.
I think you should use Custom Error Pages. Custom error pages are defined in Web.config like:
<customErrors mode="RemoteOnly" defaultRedirect="~/Error.aspx"/>
For more information about custom error pages, visit http://aspnetresources.com/articles/CustomErrorPages
Also, you can handle Global.asax Application_Error event to do whatever you want.
Microsoft has a very nice article including source code which does exactly what you want to do (and more). check it out at http://support.microsoft.com/kb/306355
Here is another way that is MVC specific:
Create a custom FilterAttribute that implements IExceptionFilter
from inside the FilterAttribute, you can redirect to the controller or view to be used to display the error.
register the filter in the Global.asax or attribute your controllers
This has the advantage that you can show a different error page only for HttpRequestValidationException.
public class HttpRequestValidationExceptionAttribute : FilterAttribute, IExceptionFilter {
public void OnException(ExceptionContext filterContext) {
if (!filterContext.ExceptionHandled && filterContext.Exception is HttpRequestValidationException) {
filterContext.Result = new RedirectResult("~/HttpError/HttpRequestValidationError");
filterContext.ExceptionHandled = true;
}
}
}
When submitting a form I get the message:
com.xxx.mvc.reports.ReportController: Data binding errors: 6 {||||||| - |}
The command class inherits from an abstract base class.
When using debugging I can see that the values are set on the command class. I use spring 2.5. Somehwere after the fields are set and between the calling of onSubmit in the controller the error occurs. I use a SimpelFormController. The onSubmit method isn't called so I can't inspect the BindException there.
What does this mean and how can I troubleshoot this?
I barely posted the question and I found the answer:
<form:errors path="pathName"/>
gives me the errors.
If you want to easily see every binding error related to your command bean in the page, put something like:
<spring:bind path="command.*">
<c:forEach items="${status.errorMessages}" var="error">
<font color="red">Error code: <c:out value="${error}"/></font>
<br><br>
</c:forEach>
</spring:bind>
The code is for a bean named "command", as default.