I'm currently in the process of moving a small scale application to SpringBoot. We have legacy code and my hope is that by hooking the landing page into SpringBoot, I am able to let the JSP/JS files of the web application handle the rest.
Currently I've been successful rolling us up to Spring 5, and Using SpringBoot 2.1.8.
POM snippet: The application is using Tomcat defaults provided by Spring, and have pulled in the relevant Jasper/JSTL JARS so Tomcat can read
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
<exclusions>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
Per this DZone Article I have built a small controller to handle the login process
@Controller
public class LoginController {
@Resource
private UserSessionService userSessionService;
@GetMapping(value = "/")
public String index() {
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, "LoginController: Hit /, returning index.jsp");
return "index";
}
@GetMapping(value = "/login")
public String login() {
Logger.getLogger(this.getClass().getName())
.log(Level.SEVERE, "LoginController: Hit /login, returning login.jsp");
return "login";
}
@GetMapping(value = "/loginFailed")
public String loginError(Model model) {
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, "LoginController: Failed to login");
model.addAttribute("error", "true");
return "login";
}
@GetMapping(value = "/logout")
public String logout(SessionStatus session) {
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, "LoginController: Logging out");
SecurityContextHolder.getContext().setAuthentication(null);
session.setComplete();
return "redirect:/login";
}
@PostMapping(value = "/postLogin")
public String postLogin(Model model, HttpSession session) {
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, "LoginController: postLogin");
return "redirect:/";
}
}
login.jsp : legacy code, modified to call the controller. I'm attempting a best effort to let Spring Security handle the process of calling my AuthenticaionProvider and my DB (for the sake of brevity I'm only showing the critical area stuff, the page is rather simple anyway
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="security" uri="http://www.springframework.org/security/tags" %>
<c:set var="contextPath" value="${pageContext.request.contextPath}"/>
<!DOCTYPE html>
<html>
<head>
<%@page contentType="text/html" pageEncoding="UTF-8" %>
<link type="text/css" href="${contextPath}/css/login.css" rel="stylesheet"/>
<link rel="stylesheet" href="${contextPath}/css/font-awesome/css/font-awesome.min.css">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title></title>
</head>
<body class="loginBody">
.
.
<div class="formdiv">
<form name='f' action='doLogin' method='POST'>
<div style="width: 215px; margin: 0 auto; ">
<label class="loginLabel">Login</label><br>
<input type="text" name="username".../>
<label class="loginLabel">Password</label><br>
<input type="password" size="25" name="password".../><br>
<input type="submit" class="header_btn_class" value="Login" id="loginButton" style="..."/>
</div>
</form>
</div>
.
.
</body>
</html>
index.jsp: legacy code, handles the main landing page
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:set var="contextPath" value="${pageContext.request.contextPath}"/>
<%@include file="beforeHtml.jsp" %>
<html>
<head>
<%@include file="head.jsp" %>
<script type="text/javascript" src="${contextPath}/js/home/home.js"></script>
<title></title>
</head>
<body>
<%@include file="top.jsp" %>
<h2 style="margin-left: 60px;">Release Notes</h2>
<div id="changeLog" style=...">
</div>
<jsp:include page="../html/Changelog.html"/>
</body>
</html>
I have a file I've called SecurityConfig to let SpringBoot know to bypass the 'default' landing page:
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().antMatchers("/xxx").hasAnyRole("ADMIN", "USER")
.and()
.authorizeRequests().antMatchers("/login", "/resource/**").permitAll()
.and()
.formLogin().loginPage("/login").usernameParameter("username").passwordParameter("password").permitAll()
.loginProcessingUrl("/doLogin")
.successForwardUrl("/postLogin")
.failureUrl("/loginFailed")
.and()
.logout().logoutUrl("/doLogout").logoutSuccessUrl("/logout").permitAll()
.and()
.csrf().disable();
}
And I have these fields in my application.properties file
server.port=8888
server.servlet.context-path=/xxx
server.tomcat.additional-tld-skip-patterns=*mchange-commons-java*.jar
spring.mvc.view.prefix=/WEB-INF/view/jsp/
spring.mvc.view.suffix=.jsp
spring.mvc.servlet.load-on-startup=1
All of this put together allows me to login at my requested URL of localhost:8888/xxx/login
just fine, and logging in, watching the logs Spring finds my set up and logs in fine. The problem is when it goes to fetch the landing page which is a JSP file named index.jsp
. Per the logging by SpringBoot/Application
Oct 09, 2019 2:44:37 PM org.springframework.core.log.LogFormatUtils traceDebug
FINE: GET "/xxx/login", parameters={}
Oct 09, 2019 2:44:37 PM org.springframework.web.servlet.handler.AbstractHandlerMapping getHandler
FINE: Mapped to public java.lang.String com.rhdjapan.xxx.controllers.LoginController.login()
Oct 09, 2019 2:44:37 PM com.xx.xxx.controllers.LoginController login
SEVERE: LoginController: Hit /login, returning login.jsp
Oct 09, 2019 2:44:37 PM org.springframework.web.servlet.view.ContentNegotiatingViewResolver getBestView
FINE: Selected 'text/html' given [text/html,...]
Oct 09, 2019 2:44:37 PM org.springframework.web.servlet.view.AbstractView render
FINE: View name 'login', model {}
Oct 09, 2019 2:44:37 PM org.springframework.web.servlet.view.InternalResourceView renderMergedOutputModel
FINE: Forwarding to [/WEB-INF/view/jsp/login.jsp]
Oct 09, 2019 2:44:38 PM org.springframework.web.servlet.FrameworkServlet logResult
FINE: Completed 200 OK
Oct 09, 2019 2:44:42 PM com.xx.xxx.services.common.security.service.UserDetailsServiceImpl loadUserByUsername
SEVERE: loadUserByUsername: looking up user [admin]
Oct 09, 2019 2:44:42 PM com.xx.xxx.services.common.security.service.UserDetailsServiceImpl loadUserByUsername
SEVERE: loadUserByUsername: userId found = [1111111]
Oct 09, 2019 2:44:42 PM org.springframework.core.log.LogFormatUtils traceDebug
FINE: "FORWARD" dispatch for POST "/xxx/postLogin", parameters={username:[admin], password:[admin]}
Oct 09, 2019 2:44:42 PM org.springframework.web.servlet.handler.AbstractHandlerMapping getHandler
FINE: Mapped to public java.lang.String com.xx.xxx.controllers.LoginController.postLogin(org.springframework.ui.Model,javax.servlet.http.HttpSession)
Oct 09, 2019 2:44:42 PM com.xx.xxx.controllers.LoginController postLogin
SEVERE: LoginController: postLogin
Oct 09, 2019 2:44:42 PM org.springframework.web.servlet.view.AbstractView render
FINE: View name 'redirect:', model {}
Oct 09, 2019 2:44:42 PM org.springframework.web.servlet.FrameworkServlet logResult
FINE: Exiting from "FORWARD" dispatch, status 302
Oct 09, 2019 2:44:42 PM org.springframework.core.log.LogFormatUtils traceDebug
FINE: GET "/xxx/", parameters={}
Oct 09, 2019 2:44:42 PM org.springframework.web.servlet.handler.AbstractHandlerMapping getHandler
FINE: Mapped to public java.lang.String com.xx.xxx.controllers.LoginController.index()
Oct 09, 2019 2:44:42 PM com.xx.xxx.controllers.LoginController index
SEVERE: LoginController: Hit /, returning index.jsp
Oct 09, 2019 2:44:42 PM org.springframework.web.servlet.view.ContentNegotiatingViewResolver getBestView
FINE: Selected 'text/html' given [text/html, ...]
Oct 09, 2019 2:44:42 PM org.springframework.web.servlet.view.AbstractView render
FINE: View name 'index', model {}
Oct 09, 2019 2:44:42 PM org.springframework.web.servlet.view.InternalResourceView renderMergedOutputModel
FINE: Forwarding to [/WEB-INF/view/jsp/index.jsp]
Oct 09, 2019 2:44:42 PM org.springframework.web.servlet.FrameworkServlet logResult
FINE: Completed 200 OK
This is where the issue lies: while successful in finding the JSP file, the page is not rendered. I am returned an empty HTML file, and using the web debugger (chrome) only shows a source of 15 blanks lines. I presume its the length of my index.jsp
file;
My question is twofold
- What might be the cause of the HTML/JSP not rendering on my screen?
- If there is a fix, for all my other legacy JSP files I need to move to work under SpringBoot, will they all require a similar procedure?
Thanks!
Update For the sake of brevity, someone asked about the structure of my produced WAR, the structure is as such when I pull up the archive
WAR
|____css
|____dashboard_view
|____excel
|____images
|____jquery
|____js
|____jsp
|____META-INF
|____org
|____third-party
|____WEB-INF
|________classes
|________lib
|________view
|____________html
|____________jsp
|_________________index.jsp
|_________________login.jsp
Taking into account the login and index jsp files I provided, I wonder if something is failing silently somewhere during the rendering?