【发布时间】:2018-09-03 18:00:33
【问题描述】:
我在 Spring Boot 中遇到控制器映射问题。 添加 Spring-JPA 依赖项后,我的映射不再起作用。
- 删除 spring-boot-starter-data-jpa 依赖项会有所帮助,但 JPA 的使用是有意的
- 控制器类位于包含main方法的类下的子包中
- 应用程序启动并且没有抛出异常。与数据库的连接也正常
添加JPA依赖时的映射:
2018-03-25 16:02:14.550 INFO 1820 --- [ restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2018-03-25 16:02:14.551 INFO 1820 --- [ restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
移除 JPA 依赖后的映射(预期如何):
2018-03-25 16:28:35.907 INFO 1032 --- [ restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/ || /index],methods=[GET]}" onto public java.lang.String com.aggrogator.controller.frontend.HomeController.getHome(org.springframework.ui.Model)
2018-03-25 16:28:35.909 INFO 1032 --- [ restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/login],methods=[GET || POST]}" onto public java.lang.String com.aggrogator.controller.frontend.HomeController.postLogin(com.aggrogator.model.Login)
2018-03-25 16:28:35.920 INFO 1032 --- [ restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2018-03-25 16:28:35.921 INFO 1032 --- [ restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
Pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>Aggrogator</artifactId>
<version>${version.number}</version>
<packaging>jar</packaging>
<name>Aggrogator</name>
<description>News-Aggregator</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<version.number>${git.commit.id.abbrev}</version.number>
<master.branch>latest</master.branch>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Thymeleaf -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-web-starter</artifactId>
<version>1.4.0-RC2</version>
</dependency>
<!-- Shiro uses SLF4J for logging. We'll use the 'simple' binding
in this example app. See http://www.slf4j.org for more info. -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.6.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
</dependencies>
<!--Import other Plugins for feature-branches or master-branch-->
<profiles>
<profile>
<id>default</id>
<build>
<plugins>
<plugin>
<groupId>com.spotify</groupId>
<artifactId>dockerfile-maven-plugin</artifactId>
<version>1.4.0</version>
<executions>
<execution>
<id>default</id>
<goals>
<goal>build</goal>
<goal>push</goal>
</goals>
</execution>
</executions>
<configuration>
<repository>damian.space:81/aggrogator/aggrogator</repository>
<tag>${version.number}</tag>
<buildArgs>
<JAR_FILE>${project.build.finalName}.jar</JAR_FILE>
</buildArgs>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>master</id>
<build>
<plugins>
<plugin>
<groupId>com.spotify</groupId>
<artifactId>dockerfile-maven-plugin</artifactId>
<version>1.4.0</version>
<executions>
<execution>
<id>default</id>
<goals>
<goal>build</goal>
<goal>push</goal>
</goals>
</execution>
</executions>
<configuration>
<repository>damian.space:81/aggrogator/aggrogator</repository>
<tag>latest</tag>
<buildArgs>
<JAR_FILE>${project.build.finalName}.jar</JAR_FILE>
</buildArgs>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
<version>2.2.1</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>revision</goal>
</goals>
</execution>
</executions>
<configuration>
<dateFormat>yyyyMMdd-HHmmss</dateFormat><!-- human-readable part of the version number -->
<dotGitDirectory>${project.basedir}/.git</dotGitDirectory>
<generateGitPropertiesFile>false</generateGitPropertiesFile><!-- somehow necessary. otherwise the variables are not available in the pom -->
</configuration>
</plugin>
</plugins>
</build>
</project>
应用:
package com.aggrogator;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
public class AggrogatorApplication {
public static void main(String[] args) {
SpringApplication.run(AggrogatorApplication.class, args);
}
}
控制器:
package com.aggrogator.controller.frontend;
import com.aggrogator.model.Login;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
@Controller
public class HomeController {
// Important for @ModelAttribute to work below!
@ModelAttribute("login")
public Login getLoginObject() {
return new Login();
}
@RequestMapping(value = {"/", "/index"}, method = RequestMethod.GET)
@RequiresRoles(logical = Logical.OR, value = {"admin","emperor"})
public String getHome(Model model){
return "index";
}
@RequestMapping(value = "/login", method = {RequestMethod.GET, RequestMethod.POST})
public String postLogin(@ModelAttribute("login") Login login){
return "login";
}
}
Application.properties:
shiro.loginUrl = /login
# Let Shiro Manage the sessions
shiro.userNativeSessionManager = true
# disable URL session rewriting
shiro.sessionManager.sessionIdUrlRewritingEnabled = false
spring.datasource.url=jdbc:mysql://localhost:3306/aggrogator
spring.datasource.username=user
spring.datasource.password=pw
spring.datasource.testWhileIdle = true
spring.datasource.validationQuery = SELECT 1
spring.jpa.show-sql = true
spring.jpa.hibernate.ddl-auto = update
spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
提前感谢您的帮助!
更新
了解更多信息 如果我添加依赖项“shiro-spring”而不是“shiro-spring-boot-web-starter”,则会添加映射,但应请求引发以下异常:
org.apache.shiro.UnavailableSecurityManagerException: No SecurityManager accessible to the calling code, either bound to the org.apache.shiro.util.ThreadContext or as a vm static singleton. This is an invalid application configuration.
这个异常显然是抛出的,因为在处理 html 模板中的 shiro 标签时没有找到 SecurityManager。删除 shiro 标记不再抛出此异常,但没有安全功能起作用(所有站点均可访问)。
经过一番摆弄,我能够通过向 Shiro 配置添加一些 Bean(仍然使用 shiro-spring 依赖项)来重现前面提到的问题。这也是重现缺少映射问题的最低配置:
package com.aggrogator.configuration;
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import org.apache.shiro.authc.credential.DefaultPasswordService;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.cache.MemoryConstrainedCacheManager;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.realm.text.PropertiesRealm;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
import org.apache.shiro.spring.web.config.ShiroWebConfiguration;
import org.apache.shiro.spring.web.config.ShiroWebFilterConfiguration;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
@Configuration
public class ShiroConfig {
@Bean
public Realm realm() {
// uses 'classpath:shiro-users.properties' by default
PropertiesRealm realm = new PropertiesRealm();
// Caching isn't needed in this example, but we can still turn it on
realm.setCachingEnabled(true);
return realm;
}
@Bean
public ShiroFilterChainDefinition shiroFilterChainDefinition() {
DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();
// Paths that need to authenticate over the login page
chainDefinition.addPathDefinition("/**", "authc");
// Path for logout. The session calling it wil be logged out
chainDefinition.addPathDefinition("/logout", "logout");
// Paths that shouldn't require authentication like static resources.
chainDefinition.addPathDefinition("/css/**", "anon");
chainDefinition.addPathDefinition("/images/**", "anon");
chainDefinition.addPathDefinition("/js/**", "anon");
chainDefinition.addPathDefinition("/vendor/**", "anon");
return chainDefinition;
}
@Bean
public CacheManager cacheManager() {
// Caching isn't needed in this example, but we will use the MemoryConstrainedCacheManager for this example.
return new MemoryConstrainedCacheManager();
}
/**
* Shiro Thymeleaf dialect like described at
* https://github.com/theborakompanioni/thymeleaf-extras-shiro
* and derived from
* https://shiro.apache.org/web.html#jsp-gsp-tag-library
* @return
*/
@Bean
public ShiroDialect shiroDialect() {
return new ShiroDialect();
}
@Bean
public DefaultPasswordService defaultPasswordService(){
return new DefaultPasswordService();
}
@Bean
public DefaultSecurityManager securityManager(){
DefaultSecurityManager securityManager = new DefaultSecurityManager();
securityManager.setRealm(realm());
return securityManager;
}
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
return new LifecycleBeanPostProcessor();
}
@Bean
public MethodInvokingFactoryBean methodInvokingFactoryBean(){
MethodInvokingFactoryBean methodInvokingFactoryBean = new MethodInvokingFactoryBean();
methodInvokingFactoryBean.setStaticMethod("org.apache.shiro.SecurityUtils.setSecurityManager");
methodInvokingFactoryBean.setArguments(new Object[]{securityManager()});
return methodInvokingFactoryBean;
}
@Bean
@DependsOn(value="lifecycleBeanPostProcessor")
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
return new DefaultAdvisorAutoProxyCreator();
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(){
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
return authorizationAttributeSourceAdvisor;
}
}
现在我很清楚 Shiro 配置是造成这个问题的原因。希望这里有人对 Shiro 及其 Spring 集成有更深入的了解。
【问题讨论】:
-
在帮助您解决问题之前,其他人需要消化太多细节。您需要提供有关症状的更多摘要信息,以及您为尝试定位问题的根源所做的工作。理想情况下,重现问题的最小完整示例程序会很有帮助。
-
嗨,我已经尝试提供最少的代码。从我的角度来看,我的帖子中给出的所有内容都是相关的。或者你能具体说明你的意思吗?
-
HTML 模板?你使用的是 JSP 标签还是 thymeleaf-extras-shiro ?
-
我使用 Thymeleaf-extras-shiro 模板。
-
“我的所有映射都不再起作用”是什么意思?
标签: java spring jpa spring-boot shiro