【问题标题】:Shared HashMap under a Spring MVC applicationSpring MVC 应用下的共享 HashMap
【发布时间】:2017-01-27 00:53:00
【问题描述】:

每个人。

我正在使用 Spring MVC 构建一个网站,并将控制器配置为单例。我想在整个应用程序下创建一个共享的 HashMap。

也就是说:当一个新用户注册一个用户帐户时,我会向他发送确认码并将其放入 HashMap。并且用户可以将确认代码提交到其他页面,可能在其他浏览器会话中,因此 HaspMap 必须可以由不同的会话访问。

我通过将它保存到数据库表中来实现这个功能,但我想知道如何在不使用数据库的情况下以这种方式做到这一点。

【问题讨论】:

    标签: spring spring-mvc session servlets hashmap


    【解决方案1】:

    在 spring 上下文中将 HashMap 创建为 bean。如果你使用基于 XML 的配置,你可以这样做:

    <util:map id="theMap" />
    

    然后您可以使用@Autowired@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;
        }
    
    }
    

    要测试,像这样访问它:

    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"}
    

    我只是使用@ResponseBody 来避免创建新视图并轻松检查地图内容。

    【讨论】:

      【解决方案2】:

      我不建议直接共享地图。这几乎没有任何正当理由存在。相反,我建议您抽象出用户帐户逻辑。

      这样您就可以对接口进行编程,如果以后您需要更改您的实现(比如转到数据库而不是地图),您只需替换您的实现类,无需更改任何其他内容。以下示例中的关键是您的 MapUserRepository 是单例,因此其中的 Map 在技术上是单例。根据您的用例,您可能还想使用 ConcurrentHashMap

        @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<>();
          }
      

      【讨论】:

      • 感谢@amin,这是一个很好的解决方案,但考虑到我正在制作一个简单且轻量级的项目,所以我选择了其他答案。祝你有美好的一天。
      【解决方案3】:

      没什么,将 HashMap 设为 static 并在您在任何类中声明时进行初始化。

      public class AnyClass{
       public static Map<?> sessionMap = new HashMap<?>;  //use anywhere in the project
      }
      

      在其他类中使用AnyClass.sessionMap.put(key,value)AnyClass.sessionMap.get(key)。直到您明确地remove 密钥或直到您stop/restart 服务器此映射将包含这些信息。

      使用Synchronize 块来放置和获取密钥。

      但是一旦重新启动应用服务器后,您将无法获取这些信息。

      【讨论】:

      • 感谢您的回答,考虑到我使用的是 Spring MVC,我选择了其他答案。祝你有美好的一天。
      猜你喜欢
      • 2017-01-24
      • 2013-04-16
      • 2012-07-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-28
      • 2012-03-27
      相关资源
      最近更新 更多