Spring Boot @ControllerAdvice仅在奇怪的情况下工作

时间:2017-08-28 10:52:19

标签: java spring-mvc spring-boot spring-security exception-handling

我们有以下问题。当我们使用ExceptionHandler创建全局@ControllerAdvice时,每次将Exception传递给控制器​​并让Spring Boot执行转换时,我们就开始关注Long

"Failed to convert value of type 'java.lang.String' to required type 'com.example.controlleradvice.model.Location'; nested exception is java.lang.IllegalStateException:"

如果没有全局ExceptionHandler,它就可以正常工作,我们也不会理解为什么。

全球ExceptionHandler

@ControllerAdvice
@RequiredArgsConstructor
public class GlobalControllerAdvice {

    private final UserService userService;
    private final IndexService indexService;

    @ExceptionHandler({Exception.class})
    public ModelAndView globalException(final Exception ex, final HttpServletRequest request) {
     //   userService.getActiveUser().ifPresent(System.out::print);
        return new ModelAndView("index")
                .addObject("viewModel", indexService.getIndexViewModelWithErrorMessage(ex));
    }

MvcConfig:

@Configuration
@EnableWebMvc
public class MvcConfig extends WebMvcConfigurerAdapter {

    private static final String[] DEFAULT_STATIC_RESOURCES = {
            "classpath:/META-INF/resources/", "classpath:/resources/",
            "classpath:/static/", "classpath:/public/"
    };
    @Getter
    private static Path documentPath;
    @Getter
    private static Path originalImagePath;
    @Getter
    private static Path resourceImagePath;
    @Getter
    private static Path temporaryPath;
    @Getter
    private static String documentWebUrl;
    @Getter
    private static String imageWebUrl;
    @Getter
    private static String imageOriginalUrl;


    @Autowired
    private RequestMappingHandlerAdapter requestMappingHandlerAdapter;

    @PostConstruct
    public void init() {
        requestMappingHandlerAdapter.setIgnoreDefaultModelOnRedirect(true);
    }

    @Override
    public void addResourceHandlers(final ResourceHandlerRegistry registry) {

        registry.addResourceHandler(getDocumentWebUrl() + "/**")
                .addResourceLocations("file:" + getDocumentPath() + "/")
                .setCachePeriod(3600)
                .resourceChain(true)
                .addResolver(new GzipResourceResolver())
                .addResolver(new PathResourceResolver());
        registry.addResourceHandler(getImageWebUrl() + "/**")
                .addResourceLocations("file:" + getResourceImagePath() + "/")
                .setCachePeriod(3600)
                .resourceChain(true)
                .addResolver(new GzipResourceResolver())
                .addResolver(new PathResourceResolver());
        registry.addResourceHandler(getImageOriginalUrl() + "/**")
                .addResourceLocations("file:" + getOriginalImagePath() + "/")
                .setCachePeriod(3600)
                .resourceChain(true)
                .addResolver(new GzipResourceResolver())
                .addResolver(new PathResourceResolver());
        registry.addResourceHandler("/**")
                .addResourceLocations(DEFAULT_STATIC_RESOURCES)
                .setCachePeriod(3600)
                .resourceChain(true)
                .addResolver(new GzipResourceResolver())
                .addResolver(new PathResourceResolver());
    }

}

SecurityConfig:

@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final SecurityUserService securityUserService;

    @Override
    protected void configure(final HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/fonts/**", "/scripts/**", "/styles/**",
                        "/css/**").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin().loginPage("/login").permitAll()
                .and()
                .logout().permitAll()
                .and().csrf().ignoringAntMatchers("/**");
        http.sessionManagement()
                .maximumSessions(Integer.MAX_VALUE)
                .maxSessionsPreventsLogin(false)
                .expiredUrl("/login")
                .sessionRegistry(sessionRegistry());
    }

    @Override
    protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(securityUserService);
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public SessionRegistry sessionRegistry() {
        return new SessionRegistryImpl();
    }

    @Bean
    public static ServletListenerRegistrationBean httpSessionEventPublisher() {
        return new ServletListenerRegistrationBean<>(new HttpSessionEventPublisher());
    }

}

路线有缺陷的控制器:

@Controller
@RequiredArgsConstructor
@RequestMapping("show")
public class ShowController {

    private final IndexService indexService;

    @GetMapping
    public String showWithId(final @RequestParam Location location, final Model model) {
        model.addAttribute("viewModel", indexService.getIndexViewModel(location));
        return "index";
    }
}

UserService:

@Service
@RequiredArgsConstructor
public class UserService {

    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;

    @Transactional(readOnly = true)
    public Optional<User> getActiveUser() {
        final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null || authentication instanceof AnonymousAuthenticationToken) {
            return Optional.empty();
        }
        return userRepository.findByUsername(authentication.getName());
    }
}

为了让我们更难理解潜在的机制,我们找到了5种不同的方法来绕过问题,而不了解问题本身。

我们已经构建了一个Spring Boot Example来重现问题并将其添加到gitlab中。这是发生错误的master branch。 而且这里有一个Branch with the MvcConfig moved到另一个目录。

非常感谢有关真正问题的任何提示!

0 个答案:

没有答案