2010-01-30

REST with Spring 3.0, Spring MVC and Dojo. Part 1 - GET

Introduction


I am going to write a few posts on RESTful application development with Spring 3.0, using Spring MVC, Dojo and Maven. In the first part, I will show you how to create a basic controller and handle a GET request. The rest: DELETE, POST, PUT we will cover later.

I would suggest that - in case you're not very familiar with REST - you read some information about REST, for instance A Brief Introduction to REST from InfoQ or this article on REST conventions.

I am going to use a Maven project in Eclipse Ganymede with the M2Eclipse plugin, the latest development build (0.9.9.200912160759), as the latest production release contains some weird bugs including this annoying bug that seems to be fixed in the development build (it's time to release, guys!).

I am also going to use JBoss 5.1.0 JDK6 and that's why I will put one of the Spring beans files (applicationContext.xml) in the classes folder of the output war which is ugly but it works (it didn't work when I put it in /WEB-INF/; it did work in WebSphere though). Funny that when I called it beans.xml I would actually get an exception from JBoss: javax.inject.DefinitionException: bean not a Java type. Handy, I guess we're getting somewhere with error reporting.

One more thing, I am using Java 1.6 but Java 1.5 will suffice for everything - except for validation where a Java 6 annotation will be used. It is possible to implement your own validation though, it's really up to you. Validation will be shown in the POST and PUT parts. In this post only very basic (type) validation will be shown.

What you will learn


Let us begin! We are going to handle GET requests - in this example two GET requests. One without parameters (it will return all books - books will be sample items in this example) and one with a parameter - book ID. This will allow you to see:

  • How to handle input RESTful parameters with Spring MVC
  • How to return a collection of items
  • How to return a single item

Operation REST method Sample URI
Return item(s) GET /books (all books)
/books/ (all books)
/books/12 (one book with ID = 12)
Create a new item POST (you pass the ID in the object itself)
/books
/books/
Update an item PUT (you pass the ID in the object itself)
/books
/books/
Delete an item DELETE /books/12 (book with ID = 12)

The controller


Let's take a look at our controller class - the controller will handle the requests.

package me.m1key.restsample.controllers;

import java.util.List;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
// Some imports excluded for brevity, eh?

/**
 * Books controller.
 *
 * @author Michal Huniewicz
 *
 */
@Controller
@RequestMapping("/books")
public class SampleController {
    // Methods excluded for brevity.
}

This is it, it doesn't have to implement or extend anything. It is only annotated as a controller with the @Controller annotation. It means it can have many actions, like MultiActionController in the old days.

It is also annotated with @RequestMapping. This is where we specify the path which this controlller is to handle. As you will see, the action methods will also be annotated with this to further narrow down the criteria.

Setup


Now, how will Spring know about this Controller? We will tell it specifying certain information, first in the web.xml file.

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
    <display-name>Books REST Handler</display-name>

    <context-param>
        <param-name>webAppRootKey</param-name>
        <param-value>rest.root</param-value>
    </context-param>

    <!-- Servlets -->

    <servlet>
        <servlet-name>rest</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>2</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>rest</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>
    
    <!-- Rest of the file omitted for brevity. -->

</web-app>

In the web.xml file we declare the dispatcher servlet from Spring and we ask the server to load it on startup. We also assign this servlet to a certain path, that is /rest/* preceded by application's context root.

Now, because we specified the servlet name to be rest, we will create one more file next to web.xml (in the /WEB-INF/ folder that is) called rest-servlet.xml. While web.xml is a standard JEE file, this rest-servlet.xml file is a Spring Framework kind of file.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:oxm="http://www.springframework.org/schema/oxm"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
                http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
                http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd">

    <context:component-scan base-package="me.m1key.restsample.controllers" />
    
    <!-- Rest of the file omitted for brevity. -->



And this is how we tell Spring to search for components: with the context:component-scan element that specifies where to look for components in our application. An alternative would be to declare all the beans separately with the bean element.

Controller actions - return all books


What we did so far is we declared a controller, we told the server and Spring about it. It's time to write some actions.

package me.m1key.restsample.controllers;

import java.util.List;

import me.m1key.restsample.Factory;
import me.m1key.restsample.beans.BooksBean;
import me.m1key.restsample.to.BookTO;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

/**
 * Books controller.
 *
 * @author Michal Huniewicz
 *
 */
@Controller
@RequestMapping("/books")
public class SampleController {

    private static final String BOOKS = "books";

    /**
     * Returns all books.
     *
     * @return all books
     */
    @RequestMapping(value = "", method = RequestMethod.GET)
    public ModelAndView handleAllBooks() {
        ModelAndView mav = new ModelAndView();

        BooksBean booksBean = Factory.getBooksBean();

        List booksTO = booksBean.loadBooks();

        mav.addObject(BOOKS, booksTO);

        return mav;
    }

    // Rest of the code omitted for brevity.

}

Please take a look at the handleAllBooks method. It is annotated with @RequestMapping, like promised. That means that it will handle /books/ (or /books without the trailing backslash slash backslash slash) requests (within the app context root). What it returns is a ModelAndView object, that's it. We use BooksBean to get us the list of all books as controllers shouldn't really contain that kind of logic (see the MVC pattern). In our example BooksBean is just a dummy object, so it doesn't use any data source like it would in a real application.

There are two more things I must mention.

  • You should not call ModelAndView#addObject() more than once because if you do you might get inconsistent results depending on the output format (JSON/XML/...). To be precise, with JSON you would get all the objects no matter how many times you call addObject. With XML - just one. It looks like a bug but Arjen Poutsma was kind enough to explain to me that it isn't.
  • Wait a second, I'm talking JSON, XML, but the code just returns a ModelAndView object... That's right, the Controller is not aware of the output method. Ideally, we should be able to say /rest/books.json and get JSON response, /rest/books.xml and get XML response, /rest/books.html and get HTML response, /rest/books.mp3 and get a bunch of ladies singing the book titles. In this simple application we are going to handle only JSON and XML.

Telling Spring about the output methods we support - XML and JSON


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:oxm="http://www.springframework.org/schema/oxm"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
                http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
                http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd">

    <context:component-scan base-package="me.m1key.restsample.controllers" />

    <bean
        class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
        <property name="messageConverters">
            <list>
                <bean id="mappingJacksonHttpMessageConverter"
                    class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" />
            </list>
        </property>
    </bean>
    <bean
        class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
        <property name="mediaTypes">
            <map>
                <entry key="json" value="application/json" />
                <entry key="xml" value="application/xml" />
            </map>
        </property>
        <property name="defaultViews">
            <list>
                <bean
                    class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
                <bean class="org.springframework.web.servlet.view.xml.MarshallingView">
                    <constructor-arg>
                        <bean class="org.springframework.oxm.xstream.XStreamMarshaller"
                            p:autodetectAnnotations="false" />
                    </constructor-arg>
                </bean>

            </list>
        </property>
        <property name="defaultContentType" ref="jsonMediaType" />
        <property name="ignoreAcceptHeader" value="false" />
    </bean>

    <bean id="jsonMediaType" class="org.springframework.http.MediaType">
        <constructor-arg value="application/json" />
    </bean>

</beans>

Update 2010-03-31: Ralph Engelmann reported that the last bean definition is not valid as of Spring 3.0.1.RELEASE (see comments below). If you are using this version of later, you must define this bean in the following manner:
<bean id="jsonMediaType" class="org.springframework.http.MediaType">
    <constructor-arg value="application"/>
    <constructor-arg value="json"/>
</bean>
Thanks goes to Ralph.

Whew!

The first part (with AnnotationMethodHandlerAdapter) tells Spring which input methods we support (it will be useful when we send objects to the server via REST).

The second part (with ContentNegotiatingViewResolver) tells Spring which output methods we support (in this example, JSON and XML, as you can see).

Below we also define the default (preferred by us) output format. Please note that the client can still ignore it and request another one if available.

Controller actions - return one book by ID


This is going to be a bit more interesting than returning all the books for two reasons:
  • We must handle an entry parameter via REST (the requested book ID).
  • We must handle the situation when the requested book cannot be found.

Let's see the action method.

/**
     * Returns a single book by ID.
     *
     * @param response
     *            response
     * @param bookId
     *            book ID
     * @return single book
     */
    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public ModelAndView handleBookById(HttpServletResponse response,
            @PathVariable("id") Long bookId) {
        ModelAndView mav = new ModelAndView();

        BooksBean booksBean = Factory.getBooksBean();

        BookTO bookTO = booksBean.loadBookById(bookId);

        mav.addObject(BOOK, bookTO);

        return mav;
    }

Now, with the new RequestMapping annotation we narrow down the query criteria. This mapping will handle /rest/books/1 kind of addresses (preceded by context root). Please note the @PathVariable annotation that binds the variable in the request mapping to the annotated variable.

See the response parameter? It's not used at the moment. Luckily, it doesn't break the method. For now, it would work (handle requests that is) with or without the parameter. We will use it later.

Hm, how does basic parameter validation work? What if I say /rest/books/x? Well, x is not a Long, so I will get a 404 - nice.

But if the book doesn't exist - that's a different story. In my dummy BooksBean I only have two books, so if I say /rest/books/3 the bean method returns an empty object. Not nice. When the book doesn't exist - we want to return a 404. This is why we need the response object. Let's look at the improved action method.

/**
     * Returns a single book by ID.
     *
     * @param response
     *            response
     * @param bookId
     *            book ID
     * @return single book
     * @throws IOException
     */
    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public ModelAndView handleBookById(HttpServletResponse response,
            @PathVariable("id") Long bookId) throws IOException {
        ModelAndView mav = new ModelAndView();

        BooksBean booksBean = Factory.getBooksBean();

        BookTO bookTO = booksBean.loadBookById(bookId);

        if (bookTO.getId() == null) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND, "Book "
                    + bookId + " not found.");
        }
        mav.addObject(BOOK, bookTO);

        return mav;
    }

If we detect that the returned book is empty - we write to response a 404 error (SC_NOT_FOUND).

Results


That's quite a post. Let us look at the output XML and JSON.

All books in XML:

<list>
    <me.m1key.restsample.to.BookTO>
        <id>1</id>
        <name>Lord of the Rings</name>
    </me.m1key.restsample.to.BookTO>

    <me.m1key.restsample.to.BookTO>
        <id>2</id>
        <name>My Name Is Red</name>
    </me.m1key.restsample.to.BookTO>
</list>

All books in JSON (I broke it into 3 lines myself for readability):

{"books":
    [{"name":"Lord of the Rings","id":1},
    {"name":"My Name Is Red","id":2}]}

One book in XML:

<me.m1key.restsample.to.BookTO>
    <id>1</id>
    <name>Lord of the Rings</name>
</me.m1key.restsample.to.BookTO>

One book in JSON:

{"book":{"name":"Lord of the Rings","id":1}}


That's it for now. In the next post I will show you how to access this data with Dojo.

Download source code for this article

  1. REST with Spring 3.0, Spring MVC and Dojo. Part 1 - GET
  2. REST with Spring 3.0, Spring MVC and Dojo. Part 2 - GET from Dojo perspective
  3. REST with Spring 3.0, Spring MVC and Dojo. Part 3 - POST and JSR-303 validation
  4. REST with Spring 3.0, Spring MVC and Dojo. Part 4 - PUT (updating objects)
  5. REST with Spring 3.0, Spring MVC and Dojo. Part 5 - DELETE

298 comments:

  1. Hello, your Post helped my a lot. But your "jsonMediaType" Bean did not work for me (Spring 3.0.1.RELEASE), i get an IllegalArgumentException: Invalid token character '/' in token "application/json". I have changed it to:

    so it works for me.

    Best Regards

    ReplyDelete
  2. Sorry: i have some troulbe with the xml: I changed the "jsonMediaType" bean configuration to use the 2 parameter constructor:

    first parameter (index="0") value="application",

    second parameter (index="1") value="json"

    ReplyDelete
  3. Hey Ralph, thanks for your comment.

    I just checked my project and "application/json" works without any problems - however my org.springframework.http.MediaType bean is Spring 3.0.0.RELEASE so that might be the reason.

    I will download the source for 3.0.1.RELEASE and compare it to 3.0.0.RELEASE and let you know if I find anything out.

    ReplyDelete
  4. OK, found it!

    This, indeed, is a change in 3.0.1, that's why I didn't have this problem.

    Thanks for pointing it out and here you can find a little bit of explanation by Arjen Poutsma (post #3):
    http://forum.springsource.org/showthread.php?t=85004

    Best regards.

    ReplyDelete
  5. This may seem like a dumb question, but... the XML version of the returned bean is fairly ghastly compared to the JSON, i.e.

    <me.m1key.restsample.to.BookTO>
    <id>1</id>
    <name>Lord of the Rings</name>
    </me.m1key.restsample.to.BookTO>

    compared to

    {"book":{"name":"Lord of the Rings","id":1}}

    Is there any simple way to get the XML to look like this?:

    <book>
    <id>1</id>
    <name>Lord of the Rings</name>
    </book>

    The clients I want to use this output don't really give a damn what Java wants to call the bean!

    ReplyDelete
  6. Nello, perhaps this could be of some help:






    org.springframework.oxm.xstream.Flight



    ...



    (http://docs.huihoo.com/spring/spring-web-services/1.0/oxm.html)

    ReplyDelete
  7. Uh oh. It lost my XML.

    [bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller"]
    [property name="aliases"]
    [props]
    [prop key="Flight">org.springframework.oxm.xstream.Flight[/prop]
    [/props]
    [/property]
    [/bean]

    ReplyDelete
  8. Thanks for that!

    I did find a reference to the XStreamMarshaller alias stuff eventually after my post above, but it doesn't fly under GAE. I have moved to using Castor ( http://www.castor.org ), which is a bit more complex to configure but works for me.

    ReplyDelete
  9. Nello,

    I'm happy to hear that. Thanks for visiting. :)

    ReplyDelete
  10. Mój problem polega na tym, że skonfigurowałem wszystko jak na obrazku, a mimo to w odpowiedzi kontener szuka mi jsp, a nie jsona. Masz na to jakąś radę?

    ReplyDelete
  11. [PL] Moim zdaniem to problem z view resolverem. Czy Twoj plik XML ma poprawna nazwe (nazwa servletu + "-servlet.xml")?
    Daj znac. :)

    [EN] Problem: Spring tries to find JSP instead of JSON.
    My Idea: It's a problem with the view resolver or your servlet.xml file has an incorrect name (servlet name + "-servlet.xml").

    ReplyDelete
  12. Thank you very much for this article! It helped me a lot.

    ReplyDelete
  13. Thank you, very good article. i am a bit stuck with the json i am receiving and adding that list to existing select box, can you help?

    ReplyDelete
  14. Hi there, what is wrong with your JSON response?

    ReplyDelete
  15. Hi, Mike - This example doesn't work for me. I created a war file from the sample given by you, but its giving me a 404 error on browser. Please help.
    - Rahul

    ReplyDelete
  16. I am using this url - http://localhost:8080/rest/books/1 as the servlet name is rest in web.xml. Let me know if i am making any mistake or else i can provide you the war file that i created. I'm publishing this on tomcat 6

    ReplyDelete
  17. Hi Rahul, I think you need to provide the war name in the URL as well. So, for a war file called rahul.war - http://localhost:8080/rahul/rest/books/1

    ReplyDelete
  18. Hi,

    First thanks for this post. But still i am having some question. I have created the controller and bean class and used DOJO to submit and fetch the data from server. But i was not able to do that but after changing the dojo code with your it is working as expected please review my dojo code and let me know what i am doing wrong.
    My Dojo Code (Not working)

    function sendForm() {
    var myForm = dijit.byId("myFormTwo");
    content: dojo.toJson(myForm.attr("value")),
    dojo.xhrPost({

    // The URL of the request
    url: "http://localhost:8080/DOJO_AJAX/updateContact.do",
    //content: dojo.formToJson(myFormTwo),
    //content: {"id":"1","name":"viveka gautam","mobile":"0067392109"},
    headers: { "Content-Type": "application/json"},
    content: dojo.toJson(myForm.attr("value")),

    //form: dojo.byId("myFormTwo"),
    // Handle the result as JSON data
    handleAs: "json",
    // The success handler
    load: function(jsonData) {
    var content = "";
    },
    // The error handler
    error: function() {
    }
    });
    }
    ###################

    Dojo code working(as taken from your example)

    function saveBook() {
    var newBook = {
    "id":1,"name":"name1"
    };
    var myForm = dijit.byId("myFormTwo");
    //content: dojo.toJson(myForm.attr("value")),
    var actualContent = dojo.toJson(myForm.attr("value"));
    //var actualContent = dojo.toJson(newBook);
    debugger;
    //Save.
    var deferred = this._request("rawXhrPost", {
    url: "http://localhost:8080/DOJO_AJAX/updateContact.do",
    handleAs: "json",
    postData: actualContent,
    headers: { "Content-Type": "application/json"}
    });
    deferred.addCallback(this, function(value) {
    alert("Retrieved " + value.name);
    });
    deferred.addErrback(this, function(value) {
    alert("Error: " + value);
    });
    }

    Please let me know what is wrong with the first code. after changing this code only everything is working find so there seeme to be some problem with my dojo code.

    Thanks

    ReplyDelete
  19. Gautam, I would provide an actual error handler to see what's wrong. Yours is empty.

    ReplyDelete
  20. I have exactly same configuration as above and I am testing using firefox-RESTClient and with that .json works fine however when i pass application/xml ,i receive json response.

    ReplyDelete
  21. Good tutorial.
    But please can you tell me what modifications I would have to do if I had to pull the data from database instead of using XML file (say I want to use spring jpa for example).
    Thanks.
    Kwame.

    ReplyDelete
  22. Needed to compose you a very little word to thank you yet again regarding the nice suggestions you’ve contributed here.

    Best Hadoop training in chennai

    ReplyDelete
  23. Thanks a lot very much for the high your blog post quality and results-oriented help. I won’t think twice to endorse to anybody who wants and needs support about this area.
    datascience training in chennai

    ReplyDelete
  24. Nice blog! This blog giving very useful information. Thanks for sharing with us.

    Dot Net Training in Chennai
    Java Training in Chennai

    ReplyDelete
  25. Your post about technology was very helpful to me. Very clear step-by-step instructions. I appreciate your hard work and thanks for sharing.
    Data Science Course in Chennai
    Machine Learning Course in Chennai

    ReplyDelete
  26. Thanks for one marvelous posting! I enjoyed reading it; you are a great author. I will make sure to bookmark your blog and may come back someday. I want to encourage that you continue your great posts, have a nice weekend!
    Data Science Training in Chennai

    ReplyDelete
  27. Needed to compose you a very little word to thank you yet again regarding the nice suggestions you’ve contributed here.

    RPA Training in Chennai

    ReplyDelete
  28. Thanks for such a great article here. I was searching for something like this for quite a long time and at last I’ve found it on your blog. It was definitely interesting for me to read  about their market situation nowadays.
    Click here:
    Angularjs training in chennai

    Click here:
    angularjs training in bangalore

    Click here:
    angularjs training in online

    Click here:
    angularjs training in Annanagar

    ReplyDelete
  29. This is such a good post. One of the best posts that I\'ve read in my whole life. I am so happy that you chose this day to give me this. Please, continue to give me such valuable posts. Cheers!
    Click here:
    Microsoft azure training in velarchery
    Click here:
    Microsoft azure training in sollinganallur
    Click here:
    Microsoft azure training in btm
    Click here:
    Microsoft azure training in rajajinagar

    ReplyDelete
  30. Great post! I am actually getting ready to across this information, It’s very helpful for this blog.Also great with all of the valuable information you have Keep up the good work you are doing well.
    Devops training in tambaram|Devops training in velachery|Devops training in annanagar|Devops training in sholinganallur

    ReplyDelete
  31. Very nice post here and thanks for it .I always like and such a super contents of these post.Excellent and very cool idea and great content of different kinds of the valuable information's.
    Good discussion. Thank you.
    Anexas
    Six Sigma Training in Abu Dhabi
    Six Sigma Training in Dammam
    Six Sigma Training in Riyadh

    ReplyDelete
  32. Good Post! Thank you so much for sharing this pretty post, it was so good to read and useful to improve my knowledge as updated one, keep blogging.

    rpa training in velachery| rpa training in tambaram |rpa training in sholinganallur | rpa training in annanagar| rpa training in kalyannagar

    ReplyDelete
  33. All the points you described so beautiful. Every time i read your i blog and i am so surprised that how you can write so well.
    java interview questions and answers | core java interview questions and answers

    java training in tambaram | java training in velachery

    ReplyDelete
  34. Thanks for the good words! Really appreciated. Great post. I’ve been commenting a lot on a few blogs recently, but I hadn’t thought about my approach until you brought it up. 
    Data Science Training in Chennai | Data Science training in anna nagar
    Data Science training in chennai | Data science training in Bangalore
    Data Science training in marathahalli | Data Science training in btm

    ReplyDelete
  35. Hmm, it seems like your site ate my first comment (it was extremely long) so I guess I’ll just sum it up what I had written and say, I’m thoroughly enjoying your blog. I as well as an aspiring blog writer, but I’m still new to the whole thing. Do you have any recommendations for newbie blog writers? I’d appreciate it.

    AWS Interview Questions And Answers


    AWS Training in Bangalore | Amazon Web Services Training in Bangalore

    AWS Training in Pune | Best Amazon Web Services Training in Pune

    Amazon Web Services Training in Pune | Best AWS Training in Pune

    AWS Online Training | Online AWS Certification Course

    ReplyDelete
  36. Wow, Nice blog. Thank you so much for the efforts of this blog. Visit for
    Web Designing Company in Delhi

    ReplyDelete
  37. Really very nice blog information for this one and more technical skills are improve,i like that kind of post.
    advanced excel training in bangalore

    ReplyDelete

  38. Awwsome informative blog ,Very good information thanks for sharing such wonderful blog with us ,after long time came across such knowlegeble blog. keep sharing such informative blog with us.
    Airport Management Courses in Chennai | Airport Management Training in Chennai | Diploma in Airport Management Course in Chennai | Airlines Training Chennai | Airline Academy in Chennai

    ReplyDelete
  39. Thank you for sharing your article. Great efforts put it to find the list of articles which is very useful to know, Definitely will share the same to other forums.
    Data Science Training in chennai at Credo Systemz | data science course fees in chennai | data science course in chennai quora | data science with python training in chennai

    ReplyDelete
  40. Outstanding blog thanks for sharing such wonderful blog with us ,after long time came across such knowlegeble blog. keep sharing such informative blog with us.
    Machine learning training in chennai
    best training insitute for machine learning
    machine learning training in velachery
    Android Training Course Fees
    Best PMP Training in Chennai

    ReplyDelete
  41. Hello! Someone in my Facebook group shared this website with us, so I came to give it a look. I’m enjoying the information
    nebosh course in chennai

    ReplyDelete
  42. I wondered upon your blog and wanted to say that I have really enjoyed reading your blog posts. Any way I’ll be subscribing to your feed and I hope you post again soon.
    Best selenium training in chennai
    Best selenium Training Institute in Chennai
    Selenium classes in chennai
    Testing Training in Chennai
    Software testing institutes in chennai
    Software Testing Training

    ReplyDelete
  43. I accept there are numerous more pleasurable open doors ahead for people that took a gander at your site.we are providing ReactJs training in Chennai.
    For more details: ReactJs training in Velachery | ReactJs training in chennai

    ReplyDelete
  44. THANKS FOR INFORMATION

    you can search low-cost website with high-quality website functions.
    Today Join Us
    Call: +91 - 8076909847

    website development company in Delhi

    levantro
    interior designers in delhi


    livewebindia
    website designing company in delhi

    SEO service in Delhi

    Best It Service Provider:

    1. Website Designing And Development.
    2. SEO Services.
    3. Software Development.
    4. Mobile App Development.

    ReplyDelete
  45. Thank you so much for your information,its very useful and helful to me.Keep updating and sharing. Thank you.
    RPA training in chennai | UiPath training in chennai

    ReplyDelete
  46. Outstanding blog thanks for sharing such wonderful blog with us ,after long time came across such knowlegeble blog. keep sharing such informative blog with us.

    machine learning training in velachery

    top institutes for machine learning in chennai

    ReplyDelete
  47. Given so much info in it, The list of your blogs are very helpful for those who want to learn more interesting facts. Keeps the users interest in the website, and keep on sharing more
    Our Credo Systemz Which is designed to offer you OpenStack Training skills required to kick-start your journey as an OpenStack Cloud Administrator.
    Please free to call us @ +91 9884412301 / 9600112302

    openstack training in Chennai | Openstack certification course in chennai | openstack certification training in Chennai | openstack training in chennai velachery

    ReplyDelete
  48. Such a Great Article!! I learned something new from your blog. Amazing stuff. I would like to follow your blog frequently. Keep Rocking!!
    Blue Prism training in chennai | Best Blue Prism Training Institute in Chennai

    ReplyDelete
  49. Nice blog..! I really loved reading through this article. Thanks for sharing such a
    amazing post with us and keep blogging... AngularJS Training in Chennai | Best AngularJS Training Institute in Chennai

    ReplyDelete
  50. Laminated Doors manufacturer in hubli
    Thanks for giving great kind of information. So useful and practical for me. Thanks for your excellent blog, nice work keep it up thanks for sharing the knowledge.

    ReplyDelete
  51. Thanks for give a wonderful experience while reading this blog.
    Selenium Training Program in Chennai

    ReplyDelete
  52. led lawn lights in delhi
    Thanks for giving great kind of information. So useful and practical for me. Thanks for your excellent blog, nice work keep it up thanks for sharing the knowledge.

    ReplyDelete
  53. Thanks for giving great kind of information. So useful and practical for me. Thanks for your excellent blog, nice work keep it up thanks for sharing the knowledge.

    AWS Training in Chennai

    ReplyDelete
  54. Wow!! Really a nice Article. Thank you so much for your efforts. Definitely, it will be helpful for others. I would like to follow your blog. Share more like this. Thanks Again.
    iot training in Chennai | Best iot Training Institute in Chennai

    ReplyDelete
  55. Great post! I am actually getting ready to across this information, It's very helpful for this blog. Also great with all of the valuable information you have Keep up the good work you are doing well.DevOps Training in Chennai | Best DevOps Training Institute in Chennai

    ReplyDelete
  56. Online casino for everyone, come in and win now only we have the best online slots The best online slots we have.

    ReplyDelete
  57. Nice blog..! I really loved reading through this article. Thanks for sharing such a
    amazing post with us and keep blogging... Best React js training near me | React js training online

    ReplyDelete
  58. Very Clear Explanation. Thank you to share this
    Regards,
    Data Science Course In Chennai

    ReplyDelete
  59. I am grateful to the owner of this site which really shares this wonderful work of this site.That is actually great and useful information.I'm satisfied with just sharing this useful information with us. Please keep it up to date like this.Thank you for sharing..
    website development company in patna
    packers and movers in patna
    cctv camera dealers in patna
    jobs in patna

    ReplyDelete
  60. Алюминиевый профиль светодиодной ленты лучшее что я находил это в компании Ekodio, супер ребята рекоммендую.

    ReplyDelete
  61. Thanks for such a great article here. I was searching for something like this for quite a long time and at last, I’ve found it on your blog. It was definitely interesting for me to read about their market situation nowadays.angularjs best training center in chennai | angularjs training in velachery | angularjs training in chennai

    ReplyDelete
  62. Information from this blog is very useful for me, am very happy to read this blog Kindly visit us @ Luxury Watch Box | Shoe Box Manufacturer |  Candle Packaging Boxes

    ReplyDelete
  63. Very Clear Explanation. Thank you to share this

    Data Science With R

    ReplyDelete
  64. It would have been the happiest moment for you,I mean if we have been waiting for something to happen and when it happens we forgot all hardwork and wait for getting that happened.
    angularjs online training

    apache spark online training

    informatica mdm online training

    devops online training

    aws online training

    ReplyDelete
  65. Hey Nice Blog!! Thanks For Sharing!!!Wonderful blog & good post.Its really helpful for me, waiting for a more new post. Keep Blogging!
    SEO company in coimbatore
    SEO company
    web design in coimbatore

    ReplyDelete
  66. I wish to say that this post is amazing, nice written and include approximately all important infos. I would like to see more posts like this
    Regards,
    Python Training in Chennai | Python Programming Classes | Python Classes in Chennai

    ReplyDelete
  67. Hey Nice Blog!! Thanks For Sharing!!!Wonderful blog & good post.Its really helpful for me, waiting for a more new post. Keep Blogging!
    SEO company in coimbatore
    SEO company
    web design company in coimbatore

    ReplyDelete
  68. I read this post two times, I like it so much, please try to keep posting & Let me introduce other material that may be good for our community.
    Microsoft Azure online training
    Selenium online training
    Java online training
    Python online training
    uipath online training

    ReplyDelete
  69. This is really too useful and have more ideas and keep sharing many techniques. Eagerly waiting for your new blog keep doing more.
    Regards,
    Tableau training in Chennai | Tableau Courses Training in Chennai | Tableau training Institute in Chennai

    ReplyDelete
  70. I feel happy about and learning more about this topic. keep sharing your information regularly for my future reference. This content creates new hope and inspiration within me. Thanks for sharing an article like this. the information which you have provided is better than another blog.
    Best IELTS Coaching in Dwarka

    ReplyDelete
  71. Thank you for allowing me to read it, welcome to the next in a recent article. And thanks for sharing the nice article, keep posting or updating news article.
    oneplus service centre chennai
    oneplus service centre
    oneplus mobile service center in chennai

    ReplyDelete
  72. The best and powerfull dua for love back and love marraige is Duas in islam use this dua and solve your love problems.

    ReplyDelete
  73. Informative. It’s not easy to get such quality information online nowadays.Great going.

    Inplant Training in Chennai
    Inplant Training
    Inplant Training in Chennai for IT

    ReplyDelete
  74. Get the best nursing services baby care services medical equipment services and allso get the physiotherapist at home in Delhi NCR For more information visit our site

    nursing attendant services in Delhi NCR
    medical equipment services in Delhi NCR
    nursing services in Delhi NCR
    physiotherapist at home in Delhi NCR
    baby care services in Delhi NCR

    ReplyDelete

  75. Amazing article. Your blog helped me to improve myself in many ways thanks for sharing this kind of wonderful informative blogs in live.
    javascript training in chennai | javascript training institute in chennai | javascript course in chennai | javascript certification in chennai | best javascript training in chennai

    ReplyDelete
  76. This is really a big and great source of information. We can all contribute and benefit from reading as well as gaining knowledge from this content just amazing
    experience Thanks for sharing such a nice information.

    DedicatedHosting4u.com

    ReplyDelete
  77. Amazing article. Your blog helped me to improve myself in many ways thanks for sharing this kind of wonderful informative blogs in live.
    IT Institute in KK nagar | dot net training in chennai | dot net training institute in chennai | dot net course in chennai | .NET Training Center in Chennai

    ReplyDelete
  78. Very informative blog and useful article thank you for sharing with us , keep posting learn more about aws with cloud computing

    AWS Online Training

    AWS Certification

    ReplyDelete
  79. شركة عزل خزانات بالمدينة المنورة
    سيدي العميل يجب عليكَ أن تحتفظ على خزان المياه خصتكَ من خلال القيام بعملية التنظيف بشكل دوري كما يجب عليكِ أن تقوم بعملية عزل الخزانات حتى تحافز على عمر الخزان من العوامل الخارجية التي يمكن أن يتعرض لها، ولا يوجد أفضل من شركة عزل خزانات بالمندينة المنورة لكي تقدم لكَ أفضل خدمات عزل خزانات بالمدينة المنورة، حيث ان الشركة تعتمد على المهندسين والفنين الحاصلين على شهادات الخبرة من أكبر الشركات التي تعمل في مجال تركيب عزل خزانات بالمدينة المنورة، إضافة إلى اجود الخامات التي تستخدمها الشركة التي لا تتعرض لأي ضرر على مدجار السنوات.

    ReplyDelete
  80. Usually I never comment on blogs but your article is so convincing that I never stop myself to say something about it. You’re doing a great job Man,Keep it up.
    best study abroad consultants in delhi

    ReplyDelete
  81. This comment has been removed by the author.

    ReplyDelete
  82. I Got Job in my dream company with decent 12 Lacks Per Annum Salary, I have learned this world most demanding course out there in the current IT Market from the python Training in bangalore Providers who helped me a lot to achieve my dreams comes true. Really worth trying.

    ReplyDelete
  83. Nice Blog, I have get enough information from your blog and I appreciate your way of writing.
    Hope you are sharing the same in future. Fine way of telling, and pleasant post.
    With thanks! Valuable information! Useful post, Nice info!
    Thanks a lot for sharing it, that’s truly has added a lot to our knowledge about this topic. Have a more success ful day. Amazing write-up, always find something interesting.
    Thanks
    BBL T20 Prediction
    CBTF Winner Prediction
    Session Lambi pari Prediction
    match predictions today
    cricket match prediction 100 sure
    BBL Match Predictor
    2020 IPL13 T20 Tips
    Cricket Winner Tips


    bhaijiking tips
    who will win today match prediction
    cbtf guru
    expertipsfree
    cbtf.biz BBL T20 reports

    ReplyDelete
  84. Assignment help is given the full vocation lift to the understudies in which we control the understudies to make the correct stride throughout everyday life and show signs of improvement opportunity throughout everyday life.
    assignment help

    ReplyDelete
  85. In this technical domain, the presence of HP printer has been seen everywhere as it is highly recommended for taking the quality printout. On the controversial side, a great number of users face some technical issue while operating the printing command. There has not seen any substantial change even though you find quite variation in the matter of HP printer type. It is not a big concern that you are using the laser and ink-jet printer. The one and only thing expected from you end is access the high density printout only. Lastly, it is advised to stay on our third party professional team and make sold improvement in its functionality through dialing hp printer tech support number. We guarantee this fact that you cannot come in the contact of failure now and then as you can treatment with us. It is your wish when to call our expert for error removal. For taking comprehensive information, you can surf our website.

    ReplyDelete
  86. Assignment Help is the good and reliable source of completing your work on time by spending minimum effort. All students who need help for raising their marks, they can connect with academic experts of greatassignmenthelp Don’t spend your time and place your order right now.
    Assignment Help Online
    Online Assignment Help
    Assignment Help Online Services
    Assignment Helper
    Assignment Assistance
    Assignment Help Experts
    Online Assignment Help Services

    ReplyDelete
  87. Om een strategische afstand tot een dergelijke fout te behouden, moet u Garmin Express Update routinematig uitvoeren. Dit is de meest ideale methode om fouten of andere problemen in Garmin Express weg te houden. Neem voor gespecialiseerde hulp contact op met onze specialisten.
    Garmin Express
    garmin connect downloaden
    garmin connect problemen

    ReplyDelete
  88. Wondering how to configure a new printer on your iPhone, iPad, iPod Touch or Android mobile device? Just download the Canon PRINT App, hit your printer’s Wireless Connect button and the data stored on your phone, including your Wi-Fi name and password, will automatically be shared allowing the overall setup process quicker and easier than ever. There are different methods to set up the canon printer in different versions of the printer. If you want to know the Canon printer setup guide, contact our experts. They will give you the easiest steps to do so. Just dial our toll-free number and talk with the experts. The best part is that you can call round the clock.
    canon setup
    Canon error code 5b00
    Canon B200 Error
    Canon Wireless Printer Setup
    Connect Canon Printer To Wi-Fi
    Canon printer offline
    canon pixma mx490
    canon ts3122
    canon printer reset
    Canon Printer Setup

    ReplyDelete
  89. Whenever your Epson printer is unable to make communication with your computer then you will see an offline error with it. Isn’t it very annoying to see your Epson Printer Offline particularly when you needed to print something straight away? If you find out that your Epson printer is offline or stopped functioning as it should be then you need to take assistance from skilled professionals. In order to make connection with these experts, you have to make a call at toll-free number and join hands with them. So, don’t waste your further time just get hold of skilled professionals and bring back your printer online.
    Epson Support
    Epson Printer Support
    www.epson.com/support
    Epson error code 0x10
    Epson connect printer setup utility

    ReplyDelete
  90. Apart from the several amazing features of HP printers sometimes users may come across several errors which usually happen unexpectedly. One of the issues that are creating issue for many users is Printer Is In An Error State. There are a number of aspects which may be the reason that your machine showing in error state such as, print settings or some issues with the product itself. Just don’t take stress if you stumble upon with this issue. Simply put a call on helpline number and take help from the deft professionals to be acquainted with the proper measures that can solve this issue. https://www.hpprintersupportpro.com/blog/facing-issue-hp-printer-in-error-state-connect-with-out-experts/
    printer is in an error state
    printer in error state
    hp printer is in error state
    hp printer in error state
    printer in an error state
    hp printer is in an error state
    hp printer troubleshooting

    ReplyDelete

  91. Nice Blog, I have get enough information from your blog and I appreciate your way of writing.
    Thanks for everything and dial our Outlook support phone number for technical support and information of Outlook.
    How do I contact Microsoft tech support?”
    How do I contact Microsoft Outlook support
    Is there a phone number for Outlook support

    ReplyDelete
  92. This is a wonderful post. Thanks for sharing visit at Top seo agency 2019

    ReplyDelete
  93. Very nice!!! This is really good blog information thanks for sharing. We are a reliable third party Quickbooks update error 404 company offering technical support for various any types of technical errors.

    ReplyDelete
  94. Geek Squad Tech Support provides the best technical help and guidance. Get in touch with extensively trained tech support team for all sort of queries and issues regarding your devices. You can contact Geek Squad round the clock according to your convenience.

    ReplyDelete

  95. Get the solutions to all the technical issues with all your electronic appliances at Geek Squad Tech Support. Avail wide no of services, on-site, and over the Internet via remote access and In-store, and also provides 24/7 telephone and emergency on-site support. Reach the experts at Geek Squad Tech Support for removing all technical glitches with your devices

    ReplyDelete
  96. Fix technical breakdown of all your electronics and appliances at Geek Squad Support. Reach the certified experts at Geek Squad Support for fixing any kind of technical bug with your devices. Best of services and assistance assured at support.

    ReplyDelete
  97. Canon Pixma MX490 Setup can be easily attained by following simple guidelines. Read this blog for following easy steps for Canon Pixma MX490 Wireless Setup.

    ReplyDelete