Spring Request Scoped Controllers and Entity Versioning

时间:2016-08-31 17:06:46

标签: spring-mvc groovy spring-data

Consider this Entity:

    @Entity
    class User {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        Integer id

        String username
        String name
        Boolean blocked

        @Version
        Integer version
    }

... and this Controller:

    @Controller
    @Scope("session")
    class ExampleController {

        @Autowired
        UserRepository userRepository

        User currentUser

        @GetMapping("/user/{id}", Model model)
        def getUser(@PathVariable Integer id) {
            currentUser = userRepository.findOne(id)
            model.addAttribute("user", currentUser)
            "user-view"
        }

        @GetMapping("/user/block", Model model)
        def alterUser() {
            currentUser.blocked = true
            userRepository.save(currentUser)
            model.addAttribute("user", currentUser)
            "user-view"
        }
    }

Since the scope of the Controller is "session" the Class variable "currentUser" will contain a instance of User that was found by "/user/{id}". If I have a button on the view that simply calls the URL "/user/block" it will change the "currentUser" instance.

The problem here is that if I have 2 browser tabs opened on different Users, they will share Scope and will overlap information.

The solution I came across on the Web is to change the Scope to "request". So the controller would have to look like this:

    @Controller
    @Scope("request")
    class ExampleController {

        @Autowired
        UserRepository userRepository

        @GetMapping("/user/{id}", Model model)
        def getUser(@PathVariable Integer id) {
            def currentUser = userRepository.findOne(id)
            model.addAttribute("user", currentUser)
            "user-view"
        }

        @GetMapping("/user/{id}/block", Model model)
        def alterUser(@PathVariable Integer id) {
            def currentUser = userRepository.findOne(id)
            currentUser.blocked = true
            userRepository.save(currentUser)
            model.addAttribute("user", currentUser)
            "user-view"
        }
    }

As we can see, the currentUser needs to be re-selected from the database for each request. This is fine but, since it's being re-selected I can't control it's version anymore. If the User has been changed by another Session between these 2 requests it will be re-selected from the database with a new version and I will not get an ObjectOptimisticLockingFailureException...

How do you guys would deal with this? Any ideas on how can I change an object between requests and still respect versioning?

0 个答案:

没有答案