如果我使用它来填充@ModelAttribute

时间:2016-12-30 23:54:13

标签: java spring spring-mvc spring-boot spring-data

这是Web入口点的主控制器

@Controller
@RequestMapping("/webapp")
public class WebAppController {

@RequestMapping(value = "/home/{authKey}",method = RequestMethod.GET)
String index(@ModelAttribute MyMeta myMeta, Model model){

    System.out.println("Token: "+myMeta.getAccessToken());

    return "index";
}

@RequestMapping(value = "/config/{authKey}",method = RequestMethod.GET)
String config(@ModelAttribute MyMeta myMeta, Model model){

    return "configure";
}
}

现在,如果您查看拦截器,您可以看到我是如何创建@ModelAttribute的,并查看实现

@Component
@ControllerAdvice
public class SessionInterceptor implements AsyncHandlerInterceptor {

MyMeta myMeta;

...

@ModelAttribute
public MyMeta getTest() {
    return this.myMeta;
}

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {

...

// parse the key from the request

... 

MetaMagicKey metaMagicKey = metaMagicKeyRepo.findKeyByMagicKey(key);

// do work here query my DB and build stuff

...

// assign the queried data built into object
this.myMeta = metaMagicKey.getId().getMyMeta();

return true;
}

我的问题是,我不知道Springboot的真正相互作用,所以我担心如果有太多人执行此操作我可能会有一些对象交换或某种碰撞?真的没有一种干净的方法可以做到这一点,我所做的所有研究都是在使用HttpServletRequest#setAttribute()和使用@ModelAttribute之间徘徊,我喜欢上面选择的路线,因为它很容易在我的方法中实现

Springboot 1.4.2 - Java 8

编辑:

我最终尝试的是基于我读过的几页。

我创建了一个新组件:

@Component
@RequestScope
public class HWRequest implements Serializable {

private MyMeta myMeta;

public MyMeta getMyMeta() {
    return myMeta;
}

public void setMyMeta(MyMeta myMeta) {
    this.myMeta = myMeta;
}

}

然后是我的Config课程

@Configuration
public class AppConfig extends WebMvcConfigurerAdapter {

UserSessionInterceptor userSessionInterceptor;

@Autowired
public AppConfig(UserSessionInterceptor userSessionInterceptor) {
    this.userSessionInterceptor = userSessionInterceptor;
}

@Bean
@RequestScope
public HWRequest hwRequest() {
    return new HWRequest();
}

@Bean
public UserSessionInterceptor createUserSessionInterceptor() {
    return userSessionInterceptor;
}

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(createUserSessionInterceptor()).addPathPatterns("/user/**");
}
}

这是我修改过的拦截器

@Component
@ControllerAdvice
public class SessionInterceptor implements AsyncHandlerInterceptor {

@Resource
HWRequest hwRequest;

...

@ModelAttribute
public HWRequest getTest() {
    return this.hwRequest;
}

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {

...

// parse the key from the request

... 

MetaMagicKey metaMagicKey = metaMagicKeyRepo.findKeyByMagicKey(key);

// do work here query my DB and build stuff

...

// assign the queried data built into object
this.hwRequest.setMyMeta(metaMagicKey.getId().getMyMeta());

return true;
}

当然还有修改后的控制器以满足我的需求

@Controller
@RequestMapping("/user")
public class WebAppUserController {

@RequestMapping(value = "/home/{authKey}",method = RequestMethod.GET)
String index(@ModelAttribute HWRequest request, Model model){

    return "index";
}

@RequestMapping(value = "/config/{authKey}",method = RequestMethod.GET)
String config(@ModelAttribute HWRequest request, Model model){

    return "configure";
}

}

根据我读过的所有文档,这应该可行,但也许我错过了一些东西,因为拦截器仍然是单身。也许我错过了什么?

1 个答案:

答案 0 :(得分:3)

myMeta变量表示单例bean中的状态。当然,它不是线程安全的,各种用户都会遇到冲突。不要将任何应用程序状态存储在单例bean中。

如果要为每个请求存储一些状态,请使用Spring的请求范围。这意味着creating separate bean just for storing state annotated with @RequestScope annotation

对编辑的反应:

可以删除此bean注册,因为它已经使用@Component注释注册到Spring IoC容器中:

@Bean
@RequestScope
public HWRequest hwRequest() {
    return new HWRequest();
}

AppConfig中不需要的另一件事是自动装配UserSessionInterceptor bean并再次将其注册为bean。删除它。由于该bean正在自动装配,它显然已经在IoC容器中,所以不需要再次注册它。

另一个令人困惑的部分是命名工作session。当您处理@RequestScope而不是@SessionScope时,我建议您将班级的命名更改为request(例如RequestInterceptor)。 Session vs Request是非常不同的野兽。

否则看起来它可以工作并且应该是线程安全的。