This application has no explicit mapping for /error, so you are seeing this as a fallback. Thymeleaf parsing exception in spring boot
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.
CoderPJ
Updated on June 04, 2022Comments
-
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">×</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 over 7 yearsI 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 over 7 yearsits 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"/>
andbr
andhr
like<br/>
and<hr/>
and so on... also some special character like&
where you use&
-
CoderPJ over 7 yearsI've shared the code for the login page. Please go through it
-
kukkuz over 7 yearsyou have an extra
div
close tag at the end.. pls check -
Shawn Clark over 7 yearsThere 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 over 7 yearsThank you! And how do I specify an external css link in case of XHTML?
-
Shawn Clark over 7 yearsw3schools.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>