How to set Controller-wide global variables - java

Currently I use #ModelAttribute to set global variables (e.g. tweets for the footer) in my #Controller:
public #Controller class MainController {
public #ModelAttribute void global(ModelMap map) {
map.addAttribute("tweets", /*...*/null);
}
}
But they're logically gone when creating another Controller to keep things clean and separated:
public #Controller class GalleryController {
// ...
}
What's the best practice to set global variables Controller wide?

If you want to put some data to every page it is easy to use interceptor:
public class PagePopulationInterceptor extends HandlerInterceptorAdapter {
#Autowired
private UserService userService;
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
if(modelAndView != null) {
User user = userService.findOne(request);
modelAndView.addObject("myUserProfile", user);
}
}
}
To make this work also declare interceptor in webmvc-config.xml (spring configuration for webapp):
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.yourcompany.yourapp.util.PagePopulationInterceptor" />
</mvc:interceptor>
<!-- other interceptors (locale, theme and so on) -->
</mvc:interceptors>

you can extend HandlerInterceptorAdapter and add common modelAttributes thr

Related

Spring interceptions not working

I know that this have been asked a lot of times, but none of them could make my code work. I might be doing something wrong but I can't find out what.
I'm using Spring Boot with AngularJS, what I'm trying to do is to preHandle all the requests.
This is my code:
Controller:
#RestController
#RequestMapping(value = { "/user" })
public class UserController {
#RequestMapping(value = "/get", method = RequestMethod.GET)
public String getLanguage() {
return "user";
}
}
Interceptor:
#Component
public class RequestHandler extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException {
System.out.println("intercepted");
return false;
}
}
WebConfig:
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
#Autowired
HandlerInterceptor requestHandler;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(requestHandler);
}
}
And I added this to the applicationContext.xml:
<mvc:interceptors>
<bean class="server.RequestHandler" />
</mvc:interceptors>
I've been all the weekend trying to make this work and I couldn't, any help will be really appreciated!
Thank you!
You could try defining the Bean manually without declaring your Interceptor as a #Component like this:
RequestHandler.java
public class RequestHandler extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(final HttpServletRequest request, final HttpServletResponse response, final Object handler) throws ServletException {
System.out.println("intercepted");
return true;
}
}
WebConfig.java
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
#Bean
public RequestHandler requestHandler() {
return new RequestHandler();
}
#Override
public void addInterceptors(final InterceptorRegistry registry) {
registry.addInterceptor(requestHandler());
}
}
And by the way: If the class is declared as an interceptor why no renaming it to something which contains the term Interceptor in it such as RequestInterceptor?
It should work straightforward. Please let me know if that did the trick for you!
Update: I've implemented this in a prototype. See this minimal, complete, and verifiable example. Hope it helps!
https://github.com/dbubenheim/stackoverflow-41794738.git

Audit/Log all incoming web requests to #RequestMapping annotated methods

Source
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-handlermapping
I have Controller classes annotated with #Controller, they have methods annotated with #RequestMapping. My task is to audit all the web requests received by the Controller classes to #RequestMapping methods, I am using datatables on UI to send and receive response from controllers. the Audit framework is already in place.
The project is configured in Java Config.
I am not sure how to proceed on getting this done.
// Configure Interceptor
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor());
}
public #Bean
RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping handlerMapping = new RequestMappingHandlerMapping();
handlerMapping.setAlwaysUseFullPath(true);
handlerMapping.setUseSuffixPatternMatch(false);
return handlerMapping;
}
}
//Add Handler
#Component
public class MyInterceptor extends HandlerInterceptorAdapter {
#Inject RequestMappingHandlerMapping requestMappingHandlerMapping;
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// do stuff - ( Does my Audit Code go here? eg: Logger.info("xyz request"))
return true;
}
}
I was thinking something like this would work.
Any Suggestions on this, and
if its easier Using Listener or some other Interceptor, it would be helpful
Using interceptors you have full access to the HandlerMethod which provides convenient access to method parameters, the method return value, method annotations, etc.
The following example intercepts and logs mapped requests.
class WebMvcConfig extends WebMvcConfigurerAdapter {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new HandlerInterceptorAdapter() {
Logger logger = LoggerFactory.getLogger(WebMvcConfig.class);
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
logger.info("{} - {} - method '{}' on controller '{}'",
request.getMethod(), request.getRequestURI(), method.getName(),
handlerMethod.getBean().getClass()
);
}
return true;
}
});
}
}
It returns true to continue with the execution chain (and forward the request to other interceptors or the controller-method itself).
An example log-output looks like:
GET - /greeting - method 'greeting' on controller 'class hello.GreetingController'

Spring HandlerInterceptor: how to access class annotations?

I registered my interceptor with the following code
#EnableWebMvc
public class WebMvcConfig extends WebMvcConfigurerAdapter {
...
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor( myInterceptor() );
}
...
}
Here the interceptor definition
public class MyInterceptorimplements HandlerInterceptor {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// Check to see if the handling controller is annotated
for (Annotation annotation : Arrays.asList(handler.getClass().getDeclaredAnnotations())){
if (annotation instanceof MyAnnotation){
... do something
However the handler.getClass().getDeclaredAnnotations() is not returning the class level annotations of the Controller intercepted.
I can only get the method level annotations which is not what I want in this case.
The same interceptor works fine with xml configuration (using Spring 3):
<bean id="handlerMapping" class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors">
<list>
<ref bean="myInterceptor"/>
</list>
</property>
</bean>
Is there a way to have class level information in Spring 4?
According to
In a Spring-mvc interceptor, how can I access to the handler controller method?
"HandlerInterceptors will only provide you access to the HandlerMethod" using the configuration above. But what is the alternative configuration to get class level information?
You can access spring controller class level annotations in the interceptor using handler method.
But you have to be aware that the Casting to HandlerMethod might throw an exception because no Method was found (404)
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("Pre-handle");
HandlerMethod hm;
try {
hm = (HandlerMethod) handler;
} catch (ClassCastException e) {
return super.preHandle(request, response, handler);
}
Method method = hm.getMethod();
// Sometimes Controller.class wont work and you have to use RestController.class just depends on what you use.
if (method.getDeclaringClass().isAnnotationPresent(Controller.class)) {
if (method.isAnnotationPresent(ApplicationAudit.class)) {
System.out.println(method.getAnnotation(ApplicationAudit.class).value());
request.setAttribute("STARTTIME", System.currentTimemillis());
}
}
return true;
}

Can't Autowired Service in AbstractJExcelView

I try Autowired My Service in class who extends AbstractJExcelView but is always null.
I'm guess i can solve this problem change Dependency Injection with Annotation to xml configuration and inject manual component.
Controller
#Controller
#SessionAttributes("user")
public class UserController {
#RequestMapping(value="/exportExel", method = RequestMethod.GET)
public ModelAndView getExelView(#ModelAttribute User user){
return new ModelAndView("ExelUserView","UserList",
user);
}
}
Service
#Service
public class UserServiceImp implements UserService {
#Override
public String getAllFood(User user) { //I Want Get All Element from model User
who contains Arrays String
String backValue = "";
for(String s : user.getFavFood()){
backValue +=s;
backValue +=",";
}
return backValue;
}
}
And ExelView
public class ExelView extends AbstractJExcelView {
private UserServiceImp userService = new UserServiceImp(); // I solve my problem that
//but in my controller i use Autowired Interface Service
// so i dont think its good solution
#Override
protected void buildExcelDocument(Map<String, Object> model,
WritableWorkbook workbook, HttpServletRequest request,
HttpServletResponse response) throws Exception {
WritableSheet sheet = workbook.createSheet("User Response", 0);
setExelHead(sheet);
User listUser = (User)model.get("UserList");
setExelRows(sheet, listUser);
}
public void setExelRows(WritableSheet sheet,User listUser) throws RowsExceededException, WriteException{
sheet.addCell(new Label(4, 1, userService.getAllFood(listUser)));
}
}
And User Model
public class User implements Serializable{
private static final long serialVersionUID = 1L;
private String[] favFood;
public String[] getFavFood() { //I want View Arrays in Exel in one Cell
return favFood;
}
public void setFavFood(String[] favFood) {
this.favFood = favFood;
}
}
in xml i use
<context:component-scan base-package="com.dinor913.example" /> // I guess delete auto scan component and inject Manual all Controller and Service and this should work then
<bean class="org.springframework.web.servlet.view.XmlViewResolver">
<property name="location">
<value>
/WEB-INF/xml-views/document-views.xml
</value>
</property>
<property name="order" value="0"/>
</bean>
and document-views.xml
<bean name="ExelUserView"
class="com.dinor913.example.businnes.ExelView" >
</bean>
UPDATE SOLVE!
I Added to document-views.xml
<context:annotation-config base-package="com.dinor913.example" />
So i understand when i create XmlViewResolver i also create new ApplicationContext for XmlViewResolver and context:annotation-config add #Autowired UserService to DispatcherServlet.
Thx For help.
I Just Start Learn Spring a few days ago
Sorry for my terrible english i hope you understand what i mean.....
Change private UserServiceImp userService = new UserServiceImp(); to:
#Autowired
private UserServiceImp userService
This should work. If not post the errormessage and the stacktrace.

Spring MVC - Interceptor never called

I am trying to configure an interceptor in my application and I am not being able to make it work.
In my application configuration class, I have configured in the following way:
#Configuration
#EnableWebMvc
public class AppContextConfiguration extends WebMvcConfigurerAdapter {
...
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor());
}
...
}
And the interceptor:
public class MyInterceptor extends HandlerInterceptorAdapter{
private static final Logger logger = LoggerFactory.getLogger(MyInterceptor.class);
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
logger.debug("MyInterceptor - PREHANDLE");
}
}
Does anybody know why is not being invoked?
I'm using Spring Boot and was having the same problem where addInterceptors() was being called to register the interceptor, but the interceptor never fired during a request. Yet XML configuration worked no problem.
Basically, you don't need the WebMvcConfigurerAdapter class. You just need to declare an #Bean of type MappedInterceptor:
#Bean
public MappedInterceptor myInterceptor()
{
return new MappedInterceptor(null, new MyInterceptor());
}
Interceptor classes must be declared in spring context xml configuration file within the tag <mvc:interceptors>. Did you do that?
From the Documentation
An example of registering an interceptor applied to all URL paths:
<mvc:interceptors>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" />
</mvc:interceptors>
An example of registering an interceptor limited to a specific URL path:
<mvc:interceptors>
<mvc:interceptor>
<mapping path="/secure/*"/>
<bean class="org.example.SecurityInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
So, you would need to configure MyInterceptor class in the spring context xml file
Can someone please mark Theos answer as the correct one? I had the situation of a perfectly working Spring Boot app using i18n and Thymeleaf (with a layout interceptor) as long as the app was running localhost with the following config:
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor());
registry.addInterceptor(thymeleafLayoutInterceptor());
}
As soon as I deployed the app to an Elasticbeanstalk instance, both interceptors were not fired anymore. Although added once. When I changed the setting to
#Bean
public MappedInterceptor localeInterceptor() {
return new MappedInterceptor(null, localeChangeInterceptor());
}
#Bean
public MappedInterceptor thymeleafInterceptor() {
return new MappedInterceptor(null, thymeleafLayoutInterceptor());
}
everything was working fine on all environments. There must be an issue with firing interceptors added with addInterceptor, it might depend on the URL that is used to invoke the request - I don't know.
Thanks for your answer, Theo, I just wanted to add this here if some else stumbles upon this nice feature.
If it´s possible. Use this approach:
public class Application extends WebMvcConfigurerAdapter{
...
#Bean
public MyInterceptor myInterceptor() {
return new MyInterceptor();
}
public #Override void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(myInterceptor());
}
}
instead of:
#Bean
public MappedInterceptor myInterceptor()
{
return new MappedInterceptor(null, new MyInterceptor());
}
because with the first you can use injection features (like #Autowired, etc...)
Maybe you should add componentscan annotation in the file where the main class is present.
#ComponentScan("package where the interceptor is placed.")
Worked for me.
This approach worked with me
#Configuration
public class WebConfiguration extends WebMvcConfigurerAdapter {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor());
}
}
Using XML configuration, ensure you defined the interceptors in the correct context.
Moving config from servlet context(*-servlet) to main context (web.xml) made it work.
Even if the URL was a call to the servlet.

Categories