skip to Main Content

I have a project using Spring MVC + AngularJS. All the data is dynamic.
Have some big database of locations in this app.

For SEO purposes, need to generate a static page for each location and put them on SEO-friendly URLs (ex. /localhost/path1/path2/here-is-very-friendly-name)

What is the best way to make it?

Should i just generate a pages separately and put them to some separate folder from the main app (if it is, whats the best way to make it?), or i can use Spring/Angular for that?

(for additional info)
each location’s object contains id,name, latitude, longtitude, address, district, city, country.

4

Answers


  1. Have you tried tools like SEO.js (http://getseojs.com/) and prerender.io (https://prerender.io/). Have you tried those?

    Login or Signup to reply.
  2. Actually it’s my Angular/SEO experience.
    You have to made lots of changes!!


    1) Removing # from url

    app.config(['$locationProvider', function ($locationProvider) {
    
        $locationProvider.html5Mode({
            enabled: true,
            requireBase: false
        });
    
    }]);
    

    2) Review your MVC Routing

    Till now maybe you had one HomeController for returning index.cshtml and booting up your Angular App.
    After removing # from Angular routing, you have to set MapRoute for all of your routes.
    Because in this situation the first time you try to visit routes like www.site.com/any_route Angular App not loaded yet so it tries to get page from MVC Routing. But after that $routeProvider do its duties.


    3) Use MVC variables for meta tags

    For better indexing and being friend with crawlers and bots we have to use MVC variables for initializing website meta tags.
    If you set your page title by Angular bindings like <title>{{title}}</title> whenever you want to share your page through social networks you will see {{title}} because social networks can’t render sites.

    <title>@ViewBag.title</title>
    <meta name="Description" content="@ViewBag.description">
    <meta name="Keywords" content="@ViewBag.keywords">
    <meta property="og:title" content="@ViewBag.title" />
    <meta property="og:description" content="@ViewBag.description" />
    

    4) Replace Angular binding for meta tags

    Our app is SPA, so after loading Angular we are out of MVC playground.
    We have to replace Angular variables with MVC variables.

    angular.element('title').remove();
    angular.element('meta[name="Description"]').remove();
    angular.element('meta[name="Keywords"]').remove();
    angular.element('meta[property="og:title"]').remove();
    angular.element('meta[property="og:description"]').remove();
    
    var description = angular.element('<meta name="Description" content="{{meta.description}}">');
    angular.element('head').prepend(description);    
    
    var keyword = angular.element('<meta name="Keywords" content="{{meta.keywords}}">');
    angular.element('head').prepend(keyword);    
    
    var titleOg = angular.element('<meta property="og:title" content="{{meta.title}}" />');
    angular.element('head').prepend(titleOg);    
    
    var descriptionOg = angular.element('<meta property="og:description" content="{{meta.description}}" />');
    angular.element('head').prepend(descriptionOg);
    
    var title = angular.element('<title ng-bind="meta.title"></title>');
    angular.element('head').prepend(title);  
    
    $rootScope.$applyAsync(function () {
        $compile(title)($rootScope);
        $compile(description)($rootScope);
        $compile(keyword)($rootScope);
        $compile(titleOg)($rootScope);
        $compile(descriptionOg)($rootScope);
    });
    

    5) use JSON-lD for dynamic contents

    If you are familiar with SCHEMA.org you better to use JSON-LD instead of others, because search engines bots can catch and analyse <script type="application/ld+json"></script>s that inserted dynamically after page loaded.
    You have to check Schema Dictionary to find the type that is most closer to your data structure.
    For example it’s my company json-ld:

    <script type="application/ld+json">
        {
            "@context" : "http://schema.org",
            "@type" : "Organization",
            "name" : "داده کاوان امیرکبیر",
            "alternateName" : "ADM | Amirkabir Data Miners",
            "description": "شرکت داده کاوان امیرکبیر | تولید کننده نرم افزارهای تحت وب، از قبیل حسابداری آنلاین 'کاج سیستم' ، سیستم مدیریت پروژه 'تسک من' و ...",
            "url" : "https://adm-co.net",
            "email": "[email protected]",
            "logo": {
                "@type": "ImageObject",
                "url": "http://khoonamon.com/images/ADM_Logo.png",
                "caption": "لوگو داده کاوان امیرکبیر",
                "width": "2480px",
                "height": "1459px"
            },
            "telephone": "+98-21-44002963",
            "address": "تهران، خیابان آیت ا... کاشانی، نبش خیابان عقیل، پلاک 380، طبقه دوم",
            "contactPoint" : [{
                "@type" : "ContactPoint",
                "telephone" : "+98-21-44002963",
                "contactType" : "customer service",
                "contactOption" : "TollFree",
                "areaServed" : "IR",
                "availableLanguage" : "Persian"
            }],
            "sameAs" : [
                "https://google.com/+ADMcoNet-GPlus",
                "https://www.linkedin.com/company/adm-amirkabir-data-miners-?trk=biz-companies-cym",
                "https://instagram.com/AmirkabirDataMiners/",
                "https://www.facebook.com/AmirkabirDataMiners",
                "http://www.pinterest.com/AmirkabirDM/",
                "https://twitter.com/AmirkabirDM",
                "https://www.youtube.com/channel/UCQxP0vZA05Pl9GlyXXQt14A/about"
            ]
        }
    </script>
    
    Login or Signup to reply.
  3. I haven’t tried it myself but PhantomJs would likely be the best option to be able to do this.

    You’ll need a dictionary of the endpoints your want to render and their corresponding static filepath names. You’d then iterate over each endpoint, rendering the given path with PhantomJS and then saving the output into the static file.

    From what I gather from your question, you haven’t actually used these paths on the front-end in your angular app as yet? If this is the case then I’d say that the other option is to actually render them server side via just Spring.

    The issue here is that angular is not made with isomorphism (client and server side rendering) in mind. Any proper rendering you want done on the server side that hasn’t been built yet, the best option is to use Spring to render it.

    Another option is updating to Angular2 which is isomorphic with the help of angular universal. If Spring is not used for rendering and only serves as an API for your app this option will work well.

    Login or Signup to reply.
  4. i didn’t done this in java but C#, please notify me if you make it work in java:

    i found that piece of code about phantomJs, and:

    as our friend said, we enabled html5 mode, we rewrite all the url in C# using write engine which is new to IIS, i keep one specific rule for google request which came with specific query parameter (couldn’t find it over net and not much time until work). so i redirect them to this specific page, i read the redirected url, passed it and run it on phantomJS, and wait for result to come back (need to know about running a process and take back the console result of it), then, we removed the ng-app attribute from the application, and pass the raw page to google crawler (we have two kind of redirect code, only one of them worked, at last till that time, one is permanent and other i temporary). the page for your self is so rude to look at, but google only look at your schema and structure, so everything is find with it.

    It’s long i didn’t been around Java, so i can’t implement it, i only regain little knowledge on spring, so i’ll appreciate if you notify me on any update.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search