I am learning spring-security and created simple application to learn matchers. Unfortunately, I cannot get mvcMatchers to work. The other thing is that it works perfectly with antMatchers. Please see it's source below.
1) dependencies in pom.xml:
<dependencies>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.9.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
2) MvcWebApplicationInitializer:
public class MvcWebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SecurityConfig.class};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { MvcWebConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
3) MvcWebConfig
#Configuration
#EnableWebMvc
#ComponentScan("com.example.controller")
public class MvcWebConfig implements WebMvcConfigurer {
#Autowired
private ApplicationContext applicationContext;
#Bean
public SpringResourceTemplateResolver templateResolver() {
SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
templateResolver.setApplicationContext(applicationContext);
templateResolver.setPrefix("/WEB-INF/views/");
templateResolver.setSuffix(".html");
return templateResolver;
}
#Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver());
templateEngine.setEnableSpringELCompiler(true);
return templateEngine;
}
#Override
public void configureViewResolvers(ViewResolverRegistry registry) {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(templateEngine());
registry.viewResolver(resolver);
}
}
4) SecurityConfig:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN");
}
#Bean
public static NoOpPasswordEncoder passwordEncoder() {
return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/secured/**").hasRole("ADMIN")
//.mvcMatchers(HttpMethod.GET, "/secured/**").hasRole("ADMIN")
.anyRequest().permitAll()
.and()
.formLogin();
}
}
5) SecurityWebInitializer:
public class SecurityWebInitializer extends AbstractSecurityWebApplicationInitializer {}
6) MyController
#Controller
public class MyController {
#GetMapping("unsecured")
public String unsecured(Model model) {
model.addAttribute("message", "Unsecured");
return "index";
}
#GetMapping("secured/msg")
public String secured(Model model) {
model.addAttribute("message", "Secured");
return "index";
}
}
7) index.html is just simple Themeleaf template to output message
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="ISO-8859-1">
</head>
<body>
<p th:text="${message}"></p>
</body>
</html>
I package app as war, deploy it to Tomcat 9 application server, and open warname/unsecured and warname/secured/msg URLs and it works as expected (unsecured just outputs message 'unsecured', secured asks for login/password. After logging in it displays page with message 'secured'). When I comment antMatchers and uncomment mvcMatchers in SecurityConfig navigating to any of these 2 urls gives me standard 404 Tomcat page. I tried to provide mvcMatchers with different patterns, such as: /secured/msg, /secured/msg/, secured/msg, /secured/msg/*, and every time I got 404. While remote debugging of app I have found that it seems that mvcMatcher.match is not get called, while antMatcher.match is called during attemt to access warname/secured/msg page. Can you please tell me how I can make app to work with mvcMatchers the same way as it works now with antMatchers?
Try add annotation #PreAuthorized("hasRole('ADMIN')") abow your endpoints like this:
#PreAuthorized("hasRole('ADMIN')")
#GetMapping("secured/msg")
public String secured(Model model) {
model.addAttribute("message", "Secured");
return "index";
}
btw. You should use direct paths in mvcMatchers like:
mvcMatchers(HttpMeethod.GET, "/secured/msg"...)
Related
There are several similar questions on the site and on the web in general but I haven't been able to make them work in my example as much as I've tried.
I'm working with Spring Boot for the first time and I'm stuck trying to include JSP views via an InternalResourceViewResolver. I already got Thymeleaf views to work.
Application.java
#SpringBootApplication
#ComponentScan("controller")
#EnableWebSecurity
#Configuration
public class Application extends WebSecurityConfigurerAdapter {
public static void main(String args[]) {
SpringApplication.run(Application.class, args);
}
#Bean
public ITemplateResolver templateResolver() {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setPrefix("classpath:/templates/");
resolver.setSuffix(".html");
resolver.setTemplateMode(TemplateMode.HTML);
resolver.setCharacterEncoding("UTF-8");
resolver.setCacheable(false);
resolver.setOrder(1);
return resolver;
}
//intended for the .jsp view
#Bean
public InternalResourceViewResolver jspResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("classpath:/templates/jsp/");
resolver.setSuffix(".jsp");
resolver.setViewClass(JstlView.class);
resolver.setOrder(2);
return resolver;
}
#Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.addTemplateResolver(new UrlTemplateResolver());
templateEngine.addTemplateResolver(templateResolver());
//IKD if/how I should somehow add jspResolver() here
templateEngine.addDialect(new SpringSecurityDialect());
templateEngine.addDialect(new LayoutDialect(new GroupingStrategy()));
templateEngine.addDialect(new Java8TimeDialect());
return templateEngine;
}
#Bean
#Description("Thymeleaf View Resolver")
public ThymeleafViewResolver viewResolver() {
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(templateEngine());
viewResolver.setOrder(0);
return viewResolver;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/users/**").hasRole("USER")//USER role can access /users/**
.antMatchers("/admin/**").hasRole("ADMIN")//ADMIN role can access /admin/**
.antMatchers("/quests/**").permitAll()// anyone can access /quests/**
.anyRequest().authenticated()//any other request just need authentication
.and()
.formLogin();//enable form login
}
#Override
protected void configure(AuthenticationManagerBuilder builder) throws Exception {
builder.inMemoryAuthentication()
.passwordEncoder(passwordEncoder())
.withUser("tim").password(passwordEncoder().encode("123")).roles("ADMIN")
.and()
.withUser("joe").password(passwordEncoder().encode("234")).roles("USER");
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
MainController.java
#Controller
public class MainController {
#GetMapping("/")
ModelAndView index(Principal principal) {
ModelAndView mv = new ModelAndView("home");
if (principal != null) {
mv.addObject("message", principal.getName());
} else {
mv.addObject("message", "anon.");
}
return mv;
}
#GetMapping("/**")
String request(HttpServletRequest request, Model model) {
Authentication auth = SecurityContextHolder.getContext()
.getAuthentication();
ModelAndView mv = new ModelAndView("home");
model.addAttribute("uri", request.getRequestURI())
.addAttribute("user", auth.getName())
.addAttribute("roles", auth.getAuthorities());
return "html"; //<-- whenever I change this to return "jsp/jsp"; it breaks
}
html.html (Thymeleaf)
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<body>
<p>
URI: <h3 th:text="${uri}"></h3>
User: <h3 th:text="${user}"></h3>
Roles: <h3 th:text="${roles}"></h3>
/admin/<br/>
/users/<br/>
/others/<br/>
/quests/<br/><br/>
</p>
<form th:action="#{/logout}" method="post">
<input type="hidden"
name="${_csrf.parameterName}"
value="${_csrf.token}"/>
<input type="submit" value="Logout">
</form>
</body>
</html>
When I try to make this work with a JSP file well, the browswer only outputs
HTTP Status 500 ? Internal Server Error
and in NetBeans Output window, where gradle's task run is, well, running, the log shows this at the very top (the whole log is quite extensive):
2018-10-07 18:09:40.070 ERROR 6024 --- [nio-8080-exec-4] org.thymeleaf.TemplateEngine : [THYMELEAF][http-nio-8080-exec-4] Exception processing template "jsp/jsp": An error happened during template parsing (template: "class path resource [templates/jsp/jsp.html]")
JSP view I'm trying to include
<%#page contentType="text/html" pageEncoding="UTF-8"%>
<%#taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html lang="en">
<body>
<p>URI: ${uri} <br/>
User : ${user} <br/>
roles: ${roles} <br/><br/>
/admin/<br/>
/users/<br/>
/others/<br/>
/quests/<br/><br/>
</p>
<form action="/logout" method="post">
<input type="hidden"
name="${_csrf.parameterName}"
value="${_csrf.token}"/>
<input type="submit" value="Logout">
</form>
</body>
</html>
Finally, my project tree:
My assumption is that the app does not know about the file jsp.jsp inside folder templates/jsp, which is why I'm aiming the question to view resolvers, but as I said, I could easily be wrong about it.
This is just an example I'm trying to materialize and build on, so feel free to shred it with suggestions, thanx.
Just adding one more view resolver for jsp won't do,
we also need to add one more template resolver for jsp and connect it to spring template engine. JSP template resolver order must be the last, because it throws exception (smth like 'page not found') when can not resolve. The code below works in Spring Boot 2.
package org.jwebshop.webshop.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;
import org.thymeleaf.spring5.SpringTemplateEngine;
import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring5.view.ThymeleafViewResolver;
import org.thymeleaf.templatemode.TemplateMode;
import javax.annotation.Resource;
#Configuration
#EnableWebMvc
public class ViewConfiguration implements WebMvcConfigurer {
#Resource
protected ApplicationContext applicationContext;
#Resource
protected SpringTemplateEngine springTemplateEngine;
#Bean
public ThymeleafViewResolver thymeleafViewResolver(){
final ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setViewNames(new String[] {"thyme/*"});
viewResolver.setExcludedViewNames(new String[] {"jsp/*"});
viewResolver.setTemplateEngine(springTemplateEngine);
viewResolver.setCharacterEncoding("UTF-8");
return viewResolver;
}
#Bean
public InternalResourceViewResolver jspViewResolver(){
final InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
viewResolver.setViewNames("jsp/*");
return viewResolver;
}
#Bean
public SpringResourceTemplateResolver thymeleafTemplateResolver(){
final SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
templateResolver.setApplicationContext(applicationContext);
templateResolver.setPrefix("/WEB-INF/views/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode(TemplateMode.HTML);
templateResolver.setCacheable(false);
templateResolver.setOrder(0);
return templateResolver;
}
#Bean
public SpringResourceTemplateResolver jspTemplateResolver(){
final SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
templateResolver.setApplicationContext(applicationContext);
templateResolver.setPrefix("/WEB-INF/views/");
templateResolver.setSuffix(".jsp");
templateResolver.setTemplateMode(TemplateMode.HTML);
templateResolver.setCacheable(false);
templateResolver.setOrder(1);
templateResolver.setCharacterEncoding("UTF-8");
return templateResolver;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/webjars/**").addResourceLocations("/webjars/");
registry.addResourceHandler("/images/**").addResourceLocations("/images/");
registry.addResourceHandler("/css/**").addResourceLocations("/css/");
registry.addResourceHandler("/js/**").addResourceLocations("/js/");
}
}
package org.jwebshop.webshop.controller.web.thymeleaf;
import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
#Controller
public class RootController {
#Secured("ROLE_CUSTOMER")
#GetMapping({"/", "/index"})
public String root() {
return "thyme/index";
}
}
package org.jwebshop.webshop.controller.web.jsp;
import org.jwebshop.webshop.dto.converter.impl.UserDataConverter;
import org.jwebshop.webshop.dto.data.UserData;
import org.jwebshop.webshop.entity.User;
import org.jwebshop.webshop.service.UserService;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import javax.annotation.Resource;
#Controller
public class LuckyController {
#Resource
protected UserService userService;
#Resource
protected UserDataConverter userDataConverter;
#Secured("ROLE_CUSTOMER")
#GetMapping("/lucky")
public String hello(final Model model, final Authentication auth) {
final User user = userService.findByEmail(auth.getName());
final UserData userData = userDataConverter.convertFrom(user);
model.addAttribute("userData", userData);
return "jsp/lucky";
}
}
Folder structure:
webapp
|
WEB-INF
|
views
| |
jsp thyme
https://imgur.com/qOTgYZW
I haven't actually tried it yet, as I used jsp and thymeleaf on totally different project. And also converted jsp into thymeleaf, but not use it together. I just want to help, as I bump into this question and I find it interesting.
I assume you already checked this thread? Using both Thymeleaf and JSP
According to this blog, you can leave as is the default configuration of thymeleaf. You just need to add InternalResourceViewResolverfor the jsp configuration.
Full example here:
Add below dependencies to your pom.xml file
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
In your application.properties set thymeleaf view names and JSP
configuration for internal view resolution
spring.view.prefix:/WEB-INF/
spring.view.suffix:.jsp
spring.view.view-names:jsp/*
spring.thymeleaf.view-names:thymeleaf/*
create a configuration class for view resolution for JSP pages
package com.example.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;
#Configuration
public class JspConfig {
#Value("${spring.view.prefix}")
private String prefix;
#Value("${spring.view.suffix}")
private String suffix;
#Value("${spring.view.view-names}")
private String viewNames;
#Bean
InternalResourceViewResolver jspViewResolver() {
final InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix(prefix);
viewResolver.setSuffix(suffix);
viewResolver.setViewClass(JstlView.class);
viewResolver.setViewNames(viewNames);
return viewResolver;
}
}
I am very disappointed, I followed a tutorial on how to add Thymeleaf to a Spring MVC project but it doesn't even work with a 3-classes sample project. Thymeleaf cannot find my views and I don't know what I am missing.
Stacktrace :
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.thymeleaf.exceptions.TemplateInputException: An error happened during template parsing (template: "ServletContext resource [/WEB-INF/views/test.html]")
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:982)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:866)
javax.servlet.http.HttpServlet.service(HttpServlet.java:635)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:851)
javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
SpringMVCConfiguration.class
#Configuration
#ComponentScan({ "main.java" })
#EnableWebMvc
public class SpringMVCConfiguration implements WebMvcConfigurer {
#Autowired
private ApplicationContext applicationContext;
#Bean
public SpringResourceTemplateResolver templateResolver() {
SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
templateResolver.setApplicationContext(applicationContext);
templateResolver.setPrefix("/WEB-INF/views/");
templateResolver.setSuffix(".html");
return templateResolver;
}
#Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver());
templateEngine.setEnableSpringELCompiler(true);
return templateEngine;
}
#Override
public void configureViewResolvers(ViewResolverRegistry registry) {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(templateEngine());
registry.viewResolver(resolver);
}
}
DispatcherServletConfiguration.class
public class DispatcherServletConfiguration extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { SpringMVCConfiguration.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
TestController.class
#Controller
public class TestController {
#GetMapping("/test")
public String test(Model model) {
System.out.println("controller test");
return "test";
}
}
In Eclipse, the HTML file is located here :
-- Project
-- WebContent
-- WEB-INF
-- views
- test.html
test.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
</head>
<body>
<h1>TEST</h1>
</body>
</html>
To get off the ground running faster, I would suggest using spring-boot with its thyme-leaf starter. It handles most of the frustrating wiring code to avoid these issues.
https://www.mkyong.com/spring-boot/spring-boot-hello-world-example-thymeleaf/
Per your code, I'm guessing your component scan is wrong. Can you switch it from main.java to the root of your package hierarchy... whatever that is? Its probably the package name that the main.java file is in.
Also, maybe try moving your WEB-INF to src/main/web-app/WEB-INF?
I use Swagger 2 with non-spring-boot and I also can deploy my app on Tomcat and run it successfully. But the controller does not appear in swagger-ui.html, just the empty page with the green swagger title show up. I have spent two days on this issue. Would you give me some advice?
#Controller means the class as bellow:
#Api
#Controller
#RequestMapping("/user")
public class UserController {
protected Logger logger = LoggerFactory.getLogger(UserController.class);
#Autowired
private UserService userService;
#RequestMapping("/showInfos")
public #ResponseBody Object showUserInfos(){
logger.info("-----------------------showUserInfos-----------------------");
List<UserInfo> userInfos = userService.getUsers();
return userInfos;
}
my spring-mvc.xml configuration as follows:
<mvc:annotation-driven/>
<!#Controller inject bean -->
<context:component-scan base-package="com.roy.demo , version" />
<!-- Enables swgger ui -->
<mvc:resources mapping="swagger-ui.html" location="classpath:/META-INF/resources/" />
<mvc:resources mapping="/webjars/**" location="classpath:/META-INF/resources/webjars/" />
<!-- Include a swagger configuration -->
<bean name="/applicationSwaggerConfig" class="com.roy.demo.config.ApplicationSwaggerConfig" />
also my swagger configuration class is as follows:
#EnableSwagger2
public class ApplicationSwaggerConfig {
private static final Logger LOGGER = Logger.getLogger(ApplicationSwaggerConfig.class);
#Bean
public Docket api() {
LOGGER.info("################################ into Docket api() #####################################");
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("com.roy.demo.controller"))
.paths(PathSelectors.any())
.build();
}
}
my maven pom.xml swagger2 dependency as follows:
<!-- Swagger 2.0 -->
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-core</artifactId>
<version>1.5.3</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.5.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.5.0</version>
</dependency>
Bellow is the result when i enter the endpoint url:http://localhost:8080/Spring_SpringMVC_Mybatis/swagger-ui.html
I also new to Swagger but Below code I used for my swagger configuration and it works well for me.I done the configuration in class.
Configuration class.
#Configuration
#EnableWebMvc
#EnableSwagger2
#ComponentScan(basePackages = "com.*")
#PropertySource(value = { "classpath:log4j.properties" })
public class SpringConfig extends WebMvcConfigurerAdapter {
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()).directModelSubstitute(LocalDate.class, String.class).genericModelSubstitutes(ResponseEntity.class)
.useDefaultResponseMessages(false)
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build();
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
#SuppressWarnings("deprecation")
private ApiInfo apiInfo() {
ApiInfo apiInfo = new ApiInfo(
"API",
"API for xxxx",
"API TOS",
"Terms of service",
"xxx",
"License of API",
"");
return apiInfo;
}
}
Maven Dependency:
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.4.0</version>
</dependency>
Controller Class
#RestController
#Api(value="users", description="Endpoint for user management")
public class Controller {
}
endpointurl:
https://localhost:8080/AppName/swagger-ui.html
clear your browser cache and try again.
or use incognito tab
It worked well for me
It happened to me that one of the controllers was not displayed. The problem was the kotlin class has not declared any package. Declaring a package in the controller fixed the problem.
I am trying to integrate facelets with my Spring. I tried the folowing configuration but getting following error
SEVERE: Servlet.service() for servlet [springWebDispatcher] in context with path [/LS360ProxyAPIWeb] threw exception [Request processing failed; nested exception is javax.faces.FacesException: /WEB-INF/jsf/viewlogin.xhtml Not Found in ExternalContext as a Resource] with root cause
com.sun.faces.context.FacesFileNotFoundException: /WEB-INF/jsf/viewlogin.xhtml Not Found in ExternalContext as a Resource
Here what I did. First I added following maven dependencies to my project
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-api</artifactId>
<version>2.2.12</version>
</dependency>
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-impl</artifactId>
<version>2.2.12</version>
</dependency>
<dependency>
<groupId>org.springframework.webflow</groupId>
<artifactId>spring-faces</artifactId>
<version>2.4.2.RELEASE</version>
</dependency>
Then I added following lines in my startup
#Order(1)
public class FrameworkBootstrap implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext container) throws ServletException {
container.getServletRegistration("default").addMapping("/resource/*");
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(RootContextConfiguration.class);
container.addListener(new ContextLoaderListener(rootContext));
container.addListener(new RequestContextListener());
AnnotationConfigWebApplicationContext webContext = new AnnotationConfigWebApplicationContext();
webContext.register(WebServletContextConfiguration.class);
ServletRegistration.Dynamic dispatcher = container.addServlet("springWebDispatcher", new DispatcherServlet(webContext));
dispatcher.setLoadOnStartup(1);
dispatcher.setMultipartConfig(new MultipartConfigElement(null, 20_971_520L, 41_943_040L, 512_000));
dispatcher.addMapping("/");
container.setInitParameter("javax.faces.DEFAULT_SUFFIX", ".xhtml");
container.getServletRegistration("FacesServlet").addMapping("*.xhtml");
AnnotationConfigWebApplicationContext restContext = new AnnotationConfigWebApplicationContext();
....
AnnotationConfigWebApplicationContext soapContext = new AnnotationConfigWebApplicationContext();
...
}
}
In my WebServletContextConfiguration class I added the following view Resolver
#Configuration
#EnableWebMvc
#ComponentScan(
basePackageClasses = {WebControllerMarker.class},
useDefaultFilters = false,
includeFilters = #ComponentScan.Filter(WebController.class)
)
public class WebServletContextConfiguration extends WebMvcConfigurerAdapter {
....
/**
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setViewClass(JstlView.class);
resolver.setPrefix("/WEB-INF/jsp/view/");
resolver.setSuffix(".jsp");
return resolver;
}
*/
#Bean
public UrlBasedViewResolver faceletViewResolver() {
UrlBasedViewResolver resolver = new UrlBasedViewResolver();
resolver.setViewClass(JsfView.class);
resolver.setPrefix("/WEB-INF/jsf/view");
resolver.setSuffix(".xhtml");
return resolver;
}
....
}
I uncommented my JSP view. JSP view works fine when application runs. I also have spring security In my rootcontext.
#Configuration
#EnableLoadTimeWeaving
#ComponentScan(..)
#Import({SecurityConfiguration.class, ...})
public class RootContextConfiguration {
....
}
Spring Security
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(
prePostEnabled = true,
order = 0,
mode = AdviceMode.PROXY,
proxyTargetClass = false
)
public class SecurityConfiguration {
#Configuration
#ComponentScan(basePackageClasses = {FilterMarker.class})
#Order(1)
public static class RestApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
....
}
#Configuration
public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
#Override
public void configure(WebSecurity security) {
security.ignoring().antMatchers("/resources/**");
}
#Override
protected void configure(HttpSecurity security) throws Exception {
security
.authorizeRequests()
.antMatchers("/sso/cas/lf/**").hasAuthority("ROLE_ANONYMOUS")
// Any request simply requires authentication, regardless of permissions.
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/j_spring_security_check" )
.failureUrl("/login?loginFailed")
.defaultSuccessUrl("/interceptor.do")
.usernameParameter("username")
.passwordParameter("password")
.permitAll()
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/login?loggedOut")
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID")
.permitAll()
.and()
.sessionManagement()
.sessionFixation()
.changeSessionId()
.maximumSessions(1)
.maxSessionsPreventsLogin(true)
.sessionRegistry(this.sessionRegistryImpl())
.and()
.and()
.csrf()
.disable();
}
}
I added following faces-config.xml in my WEB-INF
<?xml version="1.0" encoding="UTF-8"?>
<faces-config
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd"
version="2.2">
<application>
<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
</application>
</faces-config>
I added following login.xhtml page in my WEB-INF/jsf/view/login.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<h:head>
<title>JSF Spring Integration Example</title>
</h:head>
<h:body>
<h3>Item Master</h3>
</h:body>
</html>
Then I ran my project but getting error. What I am doing wrong and what I am missing ?
Thanks
The problem is the that tiles configuration is not getting applied
everytime.
I have integrated Apache tiles 3 with spring MVC. I have used annotation based configuration of spring. The problem in the application is that the tiles definitions get applied on random basis. When I try to run the application, the tiles configuration that we have configured may or may not get applied.
I am using Apache tomcat 7. Is this problem related with server? Is this problem related with Configuration? Or If Any.
Here is my Code
MVC Configuration
Annotation base Java Configuration using Spring
#EnableWebMvc
#Configuration
#ComponentScan(basePackages = { "com.om.*" })
public class MVCConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
#Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/views/layout/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
#Bean
public TilesViewResolver getTilesViewResolver() {
TilesViewResolver tilesViewResolver = new TilesViewResolver();
tilesViewResolver.setViewClass(TilesView.class);
return tilesViewResolver;
}
#Bean
public TilesConfigurer getTilesConfigurer() {
TilesConfigurer tilesConfigurer = new TilesConfigurer();
tilesConfigurer.setCheckRefresh(true);
tilesConfigurer.setDefinitionsFactoryClass(TilesDefinitionsConfig.class);
// Add apache tiles definitions
TilesDefinitionsConfig.addDefinitions();
return tilesConfigurer;
}
}
MVCInitializer
public class MVCInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { MVCConfig.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
TilesDefinitionsConfig
public final class TilesDefinitionsConfig implements DefinitionsFactory {
private static final Map<String, Definition> tilesDefinitions = new HashMap<String,Definition>();
private static final Attribute BASE_TEMPLATE = new Attribute("/WEB-INF/views/layout/defaultLayout.jsp");
public Definition getDefinition(String name, Request tilesContext) {
System.out.println("3");
return tilesDefinitions.get(name);
}
/**
* #param name <code>Name of the view</code>
* #param title <code>Page title</code>
* #param body <code>Body JSP file path</code>
*
* <code>Adds default layout definitions</code>
*/
private static void addDefaultLayoutDef(String name, String title, String body) {
Map<String, Attribute> attributes = new HashMap<String,Attribute>();
attributes.put("title", new Attribute(title));
attributes.put("header", new Attribute("/WEB-INF/views/layout/header.jsp"));
attributes.put("menu", new Attribute("/WEB-INF/views/layout/menu.jsp"));
attributes.put("body", new Attribute(body));
attributes.put("footer", new Attribute("/WEB-INF/views/layout/footer.jsp"));
tilesDefinitions.put(name, new Definition(name, BASE_TEMPLATE, attributes));
}
/**
* <code>Add Apache tiles definitions</code>
*/
public static void addDefinitions(){
addDefaultLayoutDef("welcome", "welcome", "/WEB-INF/views/layout/welcome.jsp");
addDefaultLayoutDef("personList", "viewPerson", "/WEB-INF/views/layout/personList.jsp");
}
}
Controller
#Controller
public class SpringTilesController {
#RequestMapping(value="welcome")
public ModelAndView index() {
ModelAndView model=new ModelAndView();
System.out.println("In Controller");
model.setViewName("welcome");
return model;
}
#RequestMapping(value="viewPerson")
public ModelAndView viewPersons(Model model) {
Map<String, List<Person>> persons =
new HashMap<String, List<Person>>();
persons.put("persons", Person.createPersons());
return new ModelAndView("personList", persons);
}
}
Entity
public class Person {
private String name, email;
private int age;
public Person(String name, String email, int age) {
this.name = name;
this.email = email;
this.age = age;
}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public String getEmail() {return email;}
public void setEmail(String email) {this.email = email;}
public int getAge() {return age;}
public void setAge(int age) {this.age = age;}
#Override
public String toString()
{
return String.format(
"Person [name = %s, email = %s, age = %d]",
name, email, age);
}
public static List<Person> createPersons() {
List<Person> persons = new ArrayList<Person>();
persons.add(new Person("Tousif", "tousif#mail.com", 32));
persons.add(new Person("Asif", "asif#mail.com", 28));
persons.add(new Person("Ramiz", "ramiz#mail.com", 26));
persons.add(new Person("Rizwan", "rizwan#mail.com", 32));
persons.add(new Person("Amol", "amol#mail.com", 33));
persons.add(new Person("Ramdas", "ramdas#mail.com", 31));
return persons;
}
}
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.om</groupId>
<artifactId>TilesDemo</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>TilesDemo Maven Webapp</name>
<url>http://maven.apache.org</url>
<properties>
<jdk.version>1.7</jdk.version>
<spring.version>4.1.6.RELEASE</spring.version>
<spring.security.version>4.0.1.RELEASE</spring.security.version>
<jstl.version>1.2</jstl.version>
<javax.servlet.version>3.1.0</javax.servlet.version>
<mysql.connector.version>5.1.31</mysql.connector.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<!-- jstl for jsp page -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>${jstl.version}</version>
</dependency>
<!-- Apache Tiles -->
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-api</artifactId>
<version>3.0.5</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-core</artifactId>
<version>3.0.5</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-jsp</artifactId>
<version>3.0.5</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-servlet</artifactId>
<version>3.0.5</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-template</artifactId>
<version>3.0.5</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-el</artifactId>
<version>3.0.5</version>
<scope>compile</scope>
</dependency>
<!-- Spring 4 dependencies -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
<build>
<finalName>TilesDemo</finalName>
</build>
</project>
Keep The header,footer,menu as per the requirements.
This is defaultLayout.jsp page
<%# taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles"%>
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<html>
<head>
<title><tiles:insertAttribute name="title" ignore="true"></tiles:insertAttribute></title>
</head>
<body style="background-color: #FFF">
<div class="page">
<tiles:insertAttribute name="header" />
<div class="content">
<div id="body">
<tiles:insertAttribute name="body" />
</div>
</div>
<tiles:insertAttribute name="footer" />
</div>
</body>
</html>
footer.jsp
<hr />
<div class="span-1 prepend-3"> </div>
<div class="span-16 last">
<p>
<b> Technology</b>
( All rights Reserved)
</p>
</div>
header.jsp
<div class="span-24">
<img src="resources/images/images.png"
width="950" style="padding-top:10px;" />
</div>
menu.jsp
Left side menu bar options
<%# taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<ul style="list-style:none;line-height:28px;">
<li><spring:url value="/index" var="homeUrl" htmlEscape="true" />
Home
</li>
<li><spring:url value="/viewPerson" var="personListUrl" htmlEscape="true" />
Person List
</li>
</ul>
welcome.jsp
This is the body Page on which header, footer and menu will be applied.
<div style="margin:10px;">
<h3>SpringMVC - Tiles3 Integration tutorial</h3>
<p>By:- XYZ</p>
</div>
The problem is the that tiles configuration is not getting applied everytime.
As you can see in this project Tiles configuration without xml the developer had a similar problem, the tiles configuration isn't working.
He found that if you call the view with the same name of the file.jsp, somethings going bad.
public static void addDefinitions(){
addDefaultLayoutDef("welcome", "welcome", "/WEB-INF/views/layout/welcome.jsp");
addDefaultLayoutDef("personList", "viewPerson", "/WEB-INF/views/layout/personList.jsp");
}
Try to use different name for the view and the file.jsp.
Try with
addDefaultLayoutDef("welcome", "Welcome", "/WEB-INF/views/layout/welcome.jsp");
Should work if the rest of the code is correct.
Maybe you need to define the view resolver's order precedence, something like this:
#Bean
public InternalResourceViewResolver internalResourceViewResolver(){
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setViewClass(JstlView.class);
resolver.setPrefix("/WEB-INF/pages/");
resolver.setSuffix(".jsp");
//resolver.setOrder(2);
return resolver;
}
//configuracion de apache tiles
#Bean
public TilesViewResolver getTilesViewResolver() {
TilesViewResolver tilesViewResolver = new TilesViewResolver();
tilesViewResolver.setViewClass(TilesView.class);
// tiles view resolver va ha ser el primero en mostrarse
tilesViewResolver.setOrder(1);
return tilesViewResolver;
}