I'm trying to add .css file to my index.html using Thymeleaf. But browser throws some strange errors:
GET http://localhost:8080/css/style.css net::ERR_ABORTED 404
And on server i got:
o.s.web.servlet.PageNotFound : No mapping for GET /css/style.css
Why it's happens? Also, it happens with all static components like .js and .css files. I have not any security. Please, help!
Sources:
WebConfig.java
#Configuration
#EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedMethods("*").allowedOrigins("*");
}
}
AdminPanel.java
#ConditionalOnProperty("app.is_debugging")
#Controller
public class AdminPanel {
#RequestMapping(value = { "/", "/index" }, method = RequestMethod.GET)
public String getIndex(Model model) {
return "index";
}
}
index.html
<!DOCTYPE HTML>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Custom messanger</title>
<link rel="stylesheet" type="text/css" th:href="#{/css/style.css}"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/3.0.0/handlebars.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/list.js/1.1.1/list.min.js"></script>
<!-- libs for stomp and sockjs-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.4.0/sockjs.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js"></script>
<!-- end libs for stomp and sockjs-->
<script type="text/javascript" th:src="#{/js/chat.js}"></script>
</head>
<body>
<div class="container clearfix">
<input type="text" id="name" placeholder="name">
<button onclick="createRoom()">Create room</button>
<input type="text" id="roomId" placeholder="roomId">
<button onclick="connectToTheRoom()">Connect</button>
<button onclick="connectToSocket()">Connect to socket</button>
<input type="text" id="message" placeholder="message">
<button onclick="sendMsg()">Send</button>
</div>
<div id="messagesList">
<a class="messagesConsole">Test msg1</a>
<a class="messagesConsole">Test msg2</a>
</div>
</body>
</html>
My file structure
Related
I'm trying to desingn login page by angular in my java Spring Boot Aplication. My problem is when I try login to panel page,username and password is ok and send to application by api controller and set user token correctly,but token don't set by cookeis in page, therefor panel page don't open and i have this error in inspect console :
my login page:
<!DOCTYPE html>
<html lang="en-US">
<head>
<title>Online Shop App | login</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
<script src="libs/angular.min.js"></script>
<script src="libs/jquery.min.js"></script>
<script src="libs/angular-cookies.js"></script>
<script src="scripts/app.js"></script>
<script src="scripts/controllers/loginController.js"></script>
<script src="scripts/services/ApiHandler.js"></script>
<link href="libs/bootstrap-5.1.3-dist/css/bootstrap.min.css" rel="stylesheet">
<script src="libs/bootstrap-5.1.3-dist/js/bootstrap.min.js"></script>
<link href="styles/login.css" rel="stylesheet">
</head>
<body ng-app="onlineShopApp">
<div class="container-fluid" ng-controller="loginCtrl">
<div class="row">
<div class="col-3"></div>
<div class="col login-box-holder">
<form>
<h3>Login To Panel</h3>
<div class="form-group">
<label for="username" class="form-label">Username</label>
<input type="text" class="form-control" id="username" ng-model="user.userName">
</div>
<div class="form-group">
<label for="password" class="form-label">Password</label>
<input type="password" class="form-control" id="password" autocomplete="false"
ng-model="user.password">
<div id="emailHelp" class="form-text">Do not share your username and password</div>
</div>
<button type="submit" class="btn btn-primary" ng-click="doLogin()">Login</button>
</form>
</div>
<div class="col-3"></div>
</div>
</div>
</body>
</html>
my login controller:
app.controller("loginCtrl", function ($scope, apiHandler, $cookies) {
$scope.user = {};
$scope.doLogin = () => {
apiHandler.callPost(
'user/login',
$scope.user,
(response) => {
var token=response.datalist[0].token;
$cookies.put("userToken",token);
if(token==null || token=="")
{
alert("invalid token");
return;
}
$cookies.put("uerToken",token);
alert("token is:");
location.href="/panel";
}, (error) => {
});
}
});
my panel page:
<!DOCTYPE html>
<html lang="en-US">
<head>
<title>Online Shop App | panel</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
<script src="libs/angular.min.js"></script>
<script src="libs/jquery.min.js"></script>
<script src="libs/angular-cookies.js"></script>
<script src="scripts/app.js"></script>
<script src="scripts/controllers/panelController.js"></script>
<script src="scripts/services/ApiHandler.js"></script>
<link href="libs/bootstrap-5.1.3-dist/css/bootstrap.min.css" rel="stylesheet">
<script src="libs/bootstrap-5.1.3-dist/js/bootstrap.min.js"></script>
</head>
<body ng-app="onlineShopApp">
<div class="container-fluid" ng-controller="panelCtrl">
<div class="row">
<h3>Panel</h3>
</div>
</div>
</body>
</html>
my panel controller:
app.controller("panelCtrl", function ($scope, apiHandler, $cookies) {
$scope.checkAccess = () => {
var token=$cookies.get("userToken");
if(token==undefined || token==null || token==""){
location.href="/login";
}
}
$scope.checkAccess();
});
i type wrong dataList in loginController file: (i change response.datalist[0] to=> response.dataList[0] )
We have a web application in which we need to show one header if we are logged in, and another one if we are not logged in. I would like to render these server side in a JSP file.
Here is my first attempt:
WebDelivery.java
package xyz.toold.cuebox.web;
import java.util.HashMap;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import org.glassfish.jersey.server.mvc.Viewable;
#Path("/")
public class WebDelivery {
#Path("/")
#GET
public Viewable index() {
HashMap<String, Object> model = new HashMap<>();
model.put("LoggedIn", true);
return new Viewable("/index", model);
}
#Path("/search/")
#GET
public Viewable search() {
return new Viewable("/search/index", true);
}
#Path("/user/")
#GET
public Viewable user() {
return new Viewable("/user/index");
}
#Path("/board/details/")
#GET
public Viewable boardDetails() {
return new Viewable("/board/details/index");
}
#Path("/board/")
#GET
public Viewable board() {
return new Viewable("/board/index");
}
#Path("/admin/")
#GET
public Viewable admin() {
return new Viewable("/admin/index");
}
}
index.jsp
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta http-equiv="Content-Security-Policy" content="default-src: https: 'unsafe-inline'" />
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="robots" content="index,follow" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="css/bulma.min.css">
<link rel="stylesheet" href="css/style.css">
<title>CueBox</title>
</head>
<body>
<%--TODO: Add logic to decide which header to set--%>
<c:if test="${model.LoggedIn}">
<jsp:include page="assets/partials/header-nologin-popups.jsp"/>
</c:if>
<section class="hero has-plant-image-background is-fullheight">
<div class="title-position">
<div class="hero-body">
<div class="container">
<h1 class="title-size has-text-white">NEW ERA OF<br/>FEEDBACK</h1>
<h2 class="hr subtitle-size has-text-white">GET YOUR FEEDBACK WITH EASE</h2>
</div>
</div>
</div>
</section>
<section class="section is-fullheight has-text-black has-background-grey-light has-text-centered">
<div class="column is-half is-offset-one-quarter">
<div class="hero-body">
<h1 class="title is-1">WHAT TO EXPECT</h1>
<hr class="line has-background-white">
</div>
</div>
<div class="hero-body">
<div class="container">
<div class="columns">
<div class="column">
<div class="content">
<i class="icon is-large fas fa-2x fa-comments"></i>
<h1 class="title is-size-4">Honest Feedback</h1>
<p class="is-size-5">The users can write anonymous posts, so it will be more honest.</p>
</div>
</div>
<div class="column">
<div class="content">
<i class="icon is-large fas fa-2x fa-cogs"></i>
<h1 class="title is-size-4">Easy administration</h1>
<p class="is-size-5">Don't waste time be configuring stupid settings.</p>
</div>
</div>
<div class="column">
<div class="content">
<i class="icon is-large fas fa-2x fa-users"></i>
<h1 class="title is-size-4">Scalable</h1>
<p class="is-size-5">CueBox works for living communities, small companies and lare groups.</p>
</div>
</div>
</div>
</div>
</div>
</section>
<jsp:include page="assets/partials/footer.html"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js" integrity="sha384-tsQFqpEReu7ZLhBV2VZlAu7zcOV+rXbYlF2cqB8txI/8aZajjp4Bqd+V6D5IgvKT" crossorigin="anonymous"></script>
<script defer src="https://use.fontawesome.com/releases/v5.3.1/js/all.js" integrity="sha384-kW+oWsYx3YpxvjtZjFXqazFpA7UP/MbiY4jvs+RWZo2+N94PFZ36T6TFkc9O3qoB" crossorigin="anonymous"></script>
<script src="js/main.js"></script>
<script src="js/validation.js"></script>
<script src="js/helper.js"></script>
</body>
</html>
The problem is my if never fires, so the header never gets shown. I know that the else is missing. I would have implemented it via having another if, which is inverted.
I also tried not passing a HashMap but a plain boolean, but it did not work either.
This is a link to my GitLab project.
What am I doing wrong, or is this entirely the wrong way to do it?
I'm pretty new in Spring boot and have some problems.
I have automobile and file, when I add automobile data and save it in db, want to upload the file which is connected to automobile by relationship OneToOne but when save automobile in #PostMapping("/saveAutomobile") I could't take this automobileId and to transfer it to #PostMapping("/uploadFile") to do the connection. Do you have any suggestions?
adding automobile:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head>
<div th:replace="fragments/links"></div>
<meta charset="UTF-8" />
<title>New Brand</title>
<link th:href="#{resources/css/bootstrap.min.css}" rel="stylesheet"></link>
</head>
<body>
<div class="container add shadow">
<h2>New Automobile</h2>
<form th:action="#{/automobile/saveAutomobile}" method="post"
th:object="${automobileForm}">
<div class="row">
<div class="column">
<div class="form-group shadow">
<label class="form-control-label" for="inputBrand"> Brand</label>
<input type="text"
class="form-control form-control-danger box-shadow"
id="inputBrand" th:field="*{brand}" name="brand"
required="required" />
</div>
<div class="form-group shadow">
<label class="form-control-label" for="inputModel"> Model</label>
<input type="text"
class="form-control form-control-danger box-shadow"
id="inputModel" th:field="*{model}" name="model"/>
</div>
</div>
<div style="text-align: center;">
<a th:href="#{/file/uploadFile} + ${automobile?.getId()}"> <input type="submit"
class="btn btn-default box-shadow shadow" />
</a>
</div>
</form>
</div>
<script th:src="#{resources/js/jquery-1.11.1.min.js}"></script>
<script th:src="#{resources/js/bootstrap.min.js}"></script>
</body>
</html>
#PostMapping("/saveAutomobile")
public String saveAutomobile(#Valid final AutomobileForm automobileForm, final BindingResult result) {
if (result.hasErrors()) {
LOG.error("SaveAutomobile Error: " + result);
return "automobile/add";
}
final Automobile automobile = automobileConverter.ConvertToEntity(automobileForm);
if (LOG.isDebugEnabled()) {
LOG.info("Saving client " + automobile);
}
automobileService.save(automobile);
automobileForm.setId(automobile.getId());
return "/files/uploadFile";
}
uploading file:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head>
<div th:replace="fragments/links"></div>
<meta charset="UTF-8" />
<meta name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1.0" />
<title>Upload automobile documentation</title>
<link th:href="#{resources/css/bootstrap.min.css}" rel="stylesheet"></link>
</head>
<body>
<div class="container upload shadow">
<h2>Upload automobile documentation</h2>
<form th:action="#{/uploadFile}" method="post"
enctype="multipart/form-data" id="singleUploadForm"
name="singleUploadForm" >
<div class="form-group shadow">
<label class="form-control-label" for="uploadfile">Upload
File:</label> <input id="singleFileUploadInput" type="file" name="file"
class="file-input form-control form-control-danger box-shadow" />
</div>
<button type="submit" class="btn btn-default box-shadow shadow"
id="btnSubmit">Upload</button>
</form>
<div class="upload-response">
<div id="singleFileUploadError"></div>
<div id="singleFileUploadSuccess"></div>
</div>
</div>
<script src="/js/main.js"></script>
</body>
</html>
#Autowired
private FileStorageService DBFileStorageService;
#PostMapping("/uploadFile")
public FileForm uploadFile(#RequestParam("file") MultipartFile file) {
File dbFile = DBFileStorageService.storeFile(file);
return new FileForm(dbFile.getFileName(),
file.getContentType(), file.getSize());
}
You can use models to store data and use it in your HTML page
for example:-
Controller.java
#GetMapping("/goToViewPage")
public ModelAndView passParametersWithModelAndView() {
ModelAndView modelAndView = new ModelAndView("viewPage");
modelAndView.addObject("message", "Hello from the controller");
return modelAndView;
}
Test.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Title</title>
</head>
<body>
<div>Web Application. Passed parameter : th:text="${message}"</div>
</body>
</html>
#PostMapping("/uploadFile")
public ResponseEntity<FileForm> uploadFile(#RequestParam("file") MultipartFile file) {
File dbFile = DBFileStorageService.storeFile(file);
FileForm fileForm = new FileForm(dbFile.getFileName(), file.getContentType(), file.getSize());
return new ResponseEntity<>(fileForm, HttpStatus.OK);
}
I have a problem with load a simple page where will be display all messages. I using algular for front-end and spring boot app in back-end. When i try to load page (localhost:8080/messages), page is blank and give me to download JSON with messages. Any idea? Ps. in ViewAllMessages.html i write constant text to check when page is running.
MessageController:
#RestController
#RequestMapping("/api/message")
public class MessageController {
private final Logger LOG = LoggerFactory.getLogger(MessageController.class);
#Autowired
private MessageService messageService;
#RequestMapping(value = "/all", method = GET)
public List<MessageDTO> findAll() {
LOG.info("Received request to all messages.");
return messageService.findAll();
}
}
main.js
var chatApp = angular.module('chat', ['ngRoute']);
chatApp.config(function ($routeProvider) {
$routeProvider
.when('/messages',
{
controller: 'AllMessagesController',
templateURL: '/partials/ViewAllMessages.html'
})
.otherwise( {redirectTo: '/'});
});
chatApp.service('messageService', function(){
var message = {};
var addMessage = function (v) {
message = v;
};
var getMessage = function(){
return message;
};
return {
addMessage: addMessage,
getMessage: getMessage
};
});
chatApp.controller('AllMessagesController', function($scope, $window, $http){
$scope.transfer = {};
$scope.error = false;
$http
.get('/api/message/all')
.then(function(response) {
$scope.messages = response.data;
log.console(response.data);
});
});
index.html
<!doctype html>
<html>
<link href="css/bootstrap.min.css" rel="stylesheet">
<link href="css/simple-sidebar.css" rel="stylesheet">
<link href="css/bootstrap-datetimepicker.css" rel="stylesheet">
<link href="css/office.css" rel="stylesheet">
<style type="text/css"> </style>
<body>
<script src="js/angular-route.min.js" type="text/javascript"></script>
<script src="js/angular-resource.min.js" type="text/javascript"></script>
<script src="js/main.js"></script>
<script src="js/angular.min.js" type="text/javascript"></script>
</body>
</html>
ViewAllMessages.html
<div class="container">
<div class="col-md-6">
<div class="row">
<div class="col-md-2">
<h2>Wiadomosci</h2>
</div>
</div>
</div>>
<div class="section">
<h3>{{headingTitle}}</h3>
<div>
<ul type="square">
<li>Luke</li>
<li>Darth</li>
<li>Anakin</li>
<li>Leia</li>
</ul>
</div>
</div>
<div class="panel panel-default" ng-repeat="message in messages">
<div class="row">
<div class="col-md-2">
<div class="panel-default"> {{message.id}}</div>
</div>
<div class="col-md-2">
<div class="panel-default"> {{message.message}}</div>
</div>
</div>>
</div>
</div>
page didn't show because you didn't import $routeParams dependency into your controller in index.js. After setting it, page shows up.
OK, I managed to get my application using Thymeleaf and now I need to reconstruct all the JSP pages into HTML5. First and foremost, I need to be able to login into the application using the username and password that worked very nicely on JSP.
My bean for assigning the HTML5 pages as the view layer is defined as:
#Bean
public ViewResolver viewResolver() {
ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver();
templateResolver.setTemplateMode("HTML5");
templateResolver.setCharacterEncoding("UTF-8");
templateResolver.setPrefix("/WEB-INF/html/");
templateResolver.setSuffix(".html");
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setTemplateResolver(templateResolver);
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(engine);
return viewResolver;
}
My LoginController is defined as:
#Controller
public class LoginController {
#Autowired
UserProfileService userProfileService;
#Autowired
UserService userService;
#RequestMapping(value = { "/", "/home" }, method = RequestMethod.GET)
public String homePage(ModelMap model) {
String user = getPrincipal();
model.addAttribute("greeting", "Hi, Welcome to HRM");
model.addAttribute("user", user);
model.addAttribute("roles", initializeProfiles());
return "welcome";
}
#RequestMapping(value = "/login", method = RequestMethod.GET)
public String loginPage() {
return "login";
}
#RequestMapping(value="/logout", method = RequestMethod.GET)
public String logoutPage (HttpServletRequest request, HttpServletResponse response) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null){
new SecurityContextLogoutHandler().logout(request, response, auth);
}
return "redirect:/login?logout";
}
private String getPrincipal(){
String userName = null;
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (principal instanceof UserDetails) {
userName = ((UserDetails)principal).getUsername();
} else {
userName = principal.toString();
}
return userName;
}
(...)
}
The old login.jsp is transcribed bellow:
<%# page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%#include file="include/include.jsp"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Login page</title>
<%#include file="include/imports.jsp"%>
</head>
<body>
<div id="mainWrapper">
<div class="login-container">
<div class="login-card">
<div class="login-form">
<c:url var="loginUrl" value="/login" />
<form action="${loginUrl}" method="post" class="form-horizontal">
<c:if test="${param.error != null}">
<div class="alert alert-danger">
<p>Invalid username and password.</p>
</div>
</c:if>
<c:if test="${param.logout != null}">
<div class="alert alert-success">
<p>You have been logged out successfully. </p>
</div>
</c:if>
<div class="input-group input-sm">
<label class="input-group-addon" for="username"><i class="fa fa-user"></i></label>
<input type="text" class="form-control" id="username" name="ssoId" placeholder="Enter Username" required>
</div>
<div class="input-group input-sm">
<label class="input-group-addon" for="password"><i class="fa fa-lock"></i></label>
<input type="password" class="form-control" id="password" name="password" placeholder="Enter Password" required>
</div>
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
<div class="form-actions">
<input type="submit"
class="btn btn-block btn-primary btn-default" value="Log in">
</div>
</form>
</div>
</div>
</div>
</div>
</body>
</html>
The new login.html is transcribed bellow:
<!DOCTYPE html><html>
<head>
<meta charset="utf-8"></meta>
<title>Login Page</title>
<meta name="description" content="login page" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<!-- <link rel="imports" href="include/imports.html" /> -->
<link rel="shortcut icon" href="assets/img/favicon.png"
type="image/x-icon" />
<link href="assets/css/bootstrap.min.css" rel="stylesheet" />
<link id="bootstrap-rtl-link" href="" rel="stylesheet" />
<link href="assets/css/font-awesome.min.css" rel="stylesheet" />
<link
href="http://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,400,600,700,300"
rel="stylesheet" type="text/css" />
<link id="beyond-link" href="assets/css/beyond.min.css" rel="stylesheet" />
<link href="assets/css/demo.min.css" rel="stylesheet" />
<link href="assets/css/animate.min.css" rel="stylesheet" />
<link id="skin-link" href="" rel="stylesheet" type="text/css" />
<script src="assets/js/skins.min.js" ></script>
<script src="assets/js/jquery-2.0.3.min.js"></script>
<script src="assets/js/bootstrap.min.js"></script>
<script src="assets/js/slimscroll/jquery.slimscroll.min.js"></script>
<script src="assets/js/beyond.js"></script>
</head>
<body>
<div class="login-container animated fadeInDown">
<div class="loginbox bg-white">
<div class="loginbox-title">SIGN IN</div>
<div class="loginbox-textbox">
<input type="text" class="form-control" placeholder="Username"></input>
</div>
<div class="loginbox-textbox">
<input type="password" class="form-control" placeholder="Password"></input>
</div>
<div class="loginbox-forgot">
Forgot Password?
</div>
<div class="loginbox-submit">
<input type="button" class="btn btn-primary btn-block" value="Login"></input>
</div>
<div class="loginbox-signup">
Sign Up With Email
</div>
</div>
</div>
</body>
</html>
I really am not familiar with how Thymeleaf and HTML5 handles requests. On the JSP form, the action was explicit and the submit type button or link would access the POST method on the controller and process the request. But how do I bind the view (Thymeleaf + HTML5) to the controller (Spring) layer?
Looking at your code, you have a form with both action and method attributes specified in your JSP template, but you're lacking a form entirely in your Thymeleaf template. You should be able to re-create the same form with either th:attr, th:action or th:method attributes. With properly mapped request, your controller should handle it no problem.
For more details, you can have a look at section 5 of Thymeleaf docs:
http://www.thymeleaf.org/doc/tutorials/2.1/usingthymeleaf.html#setting-attribute-values