Spring MVC :URI not working - spring

I am using the below URL to send a request,but i am getting a 404 error.
with a warning on server:No mapping found for HTTP request with URI
The URI is
http://localhost:8080/webstore/products/tablet/price;low=200;high=400?manufacturer="Google"
The method in controller used is
#RequestMapping(value="/products/{category}/{ByCriteria}",method=RequestMethod.GET)
public String getSpecificProductByFilter(#PathVariable("category")String ProductCategory,#MatrixVariable(pathVar= "ByCriteria") Map<String,List<Long>> filterParams,#RequestParam String manufacturer,Model model){
model.addAttribute("products",productService.getfilterproducts(ProductCategory,filterParams, manufacturer));
return "products";
}
The category signifies "tablet"in the URI
Criteria signifies"low" and "high"
manufacturer is"google"

For those who dont know, this is from book "Spring MVC begginers guide" by Amuthan G. This question is really old but I will give there my solution just in case somebody going to need that, just like me today.
First of all your #RequestMapping is wrong. It should looks like this:
#RequestMapping(value="/{category}/{ByCriteria}", method=RequestMethod.GET)
And reason for that is you already have #RequestMapping("/products") on this whole controller class (above your class declaration). And because you want to map
webstore/products/tablet and NOT webstore/products/products/tablet you have to leave that "products" mapping from this method.
Second thing is your URI. I know that in the books there is this one and its not really big deal, but if you dont want to have problems, leave quotation marks next to word Google. Its because you dont want to have value "Google" but just Google without these quation marks and if you let them there, you will have problems with comparing values. So your URI should looks like this.
http://localhost:8080/webstore/products/tablet/price;low=200;high=400?manufacturer=Google
For complete solution you have to do following steps:
In your repository and service interfaces and classes write method:
List<Product> getProductsByManufacturer(String manufacturer);
and implement it in same way like you wrote method GetProductsByCategory.
In your repository and service interfaces and classes write method:
Set<Product> getProductsByPrice(Map<String, List<String>> priceParams);
and implement it in same way like you wrote method getProductsByFilter.
Finnaly write method in Controller class:
#RequestMapping("/{category}/{ByPrice}")
public String filterProducts(#PathVariable("category") String productCategory,
#MatrixVariable(pathVar = "ByPrice") Map<String, List<String>> filterParams,
#RequestParam String manufacturer, Model model) {
List<Product> byCategory = productService.getProductsByCategory(productCategory);
List<Product> byManufacturer = productService.getProductsByManufacturer(manufacturer);
Set<Product> byPrice = productService.getProductsByPrice(filterParams);
byCategory.retainAll(byManufacturer);
byCategory.retainAll(byPrice);
model.addAttribute("products", byCategory);
return "products";
}
In my project this method look like this, but you can certainly do it in shorter way. After you complete these steps, your project should working. If not, feel free to ask me there. If you dont know how to write methods in steps 1 and 2 I will comment there code for you, but its almost same like that another methods as I said. I hope that this is going to help somebody.

Related

Swagger documentation for REST response

Good afternoon.
I am trying to generate Swagger documentation but fails to generate clean result if the response is not a simple class.
if we consider a user with family members, the following REST function as a partial documentation
public ResponseEntity<FamilyMembersResponse> getUserFamily(#PathVariable("user_uuid") String UUID) {
...
FamilyMembersResponse response= new FamilyMembersResponse();
...
return new ResponseEntity<>(response, HttpStatus.OK);
}
By partial, I mean that swagger will say that result is of type FamilyMembersResponse (that is correct) but the FamilyMembersResponse class itself is not documented (return without any attributes).
The issue may be that the class FamilyMembersResponse is created within the controler but even with such definitions the class description is always empty:
class FamilyMembersResponse {
#Schema(name = "user" )
User user;
#Schema(name = "family_members" )
List<FamilyMember> family_members;
}
Any idea why? Issue seems "only" on the generation of FamilyMembersResponse "class", not the route
Just found the answer... as in simply posting in SO after looking for hours helped solving the issue (why, that is the question :D).
JsonProperty was expected, .. which kind of makes sense.
#JsonProperty("user")

How to correctly initialize an object that have to contain the data retrieved by 2 methods of my controller in this Spring MVC application?

I am pretty new in Spring MVC and I have the following doubt about how correctly achieve the following task.
I am working on a web application that implement a user registration process. This registration process is divided into some consecutive steps.
For example in the first step the user have to insert a identification code (it is a code that identify uniquely a user on some statal administration systems) and in the second step it have to compile a form for his personal data (name, surname, birth date, and so on).
So, actually I have the following controller class that handle these steps:
#Controller
public class RegistrazioneController {
#Autowired
private LoadPlacesService loadPlacesService;
#RequestMapping(value = "/iscrizioneStep1")
public String iscrizioneStep1(Model model) {
return "iscrizioneStep1";
}
#RequestMapping(value = "/iscrizioneStep2", method=RequestMethod.POST)
public String iscrizioneStep2(Model model, HttpServletRequest request, #RequestParam("cf") String codicFiscale) {
System.out.println("INTO iscrizioneStep2()");
//String codicFiscale = request.getParameter("cf");
System.out.println("CODICE FISCALE: " + codicFiscale);
model.addAttribute("codicFiscale", codicFiscale);
return "iscrizioneStep2";
}
#RequestMapping(value = "/iscrizioneStep3", method=RequestMethod.POST)
public String iscrizioneStep3(#ModelAttribute("SpringWeb")Step2FormCommand step2Form, ModelMap model, HttpServletRequest request) {
System.out.println("INTO iscrizioneStep3()");
System.out.println("NOME: " + step2FormCommand.getName());
return "iscrizioneStep3";
}
Into the iscrizioneStep2() it is retrieved the first code (#RequestParam("cf") String codicFiscale).
Into the iscrizioneStep3() it is retrieved a command object containing the data inserted into the form of the view in which this form was submitted, this one:
#ModelAttribute("SpringWeb")Step2FormCommand step2FormCommand
It works fine.
Now my problem is that I have another object named Step3View that have to be initialized with the aggregation of the #RequestParam("cf") String codicFiscale object retrieved into the iscrizioneStep2() method and the #ModelAttribute("SpringWeb")Step2FormCommand step2FormCommand retrieved into the iscrizioneStep3() method.
This Step3View class simply contain the String codicFiscale and all the fields of the Step2FormCommand class.
Now my doubts are: what is the best way to handle this situation? Where have I to declare this Step3View object? at controller level? (so I can use it in all my controller methods?). Have I to annotate this class with #Component (or something like this) to inject it in my controller?
What is the best solution for this situation?
I think in order to get an answer you need to understand the question and ask the right question. I think your question is "how do I pass a parameter from one page to another page in SpringMVC?". You specifically want to know how to pass the "cf" param, but readers here will tend to pass over questions that are too specific because it takes too much time to figure out what you want.
In answer to that, see Spring MVC - passing variables from one page to anther as a possible help.
Also, there are many good answers about this question for JSP in general, which can be worked into the SpringMVC architecture. See How to pass value from one jsp to another jsp page? as a possible help.

spring 3 not rendering model in jsp

I am a bit disapointed concerning Spring 3 not rendering my model in a jsp using Expression Language and I have to admit that I dont understand why. If anyone could help me understanting why I can't make it work it will be really great.
Here's my context:
My controller have a method (called by ajax from my client) returning a jsp fragment:
#RequestMapping(value = "/datagrid/getGoatCard", method = RequestMethod.POST)
public String getGoatCard(#RequestParam Long id,
#ModelAttribute("goat") Goat goat) {
goat = goatDataService.findGoatById(id);
return "goatCard";
}
I call this method with a requestParam allowing hibernate to retrieve the desired Bean (the model contains all the requiered data, it has been checked).
Then this method retruns a jsp named "goatCard"; here's the jsp code:
<input name="goat.goatName" type="hidden" value="${goat.goatName}"/>
(this isn't the whole page code, cause this won't be easy to read if too many code is presented. My jsp contains JQuery easyui and highcharts javaScript librairies)
I though that the annotation #ModelAttribute("goat") linked the model called "goat" to my jsp allowing to render the model using EL but it doesn't seem so.
Does anybody have any idea, perhaps it just a little thing that I did wrong but I don't see which one!!!!
#ModelAttribute is used for retrieving form model rather than setting to be displayed in JSP.
If you need to display data in JSP, you have to add the data into Model first.
#RequestMapping(value = "/datagrid/getGoatCard", method = RequestMethod.POST)
public ModelAndView getGoatCard(#RequestParam Long id) {
ModelAndView mv = new ModelAndView("goatCard");
Goat goat = goatDataService.findGoatById(id);
mv.addObject("goat",goat);
return mv;
}
And then goat is available in JSP file.
By the way, for retrieving data, better to use RequestMethod.GET.
Thank's a lot for your help. Just an answer to update your code.
As I use Spring 3, it is better to write
#RequestMapping(value = "/datagrid/getGoatCard", method = RequestMethod.POST)
public String getGoatCard(#RequestParam Long id,
Model model) {
model.addAttribute("goat", goatDataService.findGoatById(id));
return "goatCard";
}
It's just to fit more to the preconisation of Spring Foundation (I agree this lead to the same result, but SpringSource recommend the use of String return instead of mav).
Again thanks for your help

Yes or no: Should models in MVC contain application logic?

Yesterday I had some discussion with one of our developers regarding MVC, more precisely about the role of the model component in MVC.
In my opinion, a model should just contain properties and almost no functionality so there are as few methods in model classes as possible.
My collegue though believes that models could and should have more than that and offer a lot more functionality.
Here is an example we argued about.
Example 1
Let's say we wanted to create a blog. A blog has articles and tags. Each article can have multiple tags and each tag can belong to multiple articles. So we have a m:n relation here.
In pseudocode it'd probably look something like this:
class Article{
public int id;
public String title;
public String content;
public Tag[] tags;
// Constructor
public void Article(id, title, content, tags){
this.id = id;
this.title = title;
this.content = content;
this.tags = tags;
}
}
class Tag{
public int id;
public String name;
// Constructor
public Tag(id, name){
this.id = id;
this.name = name;
}
}
Now, assume that we're working loose coupled here which means that it could happen that we have an instance of Article which has no Tags yet so we'll use an Ajax call (to our backend which has a database containing all the information) to get the tags that belong to our article.
Here comes the tricky part. I believe that getting the backend data via Ajax+JSON should be the controller's job using a dedicated class which deals with the ajax request using a parser:
class MyController{
private void whatever(articleID){
Article article = (Article) ContentParser.get(articleID, ContentType.ARTICLE);
doSomethingWith(article);
}
}
public abstract class ContentParser{
public static Object get(int id, ContentType type){
String json = AjaxUtil.getContent(id, type.toString()); // Asks the backend to get the article via JSON
Article article = json2Article(json);
// Just in case
Tag[] tags = article.tags;
if (tags == null || tags.length <= 0){
json = AjaxUtil.getContent(article.id, ContentType.TAGS); // Gets all tags for this article from backend via ajax
tags = json2Tags(json);
article.tags = tags;
}
return article;
}
// Does funky magic and parses the JSON string. Then creates a new instance of Article
public static Article json2Article(String json){
/*
...
*/
return new Article(id, title, content, tags);
}
// Does funky magic and parses the JSON string. Then creates a new instance of Tag
public static Tag[] json2Tags(String json){
/*
...
*/
return tags;
}
}
Example 2
My collegue believes that this breaks with the idea of MVC, he suggests that the model should take care about this:
class Blog{
public int id;
public String title;
public Article[] articles;
// Constructor
public Blog(id, title, articles){
this.id = id;
this.title = title;
this.articles = articles;
}
public void getArticles(){
if (articles == null || articles.length <= 0){
String json = AjaxUtil.getContent(id, ContentType.ARTICLE); // Gets all articles for this blog from backend via ajax
articles = json2Articles(json);
}
return articles;
}
private Article[] json2Articles(String json){
/*
...
*/
return articles;
}
}
class Article{
public int id;
public String title;
public String content;
public Tag[] tags;
// Constructor
public Article(id, title, content, tags){
this.title = title;
this.content = content;
this.tags = tags;
}
public Tag[] getTags(){
if (tags == null || tags.length <= 0){
String json = AjaxUtil.getContent(id, ContentType.TAGS); // Gets all tags for this article from backend via ajax
tags = json2Tags;
}
return tags;
}
// Does funky magic and parses the JSON string. Then creates a new instance of Tag
private Tag[] json2Tags(String json){
/*
...
*/
return tags;
}
}
And outside of the model you'd do: blog.getArticles(); or article.getTags(); to get the tags without bothering with the ajax call.
However, as handy as this might be I believe that this approach breaks with MVC because at the end of the day all models will be full of methods that do various funky stuff and the controller and helper classes do almost nothing.
In my understanding of MVC, models should only contain properties and a minimum of "helper methods" inside. For example a model "Article" could offer a method getNumOfTags() but it shouldn't do any Ajax calls on its own.
So, which approach is correct?
Generally I try to keep controllers simple in terms of logic too. If business logic is required, it will go up to 'service layer' classes to handle it. This also saves repeating any code/logic too, which ultimately makes the whole project more maintainable if business logic was to change. I just keep models purely as entity objects.
I think the answer above sums it up nicely though, it is easy to over engineer a project based on design patterns: Go with whatever works for you and is most maintainable/efficient.
You should stop treating "model" in MVC like some class. Model is not a class or object. Model is a layer (in modern MVC, there has been some evolutions since the inception of concept). What people tend to call "models" are actually domain object (I blame Rails for this mass-stupidity).
The application logic (interaction between domain logic structures and storage abstraction) should be a part of model layer. To be more precise: it should be inside the Services.
The interaction between presentation layer (controllers, views, layouts, templates) and model layer should happen only through those services.
Application has no place in controllers. Controllers are structures of presentation layer, and they are responsible for handling user input. Please do not expoqbse deomain objects to it.
Correct? Either. They both compile, don't they?
Handy tricks are nice, why not use them were you can? That being said, as you've pointed out, you may get bloated models if you put all sorts of logic in them. Likewise, though, you can get bloated controllers when they do massive amounts in each action. There are ways to abstract elements out of either, if that's necessary too.
At the end of the day all design patterns are is guidelines. You shouldn't blindly follow any rule, just because someone else said it. Do what works for you, what you think gives clean, extensible code and hits whatever metrics you think make good code.
All that being said, for true idealistic MVC I would say that models should not have any external actions, they're data representations, nothing more. But feel free to disagree :-)
Your suggestion about the modules (without any business logic inside) sounds more like you talk about Value Objects. The suggestion of your college sounds more like Domain Objects.
In my opinion the concept which will be used depends on the framework which is used (that's the practical view, the more philosophical one is bellow). If framework is used it usually sets rules about how you should implement each component.
For example we can look at different MVC frameworks. In Flex's Cairngorm framework we have both. VO (Value objects) are primary used for bindings to the view, while the DO (Domain objects) hold the business logic. If we look at ASP.NET's MVC implementation there we have a model which contains at least the data (VO) but also some validation (if required). Let us look at a UI MV* framework - for example Backbone.js. Backbone's documentation says:
Models are the heart of any JavaScript application, containing the
interactive data as well as a large part of the logic surrounding it:
conversions, validations, computed properties, and access control.
If we look into the traditional MVC provided by Smalltalk we see that: "Model: manages the behavior and data of the application domain" so we have some behavior in it, not just plain data.
Let's think practically, if don't have any logic in the Model probably we should put all the application and business logic into the Controller.
Now let's focus on a concrete example. Imagine we have a model which is a Graph. We want to find the shortest path between two nodes in it. A good question is where to put the algorithm which finds the shortest path? It's a kind of business logic, right? If we look at the main benefits of MVC (code reuse, DRY etc.) we can see that if we want to reuse our model in the best possible way we should implement the shortest path inside it. The shortest path algorithm usually depends on the graph inner representation (or at least for best performance of the algorithm) but this representation is encapsulated into the model, unfortunately we cant reuse the full shortest path for matrix representation and list of neighbors so it's not a good idea to put it into the controller.
So as conclusion I can said that it depends on your needs (mostly). The traditional MVC purpose is to be used in the UI (inside GoF
The Model/View/Controller (MVC) triad of classes [first described by Krasner and Pope in >1988] is used to build user interfaces in Smalltalk-80.
)
now we use it in different areas - only UI, for web applications, etc. It cant be used in it's pure form because of that.
But anyway, in my opinion the best separation of concerns can be achieved by isolation of the business logic into the Model and the application logic into the Controller.
In short I believe the Model should just be data that will be sent to your View. It helps drive the MVC paradigm into other aspects of your application.
If you are tring not to break the MVC pattern your data should all be returned as a Business Model to your controller and unpacked into your ViewModel. Request the information server side and then send everything. If you need to make JSon requests then that should either be a Rest Service or calls to a Controller. Having these getTags and getArticles makes it very messy ... if your view is now deciding on which to call ... I cant understand why you dont have that information isnt available upfront. Using static methods is the same approach just a different angle.
I have found it best to have my controller actions call an injected service which does the magic and use the Models within the MVC web application to return the information. This makes things neater and further emphasisis the seperation of concern. Your Controller Actions then become very lean and its clear what they are doing.
I believe starting by treating the Model as completly dumb might go a long way in sorting some of these architectural problems I am seeing from this code.
Yes. It should. You are talking about Domain Driven Design.
https://en.wikipedia.org/wiki/Domain-driven_design
If you feel, you are not doing that then you are doing Anaemic Domain Model Design. that is an Anti Pattern.
I read through an article from Martin Flower on how bad the Anaemic Domain Design is. https://martinfowler.com/bliki/AnemicDomainModel.html

Spring Request Mapping Mis

I am using Spring mapping. And have the following mapping code. The problem is there are like 20 possible misspelling for these and others that need to be accounted for. Rather than add a RequestMapping for each url which would be like 30 or 40, is there a way to simply redirect these. I know the way I am doing is not clean and would appreciate advice on how to keep my request mappings to a minium. Thanks.
#RequestMapping("/protect")
public String protect(Model model) {
QuickResponse qr = createQR();
model.addAttribute("qr", qr);
return "qr_general";
}
I am unsure as to what can be misspelled, but I am thinking you are referring to the path that is being mapped to.
The #RequestMapping annotation's default value member takes String[], so you should be able to put all of your mappings in one location:
#RequestMapping({"/protect", "/protekt", "/proteckt", "/protext"})
public String protect(Model model) {
QuickResponse qr = createQR();
model.addAttribute("qr", qr);
return "qr_general";
}

Resources