I am trying to use WebRequestInterceptor but i don't know how can i configure it in spring boot, as if I implement WebMvcConfigurer interface it requires a HandlerInterceptor object so i cannot assign my interceptor to it. Any help would be highly appreciated.
Interceptor class:
public class CustomerStateInterceptor implements WebRequestInterceptor {
#Resource(name = "customerStateRequestProcessor")
private CustomerStateRequestProcessor customerStateRequestProcessor;
#Override
public void preHandle(WebRequest webRequest) {
customerStateRequestProcessor.process(webRequest);
}
#Override
public void postHandle(WebRequest webRequest, ModelMap modelMap) {
//unimplemented
}
#Override
public void afterCompletion(WebRequest webRequest, Exception e) {
//unimplemented
}
}
and config class:
#Configuration
public class InterceptorConfig implements WebMvcConfigurer {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new CustomerStateInterceptor()); // <-- Error here.
}
}
You supposed to implement HandlerInterceptor from org.springframework.web.servlet package and not WebRequestInterceptor.
Update
You can just wrap with WebRequestHandlerInterceptorAdapter:
#Configuration
public class InterceptorConfig implements WebMvcConfigurer {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(
new WebRequestHandlerInterceptorAdapter(
new CustomerStateInterceptor()));
}
}
Add filter class to your package and please try the code below -
public class RequestValidateFilter extends GenericFilterBean {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
try {
request = new RequestWrapper(httpServletRequest);
chain.doFilter(request, response);
} catch (Exception e) {
throw new ServletException();
}
}
}
FilterClass :
#Configuration
public class CustomWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.addFilterBefore(requestValidateFilter(), BasicAuthenticationFilter.class);
http.authorizeRequests().antMatchers("/projectname/**").authenticated();
http.addFilterAfter(responseValidateFilter(), BasicAuthenticationFilter.class);
}
private RequestValidateFilter requestValidateFilter() {
return new RequestValidateFilter();
}
private ReponseValidateFilter responseValidateFilter() {
return new ReponseValidateFilter();
}
}
Related
I need to send a websocket message to the user after the handshake, without waiting the user to send something.
I tried to use afterHandshake in a HandshakeInterceptor, however possibly the user is not identified yet.
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
private final ApplicationContext applicationContext;
WebSocketConfig(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/reply");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws")
.setHandshakeHandler(new UserHandshakeHandler())
.addInterceptors(new MessagesHandshakeInterceptor(applicationContext));
}
}
public record MessagesHandshakeInterceptor(
ApplicationContext applicationContext) implements HandshakeInterceptor {
#Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response,
WebSocketHandler handler, Map<String, Object> attributes) {
return true;
}
#Override
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response,
WebSocketHandler handler, Exception exception) {
//send the message to the user
applicationContext.getBean(SimpMessagingTemplate.class)
.convertAndSendToUser(user, "/reply", message);
}
}
public class UserHandshakeHandler extends DefaultHandshakeHandler {
#Override
protected Principal determineUser(ServerHttpRequest request, WebSocketHandler handler,
Map<String, Object> attributes) {
return () -> userId;
}
}
I'm using #Autowire in custom filter class. I'm getting null pointer exception.
Does #Autowire works in Filter?
here is the code:
public class MyFilter extends CustomFilter {
#Autowire
public MyClass myClass;
#Override
public String getInfo(){
return myClass.getMessage();
}
}
This is how I registered my bean in configuration class
#Configuration
public class ConfigLoader{
#Bean
public FilterRegistrationBean myFilterBean() {
final FilterRegistrationBean filterBean = new FilterRegistrationBean();
filterBean.setFilter(new MyFilter());
filterBean.addUrlPatterns("/*");
return filterBean;
}
}
Custom filter:
public abstract class CustomFilter implements Filter {
public FilterConfig getFilterConfig() {
return this.filterConfig;
}
public void setFilterConfig(FilterConfig filterConfig) {
this.filterConfig = filterConfig;
}
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
chain.doFilter(req, resp);
this.clearContext();
}
protected abstract String getInfo();
}
Add #Component annotation to filter class.
#Component
public class MyFilter extends CustomFilter {
...
Let Spring create the filter bean and autowire it in the configuration:
#Configuration
public class ConfigLoader{
#Autowired
private MyFilter myFilter;
#Bean
public FilterRegistrationBean myFilterBean() {
final FilterRegistrationBean filterBean = new FilterRegistrationBean();
filterBean.setFilter(myFilter);
filterBean.addUrlPatterns("/*");
return filterBean;
}
}
in SpringBoot2.0.0.RELESAEversion
use WebMvcConfigurer configure MyWebMvcConfigurer
#Configuration
public class MyMvcConfig implements WebMvcConfigurer{
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new TestHandlerInterceptors()).addPathPatterns("/**");
}
}
public class TestHandlerInterceptors implements HandlerInterceptor {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return false;
}
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
static resource cannot be loaded when preHandle method returning false
Instead of implementing WebMvcConfigurer, you can extend WebMvcConfigurerAdapter Which will give you default implementation.
For static resources, you can override as below.
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**").addResourceLocations(new String[] {"classpath:/","classpath:/public/"});
}
I already found questions with answers but they don't help me.
I have a web servlet project where I use a Spring Controller (4.2.5) and Spring Security (4.0.2). I don't use Spring Boot.
My project works fine.
But now my task is this:
Make #RequestMapping(value={"auth/**"} configurable (replace "auth/**" with ${dm.filterPattern})
Problem: in #RequestMapping ${dm.filterPattern} isn't resolved, although #PropertySource is processed.
This is the entry dm.filterPattern in dmConfig.properties:
dm.filterPattern=/auth/*
Here is some essential code, with all Spring annotations.
Controller:
The output of the method init() shows me that #PropertySource is processed correctly. env.getProperty("...") returns correct values.
#Controller
#PropertySource("classpath:/dmConfig.properties")
#RequestMapping(value ={ "${dm.filterPattern}"})
public class DmProxyController implements ApplicationContextAware
{
private Environment env;
#Autowired
public DmProxyController(Environment env)
{
this.env = env;
}
#RequestMapping(path={"${dm.filterPattern}"} ,method = RequestMethod.POST)
protected void doPost(HttpServletRequest customerRequest, HttpServletResponse response)
throws ServletException, IOException, DmException
{
// code for POST request
}
#RequestMapping(path={"${dm.filterPattern}"} ,method = RequestMethod.GET)
protected void doGet(HttpServletRequest customerRequest, HttpServletResponse response)
throws ServletException, IOException, DmException
{
// code for GET request
}
#PostConstruct
public void init() throws ServletException
{
RequestMappingHandlerMapping requestMapping=
(RequestMappingHandlerMapping) appContext.getBean("requestMappingHandlerMapping");
Map<RequestMappingInfo, HandlerMethod> handlerMethods = requestMapping.getHandlerMethods();
logger.debug("RequestMapping via dm.filterPattern: {}",
env.getProperty("dm.filterPattern"));
logger.debug("Handler Methods: {}", handlerMethods.size());
for (RequestMappingInfo mapInfo : handlerMethods.keySet())
{
logger.debug(" Mappinginfo: {} --> {}", mapInfo, handlerMethods.get(mapInfo));
}
}
}
Class with bean definitions
#Configuration
#PropertySource("classpath:/dmConfig.properties")
#ComponentScan(basePackages = "com.dm.filter, com.dm.controller")
#EnableTransactionManagement(mode = AdviceMode.PROXY, proxyTargetClass = false)
#Import({DmSecurityConfigurer.class, DmWebConfigurer.class})
public class DmRoot
{
}
DispatcherServletInitializer
public class DmDispatcherServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer
{
#Override
protected Class<?>[] getRootConfigClasses()
{ return new Class[]{DmRoot.class}; }
#Override
protected Class<?>[] getServletConfigClasses()
{ return null; }
#Override
protected String[] getServletMappings()
{ return new String[]{"/"}; }
#Override
protected String getServletName()
{ return "dmDispatcherServlet"; }
#Override
protected void customizeRegistration(ServletRegistration.Dynamic registration)
{
super.customizeRegistration(registration);
registration.setLoadOnStartup(1);
}
}
WebConfigurer
public class DmWebConfigurer extends WebMvcConfigurerAdapter
{
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry)
{
super.addResourceHandlers(registry);
registry.addResourceHandler("/index.html").addResourceLocations("/");
registry.setOrder(Integer.MAX_VALUE-5);
}
}
SecurityWebApplicationInitializer
public class DmSecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer
{
public DmSecurityWebApplicationInitializer()
{
// some logging
}
#Override
protected void beforeSpringSecurityFilterChain(ServletContext servletContext)
{ // adding own filters }
#Override
protected void afterSpringSecurityFilterChain(ServletContext servletContext)
{ // adding own filters }
}
SecurityConfigurer
#EnableWebMvc
#EnableWebSecurity
#PropertySource("classpath:dmConfig.properties")
public class DmSecurityConfigurer extends WebSecurityConfigurerAdapter
{
private static Logger logger = LogManager.getLogger(DmSecurityConfigurer.class.getName());
#Autowired
private Environment env;
#Autowired
private UserDetailsService dmUserDetailsService;
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception
{
String urlPattern = env.getProperty("dm.springSecurityPattern");
String realmName = env.getProperty("dm.springSecurityRealm");
httpSecurity.httpBasic().realmName(realmName)
.and().userDetailsService(dmUserDetailsService)
.authorizeRequests()
.antMatchers(urlPattern).authenticated()
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.csrf().disable();
}
}
There is a possibility that PropertySourcesPlaceholderConfigurer is being initialised later in the spring context than your controller and hence the values are not resolved. try adding explicit bean definition for PropertySourcesPlaceholderConfigurer in one of the root configuration file as below;
#PropertySource("classpath:/dmConfig.properties")
public class DmWebConfigurer extends WebMvcConfigurerAdapter
{
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry)
{
super.addResourceHandlers(registry);
registry.addResourceHandler("/index.html").addResourceLocations("/");
registry.setOrder(Integer.MAX_VALUE-5);
}
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
The reason you can see the values properly in your init() method is because it is called after all the beans are initialised including PropertySourcesPlaceholderConfigurer.
This question already has answers here:
Why is my Spring #Autowired field null?
(21 answers)
Closed 7 years ago.
I want to make a check in database when i receive a request. So i did a Interceptor like below,
CustomInterceptor.java
#Component
public class CustomInterceptor extends HandlerInterceptorAdapter {
#Autowired
private DatabaseService databaseService;
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//Set Request Attribute(TODO)
LogService.info(this.getClass().getName(), "New Request URI is:" + request.getRequestURI());
return true;
}
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
String authToken = request.getHeader("AuthToken");
boolean isValidRequest = databaseService.checkIfTokenIsValid(authToken);
}
}
Application.class:
#SpringBootApplication
public class Application extends SpringBootServletInitializer {
// protected Properties props = new Properties();
//
// public Application() {
// props.setProperty("error.path", "/error");
//// props.setProperty("error.whitelabel.enabled", "false");
//// props.setProperty("org.springframework.web", "DEBUG");
// }
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
// application.properties(props);
return application.sources(Application.class);
}
#Override
public void onStartup(final ServletContext servletContext) throws ServletException {
LogService.info(Application.class.getName(), "Loading Service...");
super.onStartup(servletContext);
LogService.info(Application.class.getName(), "Service Started");
}
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(Application.class, args);
}
DatabasService.java
#Service
public class DatabaseService {
#Autowired
private ApplicationProperties properties;
private final JdbcTemplate defaultJdbcTemplate;
#Autowired
public DatabaseService(
#Qualifier("dataSource") DataSource dataSource) {
defaultJdbcTemplate = new JdbcTemplate(dataSource);
}
public boolean checkIfTokenIsValid() {
//Perform Check
}
}
CustomWebConfiguration.java
#Configuration
#EnableWebMvc
public class CustomWebConfiguration extends WebMvcConfigurerAdapter {
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
"classpath:/META-INF/resources/", "classpath:/resources/",
"classpath:/static/", "classpath:/public/"};
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!registry.hasMappingForPattern("/**")) {
registry.addResourceHandler("/**").addResourceLocations(
CLASSPATH_RESOURCE_LOCATIONS);
}
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new CustomInterceptor())
.addPathPatterns("/**");
}
}
But i get NullPointer At: boolean isValidRequest = databaseService.checkIfTokenIsValid(authToken);
What is wrong here, why cannot spring Autowire the Databaseservice in Interceptor?
Note: Autowire works fine everywhere else, but not in the interceptor.
Solution (Thanks to M. Deinum)
Change the CustomWebConfiguration.java like below;
#Configuration
#EnableWebMvc
public class CustomWebConfiguration extends WebMvcConfigurerAdapter {
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
"classpath:/META-INF/resources/", "classpath:/resources/",
"classpath:/static/", "classpath:/public/"};
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!registry.hasMappingForPattern("/**")) {
registry.addResourceHandler("/**").addResourceLocations(
CLASSPATH_RESOURCE_LOCATIONS);
}
}
#Bean
public CustomInterceptor customInterceptor() {
return new CustomInterceptor();
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(customInterceptor())
.addPathPatterns("/**");
}
}
Spring will only autowire beans it knows about, you are creating the instance yourself outside the control of Spring.
Either inject a CustomInterceptor into your configuration class or add a #Bean method to make it a Spring managed instance. Then use that instance to add it to the list of interceptors.
It is OK to use #SpringBootApplication on your main class, however don't you miss #EnableAutoConfiguration and #ComponentScan on the same class to tell Spring Boot to look for other components and services automatically?