This application has no explicit mapping for /error, so you are seeing this as a fallback. Thymeleaf parsing exception in spring boot

10,005

Welcome to Thymeleaf!

Thymeleaf requires strict XHTML syntax.

As the error clearly suggest:

org.xml.sax.SAXParseException: 
The element type "link" must be terminated by the matching end-tag "</link>".

Your page has a link element that you have not closed.

Share:
10,005
CoderPJ
Author by

CoderPJ

Updated on June 04, 2022

Comments

  • CoderPJ
    CoderPJ almost 2 years

    I am trying to make a login application using spring boot. I tried securing the page using Spring Security using Thymeleaf. I created a sample login page which appears like this.

    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml"
     xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
    <head>
    <title>Spring Security Example</title>
    </head>
    <body>
    <div th:if="${param.error}">
    Invalid username and password.
    </div>
    <div th:if="${param.logout}">
    You have been logged out.
    </div>
    <form th:action="@{/login}" method="post">
    <div><label> User Name : <input type="text" name="username"/> </label></div>
    <div><label> Password: <input type="password" name="password"/> </label></div>
     <div><input type="submit" value="Sign In"/></div>
    </form>
    </body>
    </html>
    

    This Code worked fine and I was able to move to the login page. But when I created a new login page using HTML5 and tried running the code, it displayed an error like this

    org.xml.sax.SAXParseException: The element type "link" must be terminated by the matching end-tag "</link>".
        at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source) [na:1.8.0_101]
        at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.fatalError(Unknown Source) [na:1.8.0_101]
        at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(Unknown Source) [na:1.8.0_101]
        at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(Unknown Source) [na:1.8.0_101]
        at com.sun.org.apache.xerces.internal.impl.XMLScanner.reportFatalError(Unknown Source) [na:1.8.0_101]
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanEndElement(Unknown Source) [na:1.8.0_101]
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(Unknown Source) [na:1.8.0_101]
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(Unknown Source) [na:1.8.0_101]
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source) [na:1.8.0_101]
        at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source) [na:1.8.0_101]
        at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source) [na:1.8.0_101]
        at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source) [na:1.8.0_101]
        at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(Unknown Source) [na:1.8.0_101]
        at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source) [na:1.8.0_101]
        at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl.parse(Unknown Source) [na:1.8.0_101]
        at org.thymeleaf.templateparser.xmlsax.AbstractNonValidatingSAXTemplateParser.doParse(AbstractNonValidatingSAXTemplateParser.java:209) [thymeleaf-2.1.5.RELEASE.jar!/:2.1.5.R
    

    The Code for login page is as follows:-

    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
    <head>
    <meta charset="utf-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
    
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <meta name="description" content="Xenon Boostrap Admin Panel"/>
    <meta name="author" content=""/>
    
    <title>Login</title>
    
    <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Arimo:400,700,400italic" media="screen"/>
    <link rel="stylesheet" href="/static/css/fonts/linecons/css/linecons.css" th:href="@{/static/css/fonts/linecons/css/linecons.css}" media="screen"/>
    <link rel="stylesheet" href="/static/css/fonts/fontawesome/css/font-awesome.min.css" th:href="@{/static/css/fonts/fontawesome/css/font-awesome.min.css}" media="screen"/>
    <link rel="stylesheet" href="/static/css/bootstrap.css" th:href="@{/static/css/bootstrap.css}" media="screen"/>
    <link rel="stylesheet" href="/static/css/xenon-core.css" th:href="@{/static/css/xenon-core.css}" media="screen"/>
    <link rel="stylesheet" href="/static/css/xenon-forms.css" th:href="@{/static/css/xenon-forms.css}" media="screen"/>
    <link rel="stylesheet" href="/static/css/xenon-components.css" th:href="@{/static/css/xenon-components.css}" media="screen"/>
    <link rel="stylesheet" href="/static/css/xenon-skins.css" th:href="@{/static/css/xenon-skins.css}" media="screen"/>
    <link rel="stylesheet" href="/static/css/custom.css" th:href="@{/static/css/custom.css}" media="screen"/>
    
    <script th:src="@{/static/js/jquery-1.11.1.min.js}" src="/static/js/jquery-1.11.1.min.js"></script>
    
    </head>
    <body class="page-body login-page login-light">
    <div class="login-container">
    
        <div class="row">
    
            <div class="col-sm-6">
    
                <script type="text/javascript">
                    jQuery(document).ready(function($)
                    {
                        // Reveal Login form
                        setTimeout(function(){ $(".fade-in-effect").addClass('in'); }, 1);
    
    
                        // Validation and Ajax action
                        $("form#login").validate({
                            rules: {
                                username: {
                                    required: true
                                },
    
                                passwd: {
                                    required: true
                                }
                            },
    
                            messages: {
                                username: {
                                    required: 'Please enter your username.'
                                },
    
                                passwd: {
                                    required: 'Please enter your password.'
                                }
                            },
    
                            // Form Processing via AJAX
                            submitHandler: function(form)
                            {
                                show_loading_bar(70); // Fill progress bar to 70% (just a given value)
    
                                var opts = {
                                    "closeButton": true,
                                    "debug": false,
                                    "positionClass": "toast-top-full-width",
                                    "onclick": null,
                                    "showDuration": "300",
                                    "hideDuration": "1000",
                                    "timeOut": "5000",
                                    "extendedTimeOut": "1000",
                                    "showEasing": "swing",
                                    "hideEasing": "linear",
                                    "showMethod": "fadeIn",
                                    "hideMethod": "fadeOut"
                                };
    
                                $.ajax({
                                    url: "data/login-check.php",
                                    method: 'POST',
                                    dataType: 'json',
                                    data: {
                                        do_login: true,
                                        username: $(form).find('#username').val(),
                                        passwd: $(form).find('#passwd').val()
                                    },
                                    success: function(resp)
                                    {
                                        show_loading_bar({
                                            delay: .5,
                                            pct: 100,
                                            finish: function(){
    
                                                // Redirect after successful login page (when progress bar reaches 100%)
                                                if(resp.accessGranted)
                                                {
                                                    window.location.href = 'dashboard-2.html';
                                                }
                                            }
                                        });
    
    
                                        // Remove any alert
                                        $(".errors-container .alert").slideUp('fast');
    
    
                                        // Show errors
                                        if(resp.accessGranted == false)
                                        {
                                            $(".errors-container").html('<div class="alert alert-danger">\
                                                <button type="button" class="close" data-dismiss="alert">\
                                                    <span aria-hidden="true">&times;</span>\
                                                    <span class="sr-only">Close</span>\
                                                </button>\
                                                ' + resp.errors + '\
                                            </div>');
    
    
                                            $(".errors-container .alert").hide().slideDown();
                                            $(form).find('#passwd').select();
                                        }
                                    }
                                });
    
                            }
                        });
    
                        // Set Form focus
                        $("form#login .form-group:has(.form-control):first .form-control").focus();
                    });
                </script>
    
                <!-- Errors container -->
                <div class="errors-container">
    
                </div>
    
                <!-- Add class "fade-in-effect" for login form effect -->
                <form th:action="@{/extra-login-light}" method="post" role="form" id="login" class="login-form fade-in-effect" autocomplete="on">
    
                    <div class="login-header">
                        <a href="dashboard-2.html" th:href="@{/dashboard-2.html}">
                            <img th:src="@{/static/images/white.jpg}" src="/static/images/white.jpg" alt="" height="" width="180" class="logo"/>
                            <img th:src="@{/static/images/xm_lockup.png}" src="/static/images/xm_lockup.png" alt="" height="45" width="220" class="logonew"/>
                        </a>
    
                        <p>Dear user, log in to access the admin area!</p>
                    </div>
    
    
                    <div class="form-group">
                        <label class="control-label" for="username">Username</label>
                        <input type="text" class="form-control" name="username" id="username" autocomplete="off"/>
                    </div>
    
                    <div class="form-group">
                        <label class="control-label" for="passwd">Password</label>
                        <input type="password" class="form-control" name="password" id="passwd" autocomplete="off"/>
                    </div>
    
                    <div class="form-group">
                        <button type="submit" class="btn btn-primary  btn-block text-left">
                            <i class="fa-lock"></i>
                            Log In
                        </button>
                    </div>
    
                    <div class="login-footer">
                        <a href="#">Forgot your password?</a>
    
                        <div class="info-links">
                            <a href="#">ToS</a> -
                            <a href="#">Privacy Policy</a>
                        </div>
    
                    </div>
    
                </form>
    
                <!-- Facebook Login
                <div class="external-login">
                    <a href="#" class="facebook">
                        <i class="fa-facebook"></i>
                        Facebook Login
                    </a>
                    -->
    
                    <!-- 
                    <a href="<?php _hash(); ?>" class="twitter">
                        <i class="fa-twitter"></i>
                        Login with Twitter
                    </a>
    
                    <a href="<?php _hash(); ?>" class="gplus">
                        <i class="fa-google-plus"></i>
                        Login with Google Plus
                    </a>
                     -->
            </div>
    
        </div>
    
    </div>
    
    <!-- Bottom Scripts -->
    <script src="/static/js/bootstrap.min.js"></script>
    <script src="/static/js/TweenMax.min.js"></script>
    <script src="/static/js/resizeable.js"></script>
    <script src="/static/js/joinable.js"></script>
    <script src="/static/js/xenon-api.js"></script>
    <script src="/static/js/xenon-toggles.js"></script>
    <script src="/static/js/jquery-validate/jquery.validate.min.js"></script>
    <script src="/static/js/toastr/toastr.min.js"></script>
    
    
    <!-- JavaScripts initializations and stuff -->
    <script src="/static/js/xenon-custom.js"></script>
    
    </body>
    </html>
    

    The error on the server appears like this Error after trying to redirect to the new login page I don't understand what the problem is. Why am I getting this error? I am using annotations and not the pom.xml file.

    Also the css files aren't loading. My project structure appears like this:- Project structure

    Please go through the picture and the code again to find out to what is wrong.

  • CoderPJ
    CoderPJ over 7 years
    I did as you said and it works fine. I've been doing it for all the tags now. I have now encountered another problem, and this time it is the body tag. I have the tag enclosed like this </body>. Yet, it throws this Exeception org.xml.sax.SAXParseException: The element type "body" must be terminated by the matching end-tag "</body>".
  • kukkuz
    kukkuz over 7 years
    its not because of the body tag. make sure you check for all elements that you have not closed for instance: image like <img src="/image.png"/> , input like <input type="text"/> and br and hr like <br/> and <hr/> and so on... also some special character like & where you use &amp;
  • CoderPJ
    CoderPJ over 7 years
    I've shared the code for the login page. Please go through it
  • kukkuz
    kukkuz over 7 years
    you have an extra div close tag at the end.. pls check
  • Shawn Clark
    Shawn Clark over 7 years
    There are HTML5 validators available on the internet to check your code. Check out html5.validator.nu as an example. That validator gave 33 issues with a number of them being errors and others being warnings.
  • CoderPJ
    CoderPJ over 7 years
    Thank you! And how do I specify an external css link in case of XHTML?
  • Shawn Clark
    Shawn Clark over 7 years
    w3schools.com/tags/tag_link.asp ... same as you normally do but you have to close the tag with an ending /> or by a full </link>