Adam Lesiak
Adam Lesiak

Reputation: 501

Spring MVC - Inherited variable value across the controllers

I have two controllers that inherited from one, MainController. The Scope of every Controller is 'session'. In MainController I have one variable: Index, just follow:

@Controller
public class C1 extends MainController {
    @RequestMapping(value="/action1") 
    public void Action1() {
        System.out.print(Index);
    }
}

@Controller
public class C2 extends MainController {
    @RequestMapping(value="/action2") 
    public void Action2() {
        System.out.print(Index);
    }
}


public class MainController {

    protected int Index = 0;

    @ModelAttribute("BeforeRequest")
    public void BeforeRequest(HttpServletRequest request) {
        if (request.getRequestURI().contains("action1")) {
            Index++;
        }
    }
}

When "Action1" runs, Index is increase by 1 (ModelAttribute annotation) in MainController. In C1 variable is increasing by 1 every request, but in C2 is still 0 (as defined).

It is possible to 'inject' current value of Index to C2?

Upvotes: 3

Views: 1831

Answers (4)

Adam Lesiak
Adam Lesiak

Reputation: 501

I resolved my problem like Martin Frey wrote. I've created Index as a session bean and Controllers can be Scope request.

The main tags to resolve problem was: scope="session" and aop:scoped-proxy in bean XML.

Here is an improved code:

@Controller
@Scope("request")
public class C1 extends BaseController {


    @RequestMapping(value="/action1")
    public void Action1() {
        System.out.println("Action1: " + Index.getIndex());
    }
}

@Controller
@Scope("request")
public class C2 extends BaseController {

    @RequestMapping(value="/action2")
    public void Action2() {
        System.out.println("Action2: " + Index.getIndex());
    }
}

And BaseController is:

public class BaseController {

    @Autowired
    protected BeanSession Index;

    @ModelAttribute("BeforeRequest")
    public void BeforeRequest(HttpServletRequest request) {
        if (request.getRequestURI().contains("action1")) {
            Index.setIndex(Index.getIndex() + 1);
        }
    }

    public BeanSession getIndex() {
        return Index;
    }

    public void setIndex(BeanSession index) {
        Index = index;
    }

}

BeanSession class:

public class BeanSession {

    private int Index;

    public BeanSession() {
        this.Index = 1;
    }


    public int getIndex() {
        return Index;
    }

    public void setIndex(int index) {
        Index = index;
    }

}

And Bean definition in xml:

<bean id="BeanSession_Bean" class="controller.BeanSession" scope="session" >
    <aop:scoped-proxy/>
</bean>

<bean id="BaseController_Bean" class="controller.BaseController">
    <property name="Index" ref="BeanSession_Bean" />
</bean>

And that it works like I want to.

Upvotes: 0

Martin Frey
Martin Frey

Reputation: 10075

I would not put the controllers themself into the sessionscope.

Rather implement your sessionobject holding the index variable in the sessionscope and wire this into your controller.

I see at least three advantages:

  • smaller session
  • no need for static
  • easier to extend: if you need this index in another place suddenly which is not a controller inheriting of your base one

Upvotes: 1

clav
clav

Reputation: 4251

If you want to count the number of times a user accesses the site there are several ways. One simple way is to create a servlet filter that's mapped to all requests that increments a request count and places it in the user's session.

This goes in web.xml:

<filter>
    <filter-name>RequestCountFilter</filter-name>
    <filter-class>com.mycompany.RequestCountFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>RequestCountFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

The filter implementation would look something like this:

public class RequestCountFilter implements Filter {

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpSession session = request.getSession();
        Integer requestCount = session.getAttribute("requestCount") == null 0 : session.getAttribute("requestCount");
        session.setAttribute("requestCount", ++requestCount);         
        chain.doFilter(req, res);
    }
    public void init(FilterConfig config) throws ServletException {
        // init code goes here
    }
    public void destroy() {
        // clean up goes here
    }
}

Upvotes: 4

gerrytan
gerrytan

Reputation: 41123

Although C1 and C2 are subclass of MainController, when spring boots it will create an instance of each, hence you have two copies of the variable Index.

Easiest way is to make Index variable static such that it belongs to the class instance, not to the object

Try print some debug statement on the constructor of each C1 and C2 and when spring boots you'll see they're both different object instance

Upvotes: 1

Related Questions