Spring MVC: flash attribute vs model attribute - spring-mvc

What is the different between flash and model attribute?
I want to store an object and display it in my JSP as well as reuse it in other controller. I have use sessionAttribute and it works fine in the JSP, but the problem is when I try to retrieve that model attribute in other controller.
I lose some data. I searched around and found that flash attribute allows to past past value to different controller, doesn't it?

If we want to pass the attributes via redirect between two controllers, we cannot use request attributes (they will not survive the redirect), and we cannot use Spring's #SessionAttributes (because of the way Spring handles it), only an ordinary HttpSession can be used, which is not very convenient.
Flash attributes provide a way for one request to store attributes intended for use in another. This is most commonly needed when redirecting — for example, the Post/Redirect/Get pattern. Flash attributes are saved temporarily before the redirect (typically in the session) to be made available to the request after the redirect and removed immediately.
Spring MVC has two main abstractions in support of flash attributes. FlashMap is used to hold flash attributes while FlashMapManager is used to store, retrieve, and manage FlashMap instances.
Example
#Controller
#RequestMapping("/foo")
public class FooController {
#RequestMapping(value = "/bar", method = RequestMethod.GET)
public ModelAndView handleGet(Model model) {
String some = (String) model.asMap().get("some");
// do the job
}
#RequestMapping(value = "/bar", method = RequestMethod.POST)
public ModelAndView handlePost(RedirectAttributes redirectAttrs) {
redirectAttrs.addFlashAttribute("some", "thing");
return new ModelAndView().setViewName("redirect:/foo/bar");
}
}
In above example, request comes to handlePost, flashAttributes are added, and retrieved in handleGet method.
More info here and here.

Related

How to assign different controller method to handle two fifferent forms on the same page

I have a a jsp page which contains two forms created using spring.tld.
I would like to assign different Controller method to process each form submit and since both requests are going to be POST I can't do it with just
#RequestMapping(method = RequestMethod.POST)
So I'm looking for another parameter to distinguish between the two requests and looks like it should either be the header or the value.
Could someone please provide a simple implementation example of these two approachs from the view and the controller side?
Thanks
In the RequestMapping you can specify the URL path your method will respond to. For instance,
#RequestMapping( value="/myFirstForm", method=RequestMethod.POST)
public String myFirstFormHandler() {}
#RequestMapping( value="/mySecondForm", method=RequestMethod.POST)
public String mySecondFormHandler() {}
See http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/htmlsingle/spring-framework-reference.html#mvc-ann-requestmapping

HandlerMethod given a HttpRequest?

I have an interceptor in which i want to do some intercepting logic based on the annotation on a controller method (Not on controller class). Say want to restrict the access to that controller method for certain users only. Is there any way to get the Handler method (Yes not the handler class) in the HandlerInterceptor?
I'm afraid not. You would have to group the desired methods in one (or a few) classes and base your check on the class, rather than method.
I guess you can parse the annotations yourself and match the paths, or try to see what spring does to do so in its classes, but that would be more complicated and error-prone.
You can try (but I haven't used it, so I don't know if it works) the #Interceptors annotation on your methods (saw it here)
You can do this in Spring 3.1 now with something like this:
public class ApiSecurityInterceptor implements HandlerInterceptor {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HandlerMethod method = (HandlerMethod) handler;
Api methodAnnotation = method.getMethodAnnotation(Api.class);
if (methodAnnotation != null) {
// this method is an #Api, we check the credentials
// you can do other things with annotation parameters at this point too
}
}
}
Then map it in servlet-config.xml:
<?xml version="1.0" encoding="UTF-8"?>
...
<mvc:interceptors>
<bean class="com.orderpipe.prototype.server.web.interceptors.ApiSecurityInterceptor"/>
</mvc:interceptors>
Then in your actual controller:
#Controller
#RequestMapping(value = "/api-service")
public class AccountApiController {
#Api(type=CredentialType.OAUTH)
#RequestMapping(value="get", method = RequestMethod.GET)
public String get(Model model) {
// secured method via oauth, for example
// in a simpler example, you'd not have the parameter for credential type.
}
}
I use it to implement special servlet paths that implement different security mechanisms to the normal app, for example /api uses oAuth credentials.
I have the same need.
I consider an inconsistency that Spring MVC promotes the use of controller methods to handle requests, but the HandlerInterceptor interface does not supply the handler method that's going to handle the request as a parameter; only the controller object.
Requests are handled at the method level and it's the method execution what you need to intercept and for doing that efficiently you need to gain access to the method meta-information, for example, custom annotations declared at method level or its arguments.
The HandlerInterceptor.preHandle signature shoud be:
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handlerInstance, Method handlerMethod)
throws Exception;
So that you can do something like this:
hadlerMethod.getAnnotation(MyCustomAnnotation.class);
GOT IT?
In my case, I wanted to implement indexed-paremeter mapping; something STRIPES FRAMEWORK has (or flash scoping).
Do I have to resort to AspectJ to implement my cross-cutting functionality? DISSAPOINTING!
Firstly this is against MVC architectural pattern. MVC architecture is an architectural pattern that desires to
isolate "domain logic" (the application logic for the user) from the user interface (input and presentation), permitting independent development, testing and maintenance of each (separation of concerns).
See here
And controller has a great work in it.It desires decoupling, focusing on design porpose, and etc. I hope software developers don't give up GRASP :/

How to configure an endpoint in Spring to accept both form data and XML request body?

I have a small question regarding Spring's MVC data binding capabilities.
I do have the following controller class:
#Controller
#RequestMapping("/foo")
public class FooController() {
// … some init stuff //
#RequestMapping(value = "/{id}/edit.{format}", method = RequestMethod.POST)
public ModelAndView editFoo(#RequestBody FooItem foo, #PathVariable("format") String format) {
// some code here to edit the FooItem //
}
}
I want to be able to post form data as well as XML against this method. For that to work I added two message converters to my applicationContext.xml: The default formHttpMessageConverter and an XStream marshaller.
This works fine, but I have a problem, that if I use #RequestBody and post form data against the URL, the server responds with a 415 Error. If I remove this annotation, form data works well and Spring creates the object for me, but if I post XML against it, I get an empty object.
Is there any way around this or do I need to have 2 methods to be able to handle both of the incoming formats?
Thanks in advance!
I think you need two methods.
FormHttpMessageConverter doesn't have the same databinding capabilities as #ModelAttribute provides, it can't bind request to the specified target class, only to MultiValueMap (see javadoc).

In asp.net mvc is it possible to make a generic controller?

I'm attempting to create a generic controller, ie:
public class MyController<T> : Controller where T : SomeType
{ ... }
However, when I try to use it, I'm running into this error everywhere...
Controller name must end in 'Controller'
So, my question, Is it possible to make a generic controller in asp.net mvc?
Thanks!
If I understand you properly, what you are trying to do, is route all requests for a given Model through a generic controller of type T.
You would like the T to vary based on the Model requested.
You would like /Product/Index to trigger MyController<Product>.Index()
This can be accomplished by writing your own IControllerFactory and implementing the CreateController method like this:
public IController CreateController(RequestContext requestContext, string controllerName)
{
Type controllerType = Type.GetType("MyController")
.MakeGenericType(Type.GetType(controllerName));
return Activator.CreateInstance(controllerType) as IController;
}
Yes you can, it's fine and I've used them lots myself.
What you need to ensure is that when you inherit from MyController you still end the type name with controller:
public class FooController : MyController<Foo>
{
...
}
The default controller factory uses "convention" around controller names when it's trying to find a controller to dispatch the request to. You could override this lookup functionality if you wanted, which could then allow your generic controller to work.
This MSDN article...
http://msdn.microsoft.com/en-us/magazine/dd695917.aspx
... has a good writeup of what's going on.
This is a duplicate of asp.net mvc generic controller which actually contains the correct answer. Jeff Fritz's answer is absolutely not correct. Creating your own IControllerFactory will not get past the limitation in ExpressionHelper.GetRouteValuesFromExpression which is generating the error you are seeing. Implementing your own IControllerFactory will still leave you with errors whenever you call RedirectToAction, BuildUrlFromExpression, ActionLink, RenderAction, BeginForm, any any methods that call those.
What is interesting to me, is that Microsoft's "restriction by convention" is already enforced by the constraint "where TController : Controller" that is placed upon the type in the ExpressionHelper.GetRouteValuesFromExpression method. No generic will ever satisfy the convention validation:
string controllerName = typeof(TController).Name;
if (!controllerName.EndsWith("Controller", StringComparison.OrdinalIgnoreCase)) {
throw new ArgumentException(MvcResources.ExpressionHelper_TargetMustEndInController, "action");
}
unless it is inherited by a class ending in "Controller" because typeof(AnyGeneric).Name will never end with "Controller".
If i was you, i'd get the MVC source and create a test MVC project with the source code so you can examine where the exception is generated and see what you can do about your generic idea and the enforced "*controller" naming convention.

How to implement custom JSON serialization from ASP.NET web service?

What options are there for serialization when returning instances of custom classes from a WebService?
We have some classes with a number of child collection class properties as well as other properties that may or may not be set depending on usage. These objects are returned from an ASP.NET .asmx WebService decorated with the ScriptService attribute, so are serialized via JSON serialization when returned by the various WebMethods.
The problem is that the out of the box serialization returns all public properties, regardless of whether or not they are used, as well as returning class name and other information in a more verbose manner than would be desired if you wanted to limit the amount of traffic.
Currently, for the classes being returned we have added custom javascript converters that handle the JSON serializtion, and added them to the web.config as below:
<system.web.extensions>
<scripting>
<webServices>
<jsonSerialization>
<converters>
<add name="CustomClassConverter" type="Namespace.CustomClassConverter" />
</converters>
</jsonSerialization>
</webServices>
</scripting>
</system.web.extensions>
But this requires a custom converter for each class. Is there any other way to change the out of the box JSON serialization, either through extending the service, creating a custom serializer or the like?
Follow Up
#marxidad:
We are using the DataContractJsonSerializer class in other applications, however I have been unable to figure out how to apply it to these services. Here's an example of how the services are set-up:
[ScriptService]
public class MyService : System.Web.Services.WebService
{
[WebMethod]
public CustomClass GetCustomClassMethod
{
return new customClass();
}
}
The WebMethods are called by javascript and return data serialized in JSON. The only method we have been able to change the serialization is to use the javascript converters as referenced above?
Is there a way to tell the WebService to use a custom DataContractJsonSerializer? Whether it be by web.config configuration, decorating the service with attributes, etc.?
Update
Well, we couldn't find any way to switch the out of the box JavaScriptSerializer except for creating individual JavaScriptConverters as above.
What we did on that end to prevent having to create a separate converter was create a generic JavaScriptConverter. We added an empty interface to the classes we wanted handled and the SupportedTypes which is called on web-service start-up uses reflection to find any types that implement the interface kind of like this:
public override IEnumerable<Type> SupportedTypes
{
get
{
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
AssemblyBuilder dynamicAssemblyCheck = assembly as AssemblyBuilder;
if (dynamicAssemblyCheck == null)
{
foreach (Type type in assembly.GetExportedTypes())
{
if (typeof(ICustomClass).IsAssignableFrom(type))
{
yield return type;
}
}
}
}
}
}
The actual implementation is a bit different so that the type are cached, and we will likely refactor it to use custom attributes rather than an empty interface.
However with this, we ran into a slightly different problem when dealing with custom collections. These typically just extend a generic list, but the custom classes are used instead of the List<> itself because there is generally custom logic, sorting etc. in the collection classes.
The problem is that the Serialize method for a JavaScriptConverter returns a dictionary which is serialized into JSON as name value pairs with the associated type, whereas a list is returned as an array. So the collection classes could not be easily serialized using the converter. The solution for this was to just not include those types in the converter's SupportedTypes and they serialize perfectly as lists.
So, serialization works, but when you try to pass these objects the other way as a parameter for a web service call, the deserialization breaks, because they can't be the input is treated as a list of string/object dictionaries, which can't be converted to a list of whatever custom class the collection contains. The only way we could find to deal with this is to create a generic class that is a list of string/object dictionaries which then converts the list to the appropriate custom collection class, and then changing any web service parameters to use the generic class instead.
I'm sure there are tons of issues and violations of "best practices" here, but it gets the job done for us without creating a ton of custom converter classes.
If you don't use code-generated classes, you can decorate your properties with the ScriptIgnoreAttribute to tell the serializer to ignore certain properties. Xml serialization has a similar attribute.
Of course, you cannot use this approach if you want to return some properties of a class on one service method call and different properties of the same class on a different service method call. If you want to do that, return an anonymous type in the service method.
[WebMethod]
[ScriptMethod]
public object GimmieData()
{
var dalEntity = dal.GimmieEntity(); //However yours works...
return new
{
id = dalEntity.Id,
description = dalEntity.Desc
};
}
The serializer could care less about the type of the object you send to it, since it just turns it into text anyway.
I also believe that you could implement ISerializable on your data entity (as a partial class if you have code-gen'd data entities) to gain fine-grained control over the serialization process, but I haven't tried it.
I know this thread has been quiet for a while, but I thought I'd offer that if you override the SupportedTypes property of JavaScriptConverter in you custom converter, you can add the types that should use the converter. This could go into a config file if necessary. That way you wouldn't need a custom converter for each class.
I tried to create a generic converter but couldn't figure out how to identify it in the web.config. Would love to find out if anyone else has managed it.
I got the idea when trying to solve the above issue and stumbled on Nick Berardi's "Creating a more accurate JSON .NET Serializer" (google it).
Worked for me:)
Thanks to all.
If you're using .NET 3.x (or can), a WCF service is going to be your best bet.
You can selectively control which properties are serialized to the client with the [DataMember] attribute. WCF also allows more fine-grained control over the JSON serialization and deserialization, if you desire it.
This is a good example to get started: http://blogs.msdn.com/kaevans/archive/2007/09/04/using-wcf-json-linq-and-ajax-passing-complex-types-to-wcf-services-with-json-encoding.aspx
You can use the System.Runtime.Serialization.Json.DataContractJsonSerializer class in the System.ServiceModel.Web.dll assembly.
Don't quote me on this working for certain, but I believe this is what you are looking for.
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public XmlDocument GetXmlDocument()
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(_xmlString);
return xmlDoc;
}

Resources