Reputation: 87
everyone.
I am building a website with Spring MVC and configured controllers as singletons. And I would like to create a shared HashMap under the whole application.
That is: when an new user registed a user account i would send him the confirm code and put it into the HashMap. And the user could submit the confirm code to some other page, maybe in some other browser session, so the HaspMap must can be accessed by different sessions.
I was implementing this function by saving it into the database table, but I would like to know how to do it in this way without using database.
Upvotes: 2
Views: 2564
Reputation: 3431
Nothing much,make HashMap
as static and initialize when you are declaring in any class.
public class AnyClass{
public static Map<?> sessionMap = new HashMap<?>; //use anywhere in the project
}
In other class use AnyClass.sessionMap.put(key,value)
or AnyClass.sessionMap.get(key)
.Till you explicitly remove
the key or till you stop/restart
the server this map will contains those information.
Use Synchronize
block to put and get the keys.
But once after restart the application server you will not be able to get those information.
Upvotes: 0
Reputation: 1209
I wouldn't recommend sharing a map directly. That hardly ever has any valid reason to exist. Instead I suggest you abstract out the user account logic.
That way you program to the interface and if later you need to change your implementation (say go to database instead of a map) you just replace your implementing class and nothing else would need to change. The key in the below example is that your MapUserRepository is a singleton and hence the Map inside it is technically a singleton. You might alsow want to use ConcurrentHashMap depending on your usecase.
@Controller
@RequestMapping("/users")
public class UserController {
@Autowired
private UserRepository userRepository;
@RequestMapping(path = "/username", method = RequestMethod.POST)
public ResponseEntity<String> registerUser(@PathParam("username") String username) {
String confirmCode = userRepository.addUser(username);
return new ResponseEntity<String>(confirmCode, HttpStatus.OK);
}
}
@Controller
@RequestMapping("/another")
public class AnotherController {
@Autowired
private UserRepository userRepository;
public ResponseEntity<String> registerUser(@RequestParam("confimCode") String confirmCode) {
User user = userRepository.getUserByConfirmationCode(confirmCode);
// do something with the user or handle not found error.
return new ResponseEntity<String>("another operation", HttpStatus.OK);
}
}
public interface UserRepository {
public String addUser(String username);
public User getUserByConfirmationCode(String confirmationCode);
}
public class User {
public User(String username) {
this.username = username;
}
private final String username;
}
@Component
public class MapUserRepository implements UserRepository {
@Override
public String addUser(String username) {
// maybe check if the user name already exists.
String confirmation = "generate some code";
this.mapUsers.put(confirmation, new User(username));
// handle possible errors.
return confirmation;
}
@Override
public User getUserByConfirmationCode(String confirmationCode) {
// possibly handle errors if confirmation code is not valid.
return this.mapUsers.get(confirmationCode);
}
private final Map<String, User> mapUsers = new HashMap<>();
}
Upvotes: 2
Reputation: 6434
Create the HashMap
as a bean in the spring context. If you use XML based configuration you could do it this way:
<util:map id="theMap" />
Then you could reference it by using @Autowired
or @Resource(name="theMap")
:
@Controller
@RequestMapping("/sharedMap")
public class MapConsumerController {
@Resource(name="theMap")
private Map theMap;
@RequestMapping("/put.service")
public @ResponseBody Map<?,?> put(String key, String value){
this.theMap.put(key, value);
return this.theMap;
}
}
To test, acces it like this:
http://host:port/context/sharedMap/put.service?key=keyOne&value=keytwo
Result: {"keyOne":"keytwo"}
http://host:port/context/sharedMap/put.service?key=keyTwo&value=valuetwo
Result: {"keyOne":"keytwo","keyTwo":"valuetwo"}
I just used a @ResponseBody
to avoid creating a new view and check the content of the map easily.
Upvotes: 2